2011-11-16 37 views
17

Dường như giao diện mmap chỉ hỗ trợ readline(). Nếu tôi cố gắng lặp lại đối tượng, tôi nhận được ký tự thay vì dòng hoàn chỉnh.Cách đọc các dòng từ tệp mmap trong python?

Phương pháp "pythonic" đọc dòng tệp mmap'ed theo dòng là gì?

import sys 
import mmap 
import os 


if (len(sys.argv) > 1): 
    STAT_FILE=sys.argv[1] 
    print STAT_FILE 
else: 
    print "Need to know <statistics file name path>" 
    sys.exit(1) 


with open(STAT_FILE, "r") as f: 
    map = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ) 
    for line in map: 
    print line # RETURNS single characters instead of whole line 
+1

Ra quan tâm, động lực cho việc sử dụng một tập tin bộ nhớ ánh xạ cho điều này là những gì, như trái ngược với một tập tin bình thường không? – NPE

+1

@aix: Tôi có thể có dữ liệu thô của GB và tôi muốn truy cập chúng theo phương pháp hiệu quả nhất có thể. Nhưng lý do thực sự là: It's cooler :) –

+0

Tôi không biết liệu nó có mát hay không, nhưng bạn không nên chỉ đơn giản giả định rằng nó nhanh hơn (nếu bạn thực sự quan tâm, bạn nên cấu hình). – NPE

Trả lời

22

Cách ngắn gọn nhất để lặp qua các đường dây của một mmap

with open(STAT_FILE, "r+b") as f: 
    map = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ) 
    for line in iter(map.readline, ""): 
     # whatever 
+2

Tôi không biết 'iter' nhận cặp đối số' callable'/'sentinel' này. +1 và xóa câu trả lời của tôi để ủng hộ câu trả lời này. –

+0

Và hãy thay đổi chế độ mở thành 'r + b' thay vì' r' (như đã đề cập trong bài đăng của tôi dưới đây). – hochl

+0

@hochl: Cảm ơn, đã hoàn thành. –

12

tôi sửa đổi ví dụ của bạn như thế này:

with open(STAT_FILE, "r+b") as f: 
     m=mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ) 
     while True: 
       line=m.readline() 
       if line == '': break 
       print line.rstrip() 

Gợi ý:

  • không gọi một biến map, đây là một chức năng built-in.
  • mở tệp ở r+b chế độ, như trong ví dụ Python trên trang trợ giúp mmap. Nó tuyên bố: Trong cả hai trường hợp, bạn phải cung cấp một bộ mô tả tập tin cho một tập tin được mở để cập nhật. Xem http://docs.python.org/library/mmap.html#mmap.mmap.
  • tốt hơn là không sử dụng tên biến toàn cầu UPPER_CASE_WITH_UNDERSCORES, như được đề cập trong Tên biến toàn cục tại http://www.python.org/dev/peps/pep-0008. Trong các ngôn ngữ lập trình khác (như C), hằng số thường được viết bằng chữ hoa.

Hy vọng điều này sẽ hữu ích.

EDIT: Tôi đã thực hiện một số kiểm tra thời gian trên Linux vì nhận xét khiến tôi tò mò. Dưới đây là so sánh về thời gian được thực hiện trên 5 lần chạy tuần tự trên tệp văn bản 137MB.

# normal file access. 
real 2.410 2.414 2.428 2.478 2.490 
sys  0.052 0.052 0.064 0.080 0.152 
user 2.232 2.276 2.292 2.304 2.320 

# mmap file access. 
real 1.885 1.899 1.925 1.940 1.954 
sys  0.088 0.108 0.108 0.116 0.120 
user 1.696 1.732 1.736 1.744 1.752 

Thời gian đó không bao gồm tuyên bố print (Tôi đã loại trừ nó). Sau những con số này tôi muốn nói rằng bộ nhớ truy cập tập tin ánh xạ là khá nhanh hơn một chút.

EDIT 2: Sử dụngpython -m cProfile test.py tôi có kết quả như sau:

5432833 2.273 0.000 2.273 0.000 {method 'readline' of 'file' objects} 
5432833 1.451 0.000 1.451 0.000 {method 'readline' of 'mmap.mmap' objects} 

Nếu tôi không nhầm thì mmap là khá một chút nhanh hơn.

Ngoài ra, có vẻ như not len(line) hoạt động kém hơn line == '', ít nhất đó là cách tôi giải thích đầu ra của hồ sơ.

+0

'Thuộc tínhError: đối tượng 'mmap.mmap' không có thuộc tính 'readlines'' –

+1

hochl: Cảm ơn bạn. Các tiêu chuẩn là rất tốt. Bạn có thể đính kèm tập lệnh để tạo lại bài kiểm tra và xác nhận phân tích không? –

+1

Tôi chỉ đơn giản là nhận xét ra các bản in trong chương trình của bạn và sau đó đã làm 'time test.py' như 10 lần, sau đó lấy 5 giá trị trung bình. Sẽ rất thú vị khi kiểm tra kết quả của 'python -m cProfile test.py'. – hochl

1

Sau đây là cách hợp lý ngắn gọn:

with open(STAT_FILE, "r") as f: 
    m = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ) 
    while True: 
     line = m.readline() 
     if line == "": break 
     print line 
    m.close() 

Lưu ý rằng line giữ lại xuống dòng, vì vậy bạn có thể muốn loại bỏ nó. Đó cũng là lý do tại sao if line == "" làm điều đúng (một dòng trống được trả lại là "\n").

Lý do bản gốc lặp lại hoạt động theo cách của nó là mmap cố gắng trông giống như cả tệp và chuỗi. Nó trông giống như một chuỗi với mục đích lặp lại.

Tôi không biết tại sao không thể (hoặc chọn không) cung cấp readlines()/xreadlines().

+0

Phương thức 'readlines()' của đối tượng tệp trả về một danh sách tất cả các dòng của tệp. làm điều này trên một tập tin mmapped hoàn toàn sẽ đánh bại mục đích của mmap. –

+0

@SvenMarnach: Nó có thể là một máy phát điện. Trong mọi trường hợp, để được hoàn toàn trung thực tôi không nhìn thấy sự cần thiết cho các tập tin bộ nhớ ánh xạ trong toàn bộ câu hỏi này. – NPE

+0

Bạn hoàn toàn đúng. Vì vậy, có lẽ lý do cho sự tồn tại của một máy phát điện như vậy là nó sẽ là vô nghĩa. :) –

Các vấn đề liên quan