Читання лише певних рядків


Відповіді:


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
Моя маленька яловичина з цим полягає в тому, що A) Ви хочете використовувати замість пари відкритих / закритих і таким чином тримати тіло коротким, B) Але тіло не таке коротке. Звучить як компроміс між швидкістю / простором і буттям пітонічним. Я не впевнений, що було б найкращим рішенням.
Гаміш Грубіян

5
з переоціненим, пітон ладнав штрафу понад 13 років без нього
Ден Д.

38
@ Дан Д. Електроенергія завищена, людство прекрасно проживало понад 200 тисяч років без неї. ;-) "з" робить його більш безпечним, читабельнішим і на один рядок коротшим.
Ромен Вінсент

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
Пол H

Ви також linecache.getlines('/etc/passwd')[0:4]можете читати в першому, другому, третьому та четвертому рядках.
zyy

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? Рішення Адама може бути швидшим, оскільки воно використовує додаткову інформацію (монотонно зростає кількість рядків), що може призвести до ранньої зупинки. У мене є 10 ГБ файл, який я не можу завантажити в пам'ять.
Mannaggia

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

рядок = відкрито ("file.txt", "r"). readlines () [7]

14
Акуратний. Але як вам close()файл, відкривши його таким чином?
Міло Вієлондек

1
@ 0sh нам потрібно закрити?
Ooker

1
так. після цього нам потрібно закрити. Коли ми відкриваємо файл, використовуючи "з" ... він закривається сам.
reetesh11

10

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

Почнемо з визначення з python docs :

фрагмент Об'єкт, який зазвичай містить частину послідовності. Фрагмент створюється за допомогою позначення підрядного індексу [] з двокрапками між числами, коли вказано декілька, наприклад у змінному_імені [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
На сьогодні найкращий підхід при роботі з великими файлами. Моя програма пішла від споживання 8 ГБ + майже нічого. Традофф полягав у використанні процесора, який піднімався від ~ 15% до ~ 40%, але фактична обробка файлу була на 70% швидшою. Я буду вести цю торгівлю цілий день. Дякую тобі! 🎉🎉🎉
GollyJer

1
Мені це здається найбільш пітонічним. Дякую!
ipetrik

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 Це дуже залежить від програми. Для багатьох цілком чудово припускати, що текстовий файл має значно менший розмір, ніж наявна пам'ять. Якщо у вас є потенційно величезні файли, я відредагував свою відповідь.
Мартін Тома

дякую за ваше доповнення, що те саме, що і відповідь алока . І вибачте ні, я не думаю, що це залежить від програми. ІМО, завжди краще не читати більше рядків, ніж вам потрібно.
повернення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

Ви можете здійснити call () виклик, який позиціонує вашій голові читання вказаний байт у файлі. Це не допоможе вам, якщо ви точно не знаєте, скільки байтів (символів) записано у файл перед рядком, який ви хочете прочитати. Можливо, ваш файл суворо відформатований (у кожному рядку X кількість байтів?), Або ви можете самі порахувати кількість символів (пам’ятайте, що слід включити невидимі символи, як розриви рядків), якщо ви дійсно хочете збільшити швидкість.

В іншому випадку вам доводиться читати кожен рядок до потрібного рядка відповідно до одного з багатьох запропонованих тут рішень.


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

Щоправда, це менш ефективно, ніж те, що Alok, але моє використовує висловлювання;)
Хаміш Грубіян

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()ітератору буде вичерпано, а другий дзвінок або поверне порожній список, або видасть помилку (не пам'ятаю, яка)
Пол H

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

Оригінальний автор: Frank Hofmann


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

Дає неправильний результат, оскільки ви не можете використовувати лінії читання та такі лінії перегляду, як кожен (вони змінюють поточну позицію читання).

Вибачте за те, що я помітив ВЕЛИЧУЮ помилку в своєму першому коді. Помилка виправлена, і поточний код повинен працювати, як очікувалося. Дякую за вказівку на мою помилку, Роджер Пейт.
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]

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