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


Відповіді:


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.