В моем проекте мне нужно разработать программу на Python для вставки UUID в устройство. В день будет производиться 1000 устройств, UUID необходимо вставить в каждое устройство, и только один раз. У меня есть большой входной файл (100 000 строк), содержащий все доступные UUID, а именно:
str[32]
str[32]
...
str[32]
str[32]
Пример:
deadbeefdeadbeefdeadbeefdeadbeefdeadbeef
coolcafebabecoolcafebabecoolcafecoolcafe
...
deadbeefdeadbeefcoolcafebabecoolcafebabe
coolcafebabecoolcafebabedeadbeefdeadbeef
Моя программа будет выполняться и закрываться каждый день. Мне нужно убедиться, что я не буду использовать один и тот же UUID дважды.
Я думал о двух решениях:
Удалите строку UUID во входном файле, как только я его использую. Затем, когда мне понадобится UUID, мне нужно прочитать только первую строку.
Измените формат входного файла, добавив в каждую строку по байту, который равен 0, когда UUID свободен, и установите его в 1, когда он использовался. Когда моя программа запускается впервые, я читаю файл, чтобы получить индекс первого 0, затем я могу отслеживать индекс и устанавливать байт в 1 каждый раз, когда я использую один UUID. Например :
deadbeefdeadbeefdeadbeefdeadbeefdeadbeef;1
coolcafebabecoolcafebabecoolcafecoolcafe;1
...
deadbeefdeadbeefcoolcafebabecoolcafebabe;0
coolcafebabecoolcafebabedeadbeefdeadbeef;0
Кажется, что оба решения подразумевают необходимость перезаписать все содержимое файла, я прав? Есть ли лучшее решение?
Если только хранение не является (по какой-то причине) очень актуальной проблемой... в этом случае вы могли бы подумать о том, чтобы использовать строки с конца и удалять их по ходу? (Я не уверен, будет ли это на самом деле более эффективно.)
ЛОЖЬ. У SO есть рекомендации.
Возможно, вы могли бы использовать Queue и немного многопоточности… И идея «двух файлов» хороша.
Здесь: Вот как удалить используемый UUID для решения вашей проблемы:
import os
def next_uuid(in_file, used_file):
used = set()
if os.path.exists(used_file):
with open(used_file) as f:
used = set(l.strip() for l in f)
with open(in_file) as f:
for l in f:
u = l.strip()
if u not in used:
with open(used_file, 'a') as uf:
uf.write(f"{u}\n")
return u
raise Exception("No more UUIDs")
in_file = 'uuids.txt'
used_file = 'used.txt'
next_u = next_uuid(in_file, used_file)
print(f"Next UUID: {next_u}")
Этот скрипт извлекает следующий доступный UUID из файла. Он отслеживает используемые UUID в отдельном файле, чтобы избежать дублирования.
По сути, это работает следующим образом:
Скрипт работает довольно быстро, потому что он читает только то, что ему нужно, и просто добавляет к «используемому» файлу, а не переписывает все. Он должен отлично работать для вашей повседневной работы.
Лучше всего использовать такую базу данных, как SQLite. Базы данных предназначены для эффективной обработки запросов и являются масштабируемыми.
Как вы и предлагали, заполните базу данных каждым UUID и отметьте, использовались они или нет. Затем вы можете запросить один неиспользуемый UUID из вашей базы данных (примерно так: SELECT uuid FROM database WHERE used = 0 LIMIT 1
). При необходимости отметьте UUID как используемый в базе данных.
Я бы не рекомендовал использовать текстовые файлы для 100 тысяч записей.
Также обратите внимание, что sqlite3
встроен в стандартную библиотеку Python — устанавливать ничего не нужно pymotw.com/3/sqlite3/index.html
Я думаю, ваша главная цель: «Мне нужно разработать программу на Python для вставки UUID в устройство». Почему бы просто не использовать библиотеку UUID? Я бы использовал версию 7, потому что она встраивает дату и делает ее сортируемой.
Почему вы читаете файл с заранее рассчитанными UUID?
Если вам нужно использовать файл, я бы сделал копию (в целях безопасности) и удалил каждую использованную строку обрабатываемого файла. Вы также можете использовать базу данных (SQLite) с новыми и использованными таблицами UUID, но мне нужно будет лучше понять ваш вариант использования. Не стесняйтесь задавать уточняющие вопросы.
Возможно, OP работает для производителя устройств, которому выдаются заранее назначенные идентификаторы (например, MAC-адреса Ethernet/Bluetooth), и им приходится использовать те, которые им предоставлены, а не генерировать свои собственные случайным образом.
Да, это просто кажется обратным способом сделать это. Генерация, назначение и сохранение в базе данных наиболее эффективны.
вместо того, чтобы возиться с исходным файлом, почему бы не создать отдельный файл для отслеживания используемых UUID? что-то вроде этого:
в следующий раз, когда вы запустите программу, просто проверьте, есть ли UUID в «used_uuids.txt», прежде чем использовать ее. таким образом, вы всегда добавляете только файл, что намного быстрее, чем перезапись целого большого файла.
def get_next_uuid():
with open('all_uuids.txt', 'r') as all_file:
with open('used_uuids.txt', 'a+') as used_file:
used_file.seek(0)
used_uuids = set(used_file.read().splitlines())
for uuid in all_file:
uuid = uuid.strip()
if uuid not in used_uuids:
used_file.write(f"{uuid}\n")
return uuid
return None
Нет, вам не придется переписывать весь файл. Вам нужно будет только переписать части файла, открыв его в режиме a+
и используя функции seek(int)
, tell(int)
и truncate(int)
. Возможно, tell()
вам и не понадобится, но он хорошо сочетается с двумя другими функциями. Вы можете использовать seek()
, чтобы переместить курсор файла в начало последней строки, прочитать ее содержимое, а затем truncate()
в начало последней строки, удалив таким образом UUID, который вы только что прочитали.
Вам понадобятся одинаковые и предсказуемые длины строк. Использование uuids дает вам это. Они имеют фиксированный размер и могут быть закодированы только в ASCII. Таким образом, даже в UTF-8 они также будут иметь фиксированный размер в байтах/размер на диске.
Более подробную информацию смотрите в документации: https://docs.python.org/3/library/io.html#io.IOBase.seek
Я каждый раз увеличивал номер строки и вместо этого читал следующий uuid из файла или переписывал его.
def read_nth_line(file_path, n):
with open(file_path, 'r') as file:
for i, line in enumerate(file, 1):
if i == n:
return line.strip()
return None # Line number exceeds file length
вызовите эту функцию с увеличенным номером строки,
file_path = 'path/to/your/file.txt'
line_number = 5
result = read_nth_line(file_path, line_number)
print(result)
Как насчет использования двух файлов. Один файл содержит все идентификаторы, другой — номер строки. Когда вам понадобится новый uid, возьмите номер строки из файла 2, прочитайте эту строку из файла 1 и увеличьте номер строки.