Yalnızca belirli satırları okuma


Yanıtlar:


253

Okunacak dosya büyükse ve tüm dosyayı bir kerede bellekte okumak istemiyorsanız:

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

Th hattı i == n-1için unutmayın n.


Python 2.6 veya üzeri sürümlerde:

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)kullanır x.next, bu nedenle bellekteki tüm dosyaya ihtiyaç duymaz.
Alok Singhal

3
Bununla olan küçük sığır etim A) Açık / kapalı çift yerine kullanmak ve böylece vücudu kısa tutmak, B) Ama beden o kadar kısa değil. Hız / mekan ve Pythonic arasında bir denge gibi görünüyor. En iyi çözümün ne olacağından emin değilim.
Hamish Grubijan

5
ile abartılıyor, python onsuz 13 yıldır iyi geçti
Dan D.

38
@Dan D. Elektrik abartılıyor, insanlık onsuz 200 bin yıldan fazla bir süre boyunca iyi anlaştı. ;-) 'with' daha güvenli, daha okunaklı ve bir satır daha kısa yapıyor.
Romain Vincent

9
neden döngü için kullanın, anlamını anladığınızı sanmıyorum big file. Döngü endekse ulaşmak için yıllar alacak
devssh

159

Hızlı cevap:

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

veya:

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

Birçok satırı ayıklamak için daha zarif bir çözüm var: linecache ( "python: büyük bir metin dosyasında belirli bir satıra nasıl atlanır ?" , Önceki stackoverflow.com sorusu).

Yukarıda bağlantılı python belgelerinden alıntı:

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

4İstediğiniz satır numarasını değiştirin ve devam edin. Sayı sıfır tabanlı olduğu için 4'ün beşinci satırı getireceğini unutmayın.

Dosya çok büyük olabilir ve belleğe okunduğunda sorun çıkarırsa, @ Alok'un tavsiyesini almak ve enumerate () kullanmak iyi bir fikir olabilir .

Sonuç olarak:

  • Küçük dosyalar için fileobject.readlines()veya for line in fileobjecthızlı bir çözüm olarak kullanın .
  • linecacheTekrar tekrar mümkün olan birçok dosyayı okumak için oldukça hızlı olacak daha zarif bir çözüm için kullanın .
  • @ Alok'un tavsiyelerinienumerate() alın ve çok büyük olabilecek ve belleğe sığmayan dosyalar için kullanın . Dosya sırayla okunduğundan bu yöntemi kullanmanın yavaşlayabileceğini unutmayın.

7
Güzel. Sadece linecachemodülün kaynağına baktım ve bellekteki tüm dosyayı okuyor gibi görünüyor. Dolayısıyla, rasgele erişim boyut optimizasyonundan daha önemliyse linecache, en iyi yöntemdir.
Alok Singhal

7
linecache.getlin ('some_file', 4) ile 5. satırı değil 4. satırı alıyorum.
Juan

eğlenceli gerçek: ikinci örnekte liste yerine bir küme kullanırsanız, O (1) çalışma süresi elde edersiniz. Listeye bakın O (n). Dahili setler karma olarak temsil edilir ve bu yüzden O (1) çalışma süresini elde edersiniz. Bu örnekte büyük bir anlaşma değil, ancak büyük bir sayı listesi kullanıyorsanız ve verimliliği önemsiyorsanız, o zaman kümeler gitmenin yoludur.
rady

linecacheşimdi sadece python kaynak dosyaları için çalışıyor gibi görünüyor
Paul H

linecache.getlines('/etc/passwd')[0:4]Birinci, ikinci, üçüncü ve dördüncü satırlarda okumak için de kullanabilirsiniz .
zyy

30

Hızlı ve kompakt bir yaklaşım şöyle olabilir:

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

bu, herhangi bir açık dosya benzeri nesneyi thefile(bir disk dosyasından mı yoksa bir yuvadan mı, yoksa başka bir dosya benzeri akıştan mı açılacağını arayan kişiye bırakarak) ve bir dizi sıfır tabanlı çizgi indeksini kabul eder whatlinesve bir düşük bellek alanı ve makul hız ile liste. Döndürülecek satır sayısı çok fazlaysa, bir üreteci tercih edebilirsiniz:

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

temelde sadece döngüye girmek için iyidir - tek farkın returnifadede kare parantez yerine yuvarlak parantez kullanmaktan kaynaklandığını ve bir liste kavrayışı ve bir jeneratör ifadesi oluşturduğunu unutmayın.

Daha notu "satırları" ve denince rağmen "file" bu işlevler çok olduğunu, çok daha genel - onlar üzerinde çalışacağız herhangi bir öğe listesi (veya jeneratör) dönen, o açık dosya veya herhangi bir başka olmak, iterable ilerici madde numaralarına göre. Bu yüzden, daha uygun genel isimler ;-) kullanmanızı öneririm.


@efemient, katılmıyorum - genexp sorunsuz ve mükemmel bir şekilde okuyor.
Alex Martelli

Mükemmel ve zarif bir çözüm, teşekkürler! Gerçekten de, jeneratör ifadesi ile büyük dosyalar bile desteklenmelidir. Bundan daha zarif olamaz, değil mi? :)
Samuel Lampa

Güzel çözüm, bu @AdamMatan tarafından önerilenle nasıl karşılaştırılır? Adam çözümü, erken durmaya yol açabilecek ek bilgileri (monoton olarak artan satır numaraları) kullandığından daha hızlı olabilir. Belleğe yükleyemediğim 10 GB'lık bir dosyam var.
Mannaggia

2
@Mannaggia Bu cevapta yeterince vurgulanmamıştır, ancak bir whatlinesolmalıdır set, çünkü if i in whatlines(sıralı) bir liste yerine bir kümeyle daha hızlı yürütülecektir. İlk önce fark etmedim ve bunun yerine sıralı listeyle kendi çirkin çözümümü tasarladım (her seferinde bir listeyi taramak zorunda kalmadım if i in whatlines, sadece bunu yapıyor), ancak performans farkı (verilerimle) ihmal edilebilir ve bu çözüm çok daha zariftir.
Victor K

28

Başka bir çözüm sunmak uğruna:

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

Umarım bu hızlı ve kolaydır :)


1
Umarım bu en uygun çözümdür.
maniac_user

2
Bu, tüm dosyayı belleğe okur. Ayrıca, file.read (). Split ('\ n')
öğesini çağırabilir

@Duhaime
anon'a

14

7. satırı istiyorsan

line = açık ("dosya.txt", "r"). readlines () [7]

14
Temiz. Fakat close()dosyayı bu şekilde açarken nasılsınız ?
Milo Wielondek

1
@ 0sh kapatmamız gerekiyor mu?
Ooker

1
Evet. Bundan sonra kapatmamız gerekir. "ile" kullanarak bir dosya açtığımızda ... kendini kapatır.
17:34

10

Bütünlük uğruna, işte bir seçenek daha.

Python dokümanlarından bir tanımla başlayalım :

dilim Genellikle bir dizinin bir kısmını içeren bir nesne. Değişken_adı [1: 3: 5] gibi bir kaç tane verildiğinde numaralar arasında iki nokta üst üste işareti bulunan [] alt simge gösterimi kullanılarak bir dilim oluşturulur. Köşeli ayraç (alt simge) gösterimi, dilim nesnelerini dahili olarak (veya eski sürümlerde __getslice __ () ve __setslice __ ()) kullanır.

Her ne kadar dilim gösterimi genel olarak yineleyiciler için geçerli olmasa da, itertoolspaket bir değiştirme işlevi içerir:

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

Fonksiyonun ek avantajı, sonuna kadar yineleyiciyi okumamasıdır. Böylece daha karmaşık şeyler yapabilirsiniz:

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

Ve orijinal soruyu cevaplamak için:

# how to read lines #26 and #30
In [365]: list(islice(xrange(1,100), 25, 30, 4))
Out[365]: [26, 30]

1
Büyük dosyalarla çalışırken açık ara en iyi yaklaşım. Programım 8GB + tüketmekten neredeyse hiçbir şeye gitmedi. İşlem, ~% 15'ten% 40'a kadar olan CPU kullanımıdır, ancak dosyanın gerçek işlenmesi% 70 daha hızlıdır. Bütün gün boyunca o yolculuğu alacağım. Teşekkürler! Ly
GollyJer

1
Bu benim için en pitonik gibi görünüyor. Teşekkürler!
ipetrik

10

Dosyaları okumak inanılmaz derecede hızlı. 100 MB'lık bir dosyayı okumak 0,1 saniyeden daha kısa sürer ( Python ile Dosyaları Okuma ve Yazma makaleme bakın ). Bu yüzden tamamen okumalı ve sonra tek satırlarla çalışmalısınız.

Burada cevapların çoğu yanlış değil, kötü bir tarz. Dosyaların her zaman with, dosyanın tekrar kapatıldığından emin olunmasıyla birlikte yapılmalıdır .

Yani böyle yapmalısın:

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

Büyük dosyalar

Büyük bir dosyanız varsa ve bellek tüketimi bir endişeniz varsa, satır satır işleyebilirsiniz:

with open("path/to/file.txt") as f:
    for i, line in enumerate(f):
        pass  # process line i

IMO, sadece ilk 30 satırı almak için bilinmeyen uzunlukta bir dosyayı okumak gerçekten kötü bir stildir .. bellek tüketimi hakkında .. ve sonsuz akışlar hakkında ne?
return42

@ return42 Uygulamaya çok bağlı. Birçoğu için, bir metin dosyasının kullanılabilir bellekten daha küçük bir boyuta sahip olduğunu varsaymak tamamen iyidir. Büyük olasılıkla büyük dosyalarınız varsa, cevabımı düzenledim.
Martin Thoma

alok cevapla aynı olan ekiniz için teşekkürler . Ve üzgünüm hayır, bunun uygulamaya bağlı olduğunu düşünmüyorum. IMO her zaman daha fazla satır okumak gerekir daha iyidir.
return42

7

Bunlardan bazıları güzel, ama çok daha basit bir şekilde yapılabilir:

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)

Bu basitçe liste dilimleme kullanır, tüm dosyayı yükler, ancak çoğu sistem bellek kullanımını uygun şekilde en aza indirir, yukarıda verilen yöntemlerin çoğundan daha hızlıdır ve 10G + veri dosyalarımda çalışır. İyi şanslar!


4

Okuma başlığınızı dosya içinde belirtilen bir bayta konumlandıran seek () çağrısı yapabilirsiniz . Okumak istediğiniz satırdan önce dosyaya kaç bayt (karakter) yazıldığını bilmediğiniz sürece bu size yardımcı olmaz. Belki de hızınızı gerçekten istiyorsanız, dosyanız kesin bir şekilde biçimlendirilmiştir (her satır X bayt sayısıdır?) Veya karakter sayısını kendiniz sayabilirsiniz (satır sonları gibi görünmez karakterler eklemeyi unutmayın).

Aksi takdirde, burada önerilen birçok çözümden birine göre, istediğiniz satırdan önce her satırı okumalısınız.


3

Büyük metin dosyanız filekesinlikle iyi yapılandırılmışsa (yani her satırın uzunluğu aynı ise l),- nsatır için kullanabilirsiniz

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

Feragatname Bu sadece aynı uzunlukta dosyalar için geçerlidir!


2

Buna ne dersin:

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

Doğru, bu
Alok'ınkinden


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

Roger, en sevdiğim adam! Bu bir with ifadesinden yararlanabilir.
Hamish Grubijan

2

Bu yaklaşımı tercih ediyorum çünkü daha genel amaçlı, yani bir dosyada, f.readlines()bir StringIOnesnede, bir nesnede, ne olursa olsun kullanabilirsiniz:

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

İşte benim küçük 2 sent, değerinde ne için;)

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

Alok Singhal'ın cevabı için daha iyi ve küçük bir değişiklik

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, numaralandırma kullanabilirsiniz

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 deyimini kullanarak dosyayı açar, 26 ve 30. satırları yazdırır, sonra dosyayı kapatır. Basit!


bu geçerli bir cevap değil. readlines()yineleyiciye yapılan ilk çağrı bittikten ve ikinci çağrı boş bir liste döndürür veya bir hata atarsa ​​(hangisini hatırlayamıyorum)
Paul H

1

Bunu daha önce bahsettiğiniz sözdizimi ile çok basit bir şekilde yapabilirsiniz, ancak bunu yapmanın en kolay yolu:

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

1

3 numaralı satırı yazdırmak için,

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

Orijinal yazar: Frank Hofmann


1

Oldukça hızlı ve noktaya.

Bir metin dosyasındaki belirli satırları yazdırmak için. Bir "lines2print" listesi oluşturun ve sonra numaralandırma lines2print listesinde "olduğunda" yazdırın. Fazladan '\ n' kurtulmak için line.strip () veya line.strip ('\ n') kullanın. Ben sadece "liste kavrama" seviyorum ve mümkün olduğunca kullanmaya çalışın. Herhangi bir nedenle bir dosyayı açık bırakmamak için metin dosyalarını okumak için "ile" yöntemini seviyorum.

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]

ya da liste küçükse, listeyi anlama alanına bir liste olarak yazın.

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

0

İstediğiniz satırı yazdırmak için. Çizgiyi istenen çizginin üstüne / altına yazdırmak için.

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

yürütmek ----> dline ("D: \ dummy.txt", 6) yani dline ("dosya yolu", satır_sayısı, aranan satırın üst satırının alt -1 için 1 vermesini istiyorsanız, bu isteğe bağlı varsayılan değer olacaktır alınacak 0)


0

Bazı eşik çizgilerinden sonra başlayan satır gibi belirli satırları okumak istiyorsanız, aşağıdaki kodları kullanabilirsiniz, 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
bu mümkün olduğu kadar sessizdir.
SilentGhost

Yanlış sonuçları verir, çünkü okuma satırlarını ve okuma satırını bu şekilde kullanamazsınız (her biri geçerli okuma konumunu değiştirir).

İlk kodumda BÜYÜK bir hatayı göz ardı ettiğim için özür dilerim. Hata düzeltildi ve mevcut kod beklendiği gibi çalışmalı. Hatamı belirttiğin için teşekkürler Roger Pate.
inspectorG4dget

-1

Bence bu işe yarayacak

 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]

Bunu yayınladığınızda zaten bir düzine okuma yöntemi vardı - başka bir şey eklemek sadece dağınıklık ekliyor
duhaime
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.