Чтение только определенных строк - PullRequest
182 голосов
/ 17 января 2010

Я использую цикл for для чтения файла, но я хочу читать только определенные строки, скажем строки № 26 и № 30. Есть ли встроенная функция для достижения этой цели?

Спасибо

Ответы [ 25 ]

233 голосов
/ 17 января 2010

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

fp = open("file")
for i, line in enumerate(fp):
    if i == 25:
        # 26th line
    elif i == 29:
        # 30th line
    elif i > 29:
        break
fp.close()

Обратите внимание, что i == n-1 для n-й строки.


В Python 2.6 или более поздней версии:

with open("file") as fp:
    for i, line in enumerate(fp):
        if i == 25:
            # 26th line
        elif i == 29:
            # 30th line
        elif i > 29:
            break
135 голосов
/ 17 января 2010

Быстрый ответ:

f=open('filename')
lines=f.readlines()
print lines[25]
print lines[29]

или

lines=[25, 29]
i=0
f=open('filename')
for line in f:
    if i in lines:
        print i
    i+=1

Существует более элегантное решение для извлечения многих строк: linecache (любезно предоставлено "python: как перейти к определенной строке в огромном текстовом файле?" , предыдущая stackoverflow.com вопрос).

Цитирование документации по Python, указанной выше:

>>> import linecache
>>> linecache.getline('/etc/passwd', 4)
'sys:x:3:3:sys:/dev:/bin/sh\n'

Измените 4 на нужный номер строки, и все готово. Обратите внимание, что 4 принесет пятую строку, так как отсчет начинается с нуля.

Если файл может быть очень большим и вызывать проблемы при чтении в память, было бы неплохо принять совет @ Алока и использовать enumerate () .

Вывод:

  • Используйте fileobject.readlines() или for line in fileobject как быстрое решение для небольших файлов.
  • Используйте linecache для более элегантного решения, которое будет достаточно быстрым для чтения многих файлов, возможно многократно.
  • Примите @ совет Алока и используйте enumerate() для файлов, которые могут быть очень большими и не помещаться в память. Обратите внимание, что использование этого метода может замедлиться, поскольку файл читается последовательно.
27 голосов
/ 17 января 2010

Быстрый и компактный подход может быть:

def picklines(thefile, whatlines):
  return [x for i, x in enumerate(thefile) if i in whatlines]

принимает любой открытый объектоподобный объект thefile (оставляя вызывающей стороне, должен ли он быть открыт из файла на диске, или через, например, сокет, или другой файловый поток) и набор, основанный на нулях строковые индексы whatlines и возвращает список с низким объемом памяти и разумной скоростью. Если количество возвращаемых строк огромно, вы можете предпочесть генератор:

def yieldlines(thefile, whatlines):
  return (x for i, x in enumerate(thefile) if i in whatlines)

, что в основном полезно только для циклов - обратите внимание, что единственное отличие заключается в использовании округлых, а не квадратных скобок в операторе return, создании списка и выражения генератора соответственно.

Далее отметим, что, несмотря на упоминание «строк» ​​и «файлов», эти функции очень, намного более общие - они будут работать на любой итерируемый, будь то открыть файл или любой другой, возвращая список (или генератор) элементов на основе их прогрессивных номеров элементов. Итак, я бы предложил использовать более подходящие общие имена; -).

26 голосов
/ 08 мая 2013

Ради предложения другого решения:

import linecache
linecache.getline('Sample.txt', Number_of_Line)

Надеюсь, это быстро и просто:)

13 голосов
/ 21 октября 2010

если хотите строку 7

line = open("file.txt", "r").readlines()[7]
9 голосов
/ 24 ноября 2014

Для полноты картины приведу еще один вариант.

Давайте начнем с определения из документов Python :

slice Объект, обычно содержащий часть последовательности. Срез создается с использованием записи нижнего индекса, [] с двоеточиями между числами, когда их несколько, например, в variable_name [1: 3: 5]. Скобка (нижний индекс) использует внутренние фрагменты объектов (или в более старых версиях __getslice __ () и __setslice __ ()).

Несмотря на то, что нотация срезов напрямую не применяется к итераторам в целом, пакет itertools содержит функцию замены:

from itertools import islice

# print the 100th line
with open('the_file') as lines:
    for line in islice(lines, 99, 100):
        print line

# print each third line until 100
with open('the_file') as lines:
    for line in islice(lines, 0, 100, 3):
        print line

Дополнительным преимуществом функции является то, что она не читает итератор до конца. Таким образом, вы можете делать более сложные вещи:

with open('the_file') as lines:
    # print the first 100 lines
    for line in islice(lines, 100):
        print line

    # then skip the next 5
    for line in islice(lines, 5):
        pass

    # print the rest
    for line in lines:
        print line

И чтобы ответить на оригинальный вопрос:

# how to read lines #26 and #30
In [365]: list(islice(xrange(1,100), 25, 30, 4))
Out[365]: [26, 30]
9 голосов
/ 23 марта 2015

Чтение файлов невероятно быстро. Чтение файла размером 100 МБ занимает менее 0,1 секунды (см. Мою статью Чтение и запись файлов с помощью Python ). Следовательно, вы должны прочитать его полностью, а затем работать с одиночными строками.

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

Итак, вы должны сделать это так:

with open("path/to/file.txt") as f:
    lines = f.readlines()
print(lines[26])  # or whatever you want to do with this line
print(lines[30])  # or whatever you want to do with this line

Огромные файлы

Если у вас большой файл и потребление памяти вызывает беспокойство, вы можете обрабатывать его построчно:

with open("path/to/file.txt") as f:
    for i, line in enumerate(f):
        pass  # process line i
5 голосов
/ 03 июля 2018

Некоторые из них прекрасны, но это можно сделать гораздо проще:

start = 0 # some starting index
end = 5000 # some ending index
filename = 'test.txt' # some file we want to use

with open(filename) as fh:
    data = fin.readlines()[start:end]

print(data)

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

3 голосов
/ 17 января 2010

Вы можете сделать вызов seek () , который установит вашу головку чтения на указанный байт в файле. Это не поможет вам, если вы точно не знаете, сколько байтов (символов) записано в файле перед строкой, которую вы хотите прочитать. Возможно, ваш файл строго отформатирован (каждая строка - это Х количество байтов?), Или вы можете сами посчитать количество символов (не забудьте включить невидимые символы, такие как разрывы строк), если вы действительно хотите повысить скорость.

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

2 голосов
/ 17 января 2010

Как насчет этого:

>>> with open('a', 'r') as fin: lines = fin.readlines()
>>> for i, line in enumerate(lines):
      if i > 30: break
      if i == 26: dox()
      if i == 30: doy()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...