Читать только определенные номера строк из большого файла в Python?

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

Есть ли способ, которым вы можете читать только определенные строки в Python? Или как это сделать наиболее эффективным способом (т.е. прочитать как можно меньше файла, чтобы ускорить выполнение)?

Отвечает ли это на ваш вопрос? Чтение только определенных строк

Selcuk 10.12.2020 01:18

Если все строки имеют ТОЧНО одинаковое количество символов/байтов, то может быть способ найти эту позицию, но если строки могут быть разной длины, то невозможно узнать, где начинается вторая строка, пока вы не прочитаете строку one и нашел новую строку в конце.

Jerry Jeremiah 10.12.2020 01:20

Второй ответ здесь хороший подход. Однако вам придется просмотреть файл хотя бы один раз.

ssp 10.12.2020 01:25

линейный кеш: docs.python.org/3/library/linecache.html

KetZoomer 10.12.2020 01:28

@Selcuk спасибо за ссылку, я этого раньше не видел. Тем не менее, похоже, что это немного другой вопрос/ответ - поскольку ответы там сосредоточены на чтении определенных строк с эффективным использованием памяти, но все же кажется, что они каждый раз читают весь файл, просто не сохраняя все строки в памяти.

KillerKode 10.12.2020 16:30

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

KillerKode 10.12.2020 16:34

@KillerKode да, это правильно

KetZoomer 10.12.2020 17:46
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
7
1 112
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

К сожалению, это невозможно по простой причине: линий не существует. То, что ваш текстовый редактор показывает вам в виде строки, — это всего лишь два фрагмента текста с символом новой строки посередине (вы можете ввести его с помощью \n в python. Если все строки имеют одинаковую длину, то это возможно, но я предполагаю, что это не так) дело здесь.

Наименьшее количество чтения делается, если вы читаете только свой контент + ваш контент. Это означает, что вы не должны использовать read или readlines. Вместо этого используйте readline, чтобы получить и отбросить ненужные строки, а затем используйте его еще раз, чтобы получить то, что вы хотите. Это, пожалуй, самый действенный способ.

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

Вот несколько вариантов:

  1. Пройдитесь по файлу хотя бы один раз и отследите в файле смещения интересующих вас строк. Это хороший подход, если вы можете искать эти строки несколько раз, и файл не будет изменен.
  2. Рассмотрите возможность изменения формата данных. Например, csv вместо json (см. комментарии).
  3. Если у вас нет другой альтернативы, используйте традиционный:
def get_lines(..., linenums: list):
    with open(...) as f:
        for lno, ln in enumerate(f):
            if lno in linenums:
                yield ln

Для файла размером 4 ГБ это заняло ~ 6 секунд для linenums = [n // 4, n // 2, n - 1], где n = lines_in_file.

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

KillerKode 10.12.2020 16:35

Только что провел некоторое тестирование, чтобы прочитать мой образец набора данных так, как я сейчас делаю в этом большом файле JSON, требуется 159 секунд только для чтения определенных частей этого файла. Когда я переформатирую те же данные в формат стиля CSV, а затем сохраняю метаданные об их смещениях в другом файле (используя подход 1), мне требуется 0,88 секунды, чтобы прочитать оба файла и получить нужные мне строки. Это более чем в 159 раз быстрее. !!! Очень хорошо, удалите пункт 2 из своего ответа, и я соглашусь.

KillerKode 10.12.2020 21:35

Я также подсчитал, что даже после еще 20 лет сбора данных для загрузки нужных мне битов потребуется не более 3 секунд, что более чем достаточно для моих нужд. Сочетание отказа от JSON и поиска файла имеет огромное значение.

KillerKode 10.12.2020 21:36

@KillerKode Вау, это большая разница; хороший! Я думаю, что оставлю пункт 2, потому что, хотя это не лучшее решение для вас, если кто-то еще столкнется с этим вопросом и у него будет файл среднего или меньшего размера, который будет изменен, это, вероятно, будет лучшей альтернативой.

ssp 11.12.2020 01:23

@KillerKode хорошо, после дальнейшего изучения похоже, что linecache в целом просто не лучшее решение. Например, он не может читать двоичные файлы, и его основная цель использования находится в самом исходном коде Python. Я обновлю свой ответ.

ssp 11.12.2020 01:56

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