Какое самое быстрое решение для удаления строк из текстового файла?

В моем проекте мне нужно разработать программу на Python для вставки UUID в устройство. В день будет производиться 1000 устройств, UUID необходимо вставить в каждое устройство, и только один раз. У меня есть большой входной файл (100 000 строк), содержащий все доступные UUID, а именно:

str[32]
str[32]
...
str[32]
str[32]

Пример:

deadbeefdeadbeefdeadbeefdeadbeefdeadbeef
coolcafebabecoolcafebabecoolcafecoolcafe
...
deadbeefdeadbeefcoolcafebabecoolcafebabe
coolcafebabecoolcafebabedeadbeefdeadbeef

Моя программа будет выполняться и закрываться каждый день. Мне нужно убедиться, что я не буду использовать один и тот же UUID дважды.

Я думал о двух решениях:

  1. Удалите строку UUID во входном файле, как только я его использую. Затем, когда мне понадобится UUID, мне нужно прочитать только первую строку.

  2. Измените формат входного файла, добавив в каждую строку по байту, который равен 0, когда UUID свободен, и установите его в 1, когда он использовался. Когда моя программа запускается впервые, я читаю файл, чтобы получить индекс первого 0, затем я могу отслеживать индекс и устанавливать байт в 1 каждый раз, когда я использую один UUID. Например :

    deadbeefdeadbeefdeadbeefdeadbeefdeadbeef;1
    coolcafebabecoolcafebabecoolcafecoolcafe;1
    ...
    deadbeefdeadbeefcoolcafebabecoolcafebabe;0
    coolcafebabecoolcafebabedeadbeefdeadbeef;0
    

Кажется, что оба решения подразумевают необходимость перезаписать все содержимое файла, я прав? Есть ли лучшее решение?

Как насчет использования двух файлов. Один файл содержит все идентификаторы, другой — номер строки. Когда вам понадобится новый uid, возьмите номер строки из файла 2, прочитайте эту строку из файла 1 и увеличьте номер строки.

Barmar 05.08.2024 22:42

Если только хранение не является (по какой-то причине) очень актуальной проблемой... в этом случае вы могли бы подумать о том, чтобы использовать строки с конца и удалять их по ходу? (Я не уверен, будет ли это на самом деле более эффективно.)

Andrew Yim 05.08.2024 22:44

ЛОЖЬ. У SO есть рекомендации.

VoNWooDSoN 05.08.2024 23:25

Возможно, вы могли бы использовать Queue и немного многопоточности… И идея «двух файлов» хороша.

DeepThought42 06.08.2024 02:36
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
4
81
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Ответ принят как подходящий

Здесь: Вот как удалить используемый 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 в отдельном файле, чтобы избежать дублирования.

По сути, это работает следующим образом:

  1. Считайте все используемые UUID в память.
  2. Пройдите через основной файл UUID
  3. Когда он находит UUID, который не использовался, он:
    • Отмечает его как использованный
    • Возвращает его
  4. Если все UUID израсходованы, выдается ошибка

Скрипт работает довольно быстро, потому что он читает только то, что ему нужно, и просто добавляет к «используемому» файлу, а не переписывает все. Он должен отлично работать для вашей повседневной работы.

Лучше всего использовать такую ​​базу данных, как SQLite. Базы данных предназначены для эффективной обработки запросов и являются масштабируемыми.

Как вы и предлагали, заполните базу данных каждым UUID и отметьте, использовались они или нет. Затем вы можете запросить один неиспользуемый UUID из вашей базы данных (примерно так: SELECT uuid FROM database WHERE used = 0 LIMIT 1). При необходимости отметьте UUID как используемый в базе данных.

Я бы не рекомендовал использовать текстовые файлы для 100 тысяч записей.

Также обратите внимание, что sqlite3 встроен в стандартную библиотеку Python — устанавливать ничего не нужно pymotw.com/3/sqlite3/index.html

Mark Setchell 05.08.2024 23:08

Я думаю, ваша главная цель: «Мне нужно разработать программу на Python для вставки UUID в устройство». Почему бы просто не использовать библиотеку UUID? Я бы использовал версию 7, потому что она встраивает дату и делает ее сортируемой.

Почему вы читаете файл с заранее рассчитанными UUID?

Если вам нужно использовать файл, я бы сделал копию (в целях безопасности) и удалил каждую использованную строку обрабатываемого файла. Вы также можете использовать базу данных (SQLite) с новыми и использованными таблицами UUID, но мне нужно будет лучше понять ваш вариант использования. Не стесняйтесь задавать уточняющие вопросы.

Возможно, OP работает для производителя устройств, которому выдаются заранее назначенные идентификаторы (например, MAC-адреса Ethernet/Bluetooth), и им приходится использовать те, которые им предоставлены, а не генерировать свои собственные случайным образом.

Mark Setchell 05.08.2024 23:11

Да, это просто кажется обратным способом сделать это. Генерация, назначение и сохранение в базе данных наиболее эффективны.

Robert Brisita 05.08.2024 23:16

вместо того, чтобы возиться с исходным файлом, почему бы не создать отдельный файл для отслеживания используемых UUID? что-то вроде этого:

  1. прочитайте первый неиспользуемый UUID из вашего большого файла
  2. используйте его для своего устройства
  3. добавьте его в файл «used_uuids.txt»

в следующий раз, когда вы запустите программу, просто проверьте, есть ли 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)

Другие вопросы по теме