Чтение только определенных строк


215

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

Спасибо


1
Возможное дублирование: stackoverflow.com/questions/620367/…
Адам Матан

Ответы:


253

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

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

8
enumerate(x)использует x.next, поэтому ему не нужен весь файл в памяти.
Алок Сингхал

3
Моя маленькая говядина с этим заключается в том, что А) Вы хотите использовать вместо пары «открыть / закрыть» и таким образом держать тело коротким, Б) Но тело не такое короткое. Звучит как компромисс между скоростью / пространством и тем, что ты Питон. Я не уверен, что будет лучшим решением.
Хэмиш Грубиджан

5
с переоценен, питон прекрасно обходился более 13 лет без него
Дэн Д.

38
@ Дэн Д. Электричество переоценено, человечество обходилось без него более 200 тысяч лет. ;-) 'with' делает его более безопасным, более читаемым и на одну строку короче.
Ромен Винсент

9
зачем использовать для цикла, я не думаю, что вы понимаете значение big file. Цикл займет годы, чтобы достичь индекса
devssh

159

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

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 принесет пятую строку, так как отсчет начинается с нуля.

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

Заключить:

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

7
Ницца. Я только что посмотрел на источник linecacheмодуля, и похоже, что он читает весь файл в памяти. Таким образом, если произвольный доступ важнее, чем оптимизация размера, linecacheэто лучший метод.
Алок Сингхал

7
с помощью linecache.getlin ('some_file', 4) я получаю 4-ю строку, а не 5-ю.
Хуан

Интересный факт: если вы используете набор вместо списка во втором примере, вы получите время выполнения O (1). Посмотрите в списке O (n). Внутренние наборы представлены в виде хэшей, поэтому вы получаете время выполнения O (1). в этом примере не так уж и много, но если использовать большой список чисел и заботиться об эффективности, то подходы - это путь.
Радий

linecacheтеперь, похоже, работает только для исходных файлов Python
Пол Х

Вы также можете использовать linecache.getlines('/etc/passwd')[0:4]для чтения в первой, второй, третьей и четвертой строках.
Зы

30

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

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выражении, создании понимания списка и выражения генератора соответственно.

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


@ephemient, я не согласен - genexp читает гладко и отлично.
Алекс Мартелли

Отличное и элегантное решение, спасибо! Действительно, должны поддерживаться даже большие файлы с выражением генератора. Не может быть более элегантным, чем это, не так ли? :)
Самуэль Лампа

Хорошее решение, как это можно сравнить с предложением @AdamMatan? Решение Adam может быть быстрее, поскольку оно использует дополнительную информацию (номера строк монотонно увеличиваются), что может привести к ранней остановке. У меня есть файл 10 ГБ, который я не могу загрузить в память.
Маннаггия

2
@Mannaggia Это недостаточно подчеркнуто в этом ответе, но whatlinesдолжно быть set, потому что if i in whatlinesбудет выполняться быстрее с набором, а не (отсортированным) списком. Сначала я этого не заметил, а вместо этого разработал свое собственное уродливое решение с отсортированным списком (в котором мне не нужно было каждый раз сканировать список, а if i in whatlinesименно так), но разница в производительности была незначительной (с моими данными), и это Решение гораздо элегантнее.
Виктор К

28

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

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

Я надеюсь, что это быстро и легко :)


1
Надеюсь, что это наиболее оптимальное решение.
maniac_user

2
Это читает весь файл в память. Вы также можете вызвать file.read (). Split ('\ n'), а затем использовать поиск по индексу массива, чтобы получить интересующую вас строку ...
duhaime

Не могли бы вы привести пример @duhaime
anon

14

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

line = open ("file.txt", "r"). readlines () [7]

14
Ухоженная. А как вам close()файл при открытии его таким образом?
Майло Велондек

1
@ 0sh нам нужно закрыть?
Ooker

1
да. нам нужно закрыть после этого. Когда мы открываем файл, используя «с» ... он закрывается сам.
reetesh11

10

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

Давайте начнем с определения из документации по 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]

1
Безусловно, лучший подход при работе с большими файлами. Моя программа перешла от потребления 8GB + почти к нулю. Трейдофф был использованием ЦП, который увеличился с ~ 15% до ~ 40%, но фактическая обработка файла была на 70% быстрее. Я возьму этот обмен весь день. Спасибо вам! 🎉🎉🎉
GollyJer

1
Это кажется самым питоническим для меня. Спасибо!
Ипетрик

10

Чтение файлов невероятно быстро. Чтение файла размером 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

IMO - это действительно плохой стиль, чтобы читать весь файл неизвестной длины, только чтобы получить первые 30 строк ... как насчет потребления памяти ... а что насчет бесконечных потоков?
возврат42

@ return42 Очень сильно зависит от приложения. Для многих совершенно нормально предположить, что текстовый файл имеет гораздо меньший размер, чем доступная память. Если у вас есть потенциально большие файлы, я отредактировал свой ответ.
Мартин Тома

спасибо за ваше добавление, которое совпадает с ответом alok . И извините, нет, я не думаю, что это зависит от приложения. ИМО всегда лучше не читать больше строк, чем нужно.
возврат42

7

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

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 +. Удачи!


4

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

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


3

Если ваш большой текстовый файл fileстрого структурирован (то есть каждая строка имеет одинаковую длину l), вы можете использовать для n-ой строки

with open(file) as f:
    f.seek(n*l)
    line = f.readline() 
    last_pos = f.tell()

Отказ от ответственности Это работает только для файлов с одинаковой длиной!


2

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

>>> 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()

Правда, это менее эффективно, чем у Алока, но мой использует утверждение with;)
Хэмиш Грубиджан

2

Если вы не возражаете против импорта, то fileinput делает именно то, что вам нужно (это вы можете прочитать номер текущей строки)


2
def getitems(iterable, items):
  items = list(items) # get a list from any iterable and make our own copy
                      # since we modify it
  if items:
    items.sort()
    for n, v in enumerate(iterable):
      if n == items[0]:
        yield v
        items.pop(0)
        if not items:
          break

print list(getitems(open("/usr/share/dict/words"), [25, 29]))
# ['Abelson\n', 'Abernathy\n']
# note that index 25 is the 26th item

Роджер, мой любимый парень! Это может быть полезно с заявлением.
Хэмиш Грубиджан

2

Я предпочитаю этот подход, потому что он более универсален, то есть вы можете использовать его в файле, в результате f.readlines(), на StringIOобъекте, что угодно:

def read_specific_lines(file, lines_to_read):
   """file is any iterable; lines_to_read is an iterable containing int values"""
   lines = set(lines_to_read)
   last = max(lines)
   for n, line in enumerate(file):
      if n + 1 in lines:
          yield line
      if n + 1 > last:
          return

>>> with open(r'c:\temp\words.txt') as f:
        [s for s in read_specific_lines(f, [1, 2, 3, 1000])]
['A\n', 'a\n', 'aa\n', 'accordant\n']

2

Вот мои маленькие 2 цента, за что стоит;)

def indexLines(filename, lines=[2,4,6,8,10,12,3,5,7,1]):
    fp   = open(filename, "r")
    src  = fp.readlines()
    data = [(index, line) for index, line in enumerate(src) if index in lines]
    fp.close()
    return data


# Usage below
filename = "C:\\Your\\Path\\And\\Filename.txt"
for line in indexLines(filename): # using default list, specify your own list of lines otherwise
    print "Line: %s\nData: %s\n" % (line[0], line[1])

2

Лучшее и незначительное изменение для ответа Алока Сингхала

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


1

@OP, вы можете использовать перечислять

for n,line in enumerate(open("file")):
    if n+1 in [26,30]: # or n in [25,29] 
       print line.rstrip()

1
file = '/path/to/file_to_be_read.txt'
with open(file) as f:
    print f.readlines()[26]
    print f.readlines()[30]

Используя оператор with, он открывает файл, печатает строки 26 и 30, а затем закрывает файл. Просто!


это неверный ответ. после того, как первый вызов readlines()итератора будет исчерпан, а второй вызов либо возвратит пустой список, либо выдаст ошибку (не могу вспомнить, какая именно)
Пол Х

1

Вы можете сделать это очень просто с помощью этого синтаксиса, который кто-то уже упоминал, но это, безусловно, самый простой способ сделать это:

inputFile = open("lineNumbers.txt", "r")
lines = inputFile.readlines()
print (lines[0])
print (lines[2])

1

Чтобы напечатать строку № 3,

line_number = 3

with open(filename,"r") as file:
current_line = 1
for line in file:
    if current_line == line_number:
        print(file.readline())
        break
    current_line += 1

Оригинальный автор: Фрэнк Хофманн


1

Довольно быстро и точно.

Для печати определенных строк в текстовом файле. Создайте список "lines2print", а затем просто напечатайте, когда перечисление находится "в" списке lines2print. Чтобы избавиться от лишних '\ n', используйте line.strip () или line.strip ('\ n'). Мне просто нравится «понимание списка» и я стараюсь использовать, когда могу. Мне нравится метод «с» для чтения текстовых файлов, чтобы не оставлять файл открытым по любой причине.

lines2print = [26,30] # can be a big list and order doesn't matter.

with open("filepath", 'r') as fp:
    [print(x.strip()) for ei,x in enumerate(fp) if ei in lines2print]

или, если список маленький, просто введите список как список в понимание.

with open("filepath", 'r') as fp:
    [print(x.strip()) for ei,x in enumerate(fp) if ei in [26,30]]

0

Для печати нужной строки. Для печати строки выше / ниже требуемой строки.

def dline(file,no,add_sub=0):
    tf=open(file)
    for sno,line in enumerate(tf):
        if sno==no-1+add_sub:
         print(line)
    tf.close()

выполнить ----> dline ("D: \ dummy.txt", 6) т.е. dline ("путь к файлу", номер_строки, если вы хотите, чтобы верхняя строка искомой строки давала 1 для нижнего -1, это необязательное значение по умолчанию будет быть взятым 0)


0

Если вы хотите прочитать определенные строки, такие как строка, начинающаяся после некоторой пороговой строки, вы можете использовать следующие коды: file = open("files.txt","r") lines = file.readlines() ## convert to list of lines datas = lines[11:] ## raed the specific lines


-1
f = open(filename, 'r')
totalLines = len(f.readlines())
f.close()
f = open(filename, 'r')

lineno = 1
while lineno < totalLines:
    line = f.readline()

    if lineno == 26:
        doLine26Commmand(line)

    elif lineno == 30:
        doLine30Commmand(line)

    lineno += 1
f.close()

7
это настолько же непитонно, насколько это возможно.
SilentGhost

Дает неверный результат, так как вы не можете использовать readline и readline, как это (каждый из них меняет текущую позицию чтения).

Я извиняюсь за то, что пропустил ОГРОМНУЮ ошибку в моем первом коде. Ошибка была исправлена, и текущий код должен работать как положено. Спасибо за указание на мою ошибку, Роджер Пейт.
inspectorG4dget

-1

Я думаю, что это будет работать

 open_file1 = open("E:\\test.txt",'r')
 read_it1 = open_file1.read()
 myline1 = []
 for line1 in read_it1.splitlines():
 myline1.append(line1)
 print myline1[0]

Когда вы это опубликовали, уже было дюжина методов readline - добавление еще одного просто добавляет беспорядок
duhaime
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.