Chỉ đọc những dòng cụ thể


Câu trả lời:


253

Nếu tệp cần đọc lớn và bạn không muốn đọc toàn bộ tệp trong bộ nhớ cùng một lúc:

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

Lưu ý rằng i == n-1đối với ndòng thứ.


Trong Python 2.6 trở lên:

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)sử dụng x.next, vì vậy nó không cần toàn bộ tập tin trong bộ nhớ.
Alok Singhal

3
Thịt bò nhỏ của tôi với cái này là A) Bạn muốn sử dụng thay vì cặp mở / đóng và do đó giữ cho cơ thể ngắn, B) Nhưng cơ thể không phải là ngắn. Âm thanh như một sự đánh đổi giữa tốc độ / không gian và là Pythonic. Tôi không chắc giải pháp tốt nhất sẽ là gì.
Hamish Grubijan

5
với sự đánh giá quá cao, con trăn đã sống tốt trong hơn 13 năm mà không có nó
Dan D.

38
@Dan D. Điện được đánh giá cao, nhân loại đã hòa thuận với nhau trong hơn 200 nghìn năm mà không có nó. ;-) 'với' đang làm cho nó an toàn hơn, dễ đọc hơn và ngắn hơn một dòng.
Romain Vincent

9
Tại sao sử dụng cho vòng lặp, tôi không nghĩ bạn hiểu ý nghĩa của big file. Vòng lặp sẽ mất nhiều năm để đạt được chỉ số
devssh

159

Câu trả lời nhanh:

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

hoặc là:

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

Có một giải pháp tinh tế hơn để trích xuất nhiều dòng: linecache (phép lịch sự của "python: làm thế nào để chuyển đến một dòng cụ thể trong một tệp văn bản lớn?" , Một câu hỏi stackoverflow.com trước đó).

Trích dẫn tài liệu python được liên kết ở trên:

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

Thay đổi 4số dòng mong muốn của bạn và bạn đang bật. Lưu ý rằng 4 sẽ mang lại dòng thứ năm vì số đếm là không dựa trên.

Nếu tệp có thể rất lớn và gây ra sự cố khi đọc vào bộ nhớ, có thể nên lấy lời khuyên của @ Alok và sử dụng phép liệt kê () .

Để kết luận:

  • Sử dụng fileobject.readlines()hoặc for line in fileobjectnhư một giải pháp nhanh chóng cho các tập tin nhỏ.
  • Sử dụng linecachecho một giải pháp thanh lịch hơn, sẽ khá nhanh để đọc nhiều tệp, có thể lặp đi lặp lại.
  • Hãy tham khảo lời khuyên của @ Alok và sử dụngenumerate() cho các tệp có thể rất lớn và sẽ không vừa với bộ nhớ. Lưu ý rằng sử dụng phương pháp này có thể chậm vì tệp được đọc tuần tự.

7
Đẹp. Tôi chỉ nhìn vào nguồn của linecachemô-đun, và có vẻ như nó đọc toàn bộ tập tin trong bộ nhớ. Vì vậy, nếu truy cập ngẫu nhiên quan trọng hơn tối ưu hóa kích thước, linecachelà phương pháp tốt nhất.
Alok Singhal

7
với linecache.getlin ('some_file', 4) Tôi nhận được dòng thứ 4, không phải dòng thứ 5.
Juan

sự thật thú vị: nếu bạn sử dụng một tập hợp thay vì danh sách trong ví dụ thứ hai, bạn sẽ có thời gian chạy O (1). Tra cứu trong một danh sách là O (n). Các bộ bên trong được biểu diễn dưới dạng băm và đó là lý do tại sao bạn có thời gian chạy O (1). không phải là một vấn đề lớn trong ví dụ này, nhưng nếu sử dụng một danh sách lớn các con số và quan tâm đến hiệu quả, thì các bộ là cách để đi.
rạng rỡ

linecachebây giờ dường như chỉ hoạt động cho các tệp nguồn python
Paul H

Bạn cũng có thể sử dụng linecache.getlines('/etc/passwd')[0:4]để đọc trong dòng đầu tiên, thứ hai, thứ ba và thứ tư.
zyy

30

Một cách tiếp cận nhanh và gọn có thể là:

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

điều này chấp nhận mọi đối tượng giống như tệp đang mở thefile(tùy thuộc vào người gọi cho dù nó có được mở từ tệp đĩa hay thông qua ổ cắm, hoặc luồng giống như tệp khác) và một bộ chỉ mục dòng dựa trên không whatlinesvà trả về danh sách, với dấu chân bộ nhớ thấp và tốc độ hợp lý. Nếu số lượng dòng được trả về là rất lớn, bạn có thể thích một trình tạo:

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

về cơ bản chỉ tốt cho việc lặp lại - lưu ý rằng sự khác biệt duy nhất đến từ việc sử dụng dấu ngoặc tròn thay vì dấu ngoặc vuông trong returncâu lệnh, tạo ra sự hiểu biết danh sách và biểu thức trình tạo tương ứng.

Lưu ý thêm rằng mặc dù đề cập đến "dây chuyền" và "tập tin" các chức năng này là nhiều, nhiều hơn nói chung - họ sẽ làm việc trên bất kỳ iterable, có thể là một tập tin mở hoặc bất kỳ khác, trả lại một danh sách (hoặc máy phát điện) các mặt hàng dựa trên số mục tiến bộ của họ. Vì vậy, tôi khuyên bạn nên sử dụng tên chung phù hợp hơn ;-).


@ephemient, tôi không đồng ý - genEx đọc trơn tru và hoàn hảo.
Alex Martelli

Giải pháp tuyệt vời và thanh lịch, cảm ơn! Thật vậy, ngay cả các tệp lớn cũng cần được hỗ trợ, với biểu thức trình tạo. Không thể thanh lịch hơn thế này, phải không? :)
Samuel Lampa

Giải pháp tuyệt vời, làm thế nào để so sánh với giải pháp được đề xuất bởi @AdamMatan? Giải pháp Adam có thể nhanh hơn vì nó khai thác thêm thông tin (số dòng tăng đơn điệu) có thể dẫn đến dừng sớm. Tôi có một tệp 10 GB mà tôi không thể tải vào bộ nhớ.
Mannaggia

2
@Mannaggia Nó không được nhấn mạnh đủ trong câu trả lời này, nhưng whatlinesnên là một set, bởi vì if i in whatlinessẽ thực thi nhanh hơn với một tập hợp chứ không phải là một danh sách (được sắp xếp). Tôi đã không chú ý đến nó trước và thay vào đó đã nghĩ ra giải pháp xấu xí của riêng mình với danh sách được sắp xếp (nơi tôi không phải quét danh sách mỗi lần, trong khi if i in whatlinesđó), nhưng sự khác biệt về hiệu suất là không đáng kể (với dữ liệu của tôi) và điều này Giải pháp thanh lịch hơn nhiều.
Victor K

28

Vì mục đích đưa ra một giải pháp khác:

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

Tôi hy vọng điều này là nhanh chóng và dễ dàng :)


1
Hy vọng đây là giải pháp tối ưu nhất.
maniac_user

2
Điều này đọc toàn bộ tập tin vào bộ nhớ. Bạn cũng có thể gọi file.read (). Split ('\ n') sau đó sử dụng tra cứu chỉ mục mảng để có được dòng quan tâm ...
duhaime

Bạn có thể cung cấp một ví dụ @duhaime
anon

14

nếu bạn muốn dòng 7

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

14
Khéo léo. Nhưng làm thế nào để bạn close()tập tin khi mở nó theo cách này?
Milo Wielondek

1
@ 0sh chúng ta có cần đóng không?
Ooker

1
Đúng. chúng ta cần phải đóng lại sau này. Khi chúng ta mở một tệp bằng cách sử dụng "với" ... nó sẽ tự đóng lại.
reetesh11

10

Để hoàn thiện, đây là một lựa chọn nữa.

Hãy bắt đầu với một định nghĩa từ các tài liệu python :

lát Một đối tượng thường chứa một phần của chuỗi. Một lát cắt được tạo bằng cách sử dụng ký hiệu đăng ký, [] với dấu hai chấm giữa các số khi một số được đưa ra, chẳng hạn như trong biến_name [1: 3: 5]. Ký hiệu ngoặc (đăng ký) sử dụng các đối tượng lát bên trong (hoặc trong các phiên bản cũ hơn, __getslice __ () và __setslice __ ()).

Mặc dù ký hiệu lát cắt không thể áp dụng trực tiếp cho các trình vòng lặp nói chung, itertoolsgói chứa hàm thay thế:

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

Ưu điểm bổ sung của hàm là nó không đọc iterator cho đến khi kết thúc. Vì vậy, bạn có thể làm những điều phức tạp hơn:

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

Và để trả lời câu hỏi ban đầu:

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

1
Cho đến nay cách tiếp cận tốt nhất khi làm việc với các tệp lớn. Chương trình của tôi đã chuyển từ tiêu thụ 8GB + sang gần như không có gì. Giao dịch là việc sử dụng CPU đã tăng từ ~ 15% đến ~ 40% nhưng quá trình xử lý tệp thực tế nhanh hơn 70%. Tôi sẽ thực hiện giao dịch đó cả ngày. Cảm ơn bạn! 🎉🎉🎉
GollyJer

1
Điều này có vẻ như pythonic nhất đối với tôi. Cảm ơn!
ipetrik

10

Đọc các tập tin là nhanh chóng đáng kinh ngạc. Đọc một tệp 100 MB chỉ mất chưa đến 0,1 giây (xem bài viết của tôi Đọc và ghi tệp bằng Python ). Do đó bạn nên đọc nó hoàn toàn và sau đó làm việc với các dòng đơn.

Những gì hầu hết câu trả lời ở đây làm không phải là sai, nhưng phong cách xấu. Mở tập tin phải luôn luôn được thực hiện vớiwith vì nó đảm bảo rằng tệp được đóng lại.

Vì vậy, bạn nên làm điều đó như thế này:

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

Tập tin lớn

Nếu bạn có một tập tin lớn và tiêu thụ bộ nhớ là một mối quan tâm, bạn có thể xử lý từng dòng một:

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

IMO đó là một phong cách thực sự tồi tệ khi đọc toàn bộ tệp có chiều dài không xác định, chỉ để có được 30 dòng đầu tiên .. điều gì về mức tiêu thụ bộ nhớ .. và những gì về dòng vô tận?
return42

@ return42 Nó phụ thuộc rất nhiều vào ứng dụng. Đối với nhiều người, hoàn toàn ổn khi cho rằng một tệp văn bản có kích thước thấp hơn bộ nhớ khả dụng. Nếu bạn tình cờ có các tệp rất lớn, tôi đã chỉnh sửa câu trả lời của mình.
Martin Thoma

cảm ơn vì sự bổ sung của bạn, giống như câu trả lời của alok . Và xin lỗi không, tôi không nghĩ rằng điều này phụ thuộc vào ứng dụng. IMO nó luôn luôn tốt hơn không đọc nhiều dòng hơn bạn cần.
return42

7

Một số trong số này là đáng yêu, nhưng nó có thể được thực hiện đơn giản hơn nhiều:

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)

Điều đó sẽ sử dụng danh sách cắt đơn giản, nó tải toàn bộ tệp, nhưng hầu hết các hệ thống sẽ giảm thiểu việc sử dụng bộ nhớ một cách phù hợp, nó nhanh hơn hầu hết các phương pháp được đưa ra ở trên và hoạt động trên các tệp dữ liệu 10G + của tôi. Chúc may mắn!


4

Bạn có thể thực hiện lệnh gọi () tìm vị trí đầu đọc của bạn đến một byte được chỉ định trong tệp. Điều này sẽ không giúp bạn trừ khi bạn biết chính xác có bao nhiêu byte (ký tự) được ghi trong tệp trước dòng bạn muốn đọc. Có lẽ tệp của bạn được định dạng nghiêm ngặt (mỗi dòng là X số byte?) Hoặc, bạn có thể tự đếm số lượng ký tự (nhớ bao gồm các ký tự vô hình như ngắt dòng) nếu bạn thực sự muốn tăng tốc độ.

Mặt khác, bạn phải đọc mọi dòng trước dòng bạn mong muốn, theo một trong nhiều giải pháp đã được đề xuất ở đây.


3

Nếu tệp văn bản lớn của bạn filecó cấu trúc chặt chẽ (có nghĩa là mọi dòng có cùng độ dài l), bạn có thể sử dụng cho ndòng -th

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

Tuyên bố từ chối Điều này chỉ hoạt động đối với các tệp có cùng độ dài!


2

Còn cái này thì sao:

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

Đúng, điều này kém hiệu quả hơn so với Alok, nhưng tôi sử dụng một tuyên bố có;)
Hamish Grubijan

2

Nếu bạn không nhớ nhập thì fileinput thực hiện chính xác những gì bạn cần (đây là bạn có thể đọc số dòng của dòng hiện tại)


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, chàng trai yêu thích của tôi! Điều này có thể được hưởng lợi từ một tuyên bố với.
Hamish Grubijan

2

Tôi thích cách tiếp cận này vì nó có mục đích chung hơn, tức là bạn có thể sử dụng nó trên một tệp, trên kết quả của f.readlines(), trên một StringIOđối tượng, bất cứ điều gì:

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

Đây là 2 xu nhỏ của tôi, với giá trị của nó;)

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

Một thay đổi tốt hơn và nhỏ hơn cho câu trả lời của Alok Singhal

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, bạn có thể sử dụng liệt kê

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]

Sử dụng câu lệnh with, điều này sẽ mở tệp, in các dòng 26 và 30, sau đó đóng tệp. Đơn giản!


Đây không phải là một câu trả lời hợp lệ. sau khi cuộc gọi đầu tiên đến readlines()iterator sẽ hết và cuộc gọi thứ hai sẽ trả về một danh sách trống hoặc đưa ra một lỗi (không thể nhớ đó)
Paul H

1

Bạn có thể làm điều này rất đơn giản với cú pháp mà ai đó đã đề cập, nhưng đó là cách dễ nhất để làm điều đó:

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

1

Để in dòng # 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

Tác giả gốc: Frank Hofmann


1

Khá nhanh chóng và đến điểm.

Để in một số dòng nhất định trong một tập tin văn bản. Tạo một danh sách "lines2print" và sau đó chỉ in khi liệt kê là "trong" danh sách lines2print. Để loại bỏ thêm '\ n', hãy sử dụng line.strip () hoặc line.strip ('\ n'). Tôi chỉ thích "hiểu danh sách" và cố gắng sử dụng khi tôi có thể. Tôi thích phương pháp "với" để đọc tệp văn bản để tránh để mở tệp vì bất kỳ lý do gì.

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]

hoặc nếu danh sách nhỏ chỉ cần nhập danh sách dưới dạng danh sách vào phần hiểu.

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

0

Để in dòng mong muốn. Để in dòng trên / dưới dòng yêu cầu.

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

thực thi ----> dline ("D: \ dummy.txt", 6) tức là dline ("đường dẫn tệp", line_number, nếu bạn muốn dòng trên của dòng tìm kiếm cho 1 cho dưới -1 thì đây là giá trị mặc định tùy chọn sẽ được lấy 0)


0

Nếu bạn muốn đọc các dòng cụ thể, chẳng hạn như dòng bắt đầu sau một số dòng ngưỡng thì bạn có thể sử dụng các mã sau đây, 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
Điều này là unpythonic như nó được.
SilentGhost

Cung cấp kết quả sai, vì bạn không thể sử dụng các đường dẫn và đường dẫn như thế (mỗi cái thay đổi vị trí đọc hiện tại).

Tôi xin lỗi vì đã bỏ qua một lỗi LỚN trong mã đầu tiên của tôi. Lỗi đã được sửa và mã hiện tại sẽ hoạt động như mong đợi. Cảm ơn đã chỉ ra lỗi của tôi, Roger Pate.
thanh

-1

Tôi nghĩ rằng nó sẽ làm việc

 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]

Đã có hàng tá phương thức đọc khi bạn đăng bài này - thêm một phương pháp khác chỉ thêm lộn xộn
duhaime
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.