Jak odczytać linie z pliku mm?

Wygląda na to, że interfejs mmap obsługuje tylko readline (). Jeśli próbuję iterację nad obiektem, otrzymuję znak zamiast pełnych linii.

Jaka byłaby metoda "pythoniczna" odczytu pliku mmap wiersz po wierszu?

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
Author: martineau, 2011-11-16

4 answers

Najbardziej zwięzłym sposobem iteracji po liniach mmap jest

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

Zauważ, że w Pythonie 3 parametr sentinel iter() musi być typu bytes, podczas gdy w Pythonie 2 musi być str (tj. "" zamiast b"").

 32
Author: Sven Marnach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-04 19:17:39

Zmodyfikowałem twój przykład tak:

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

Sugestie:

Mam nadzieję, że to pomoże.

Edit: zrobiłem kilka testów czasu na Linuksie, ponieważ komentarz mnie zaciekawił. Oto porównanie timingów wykonanych na 5 sekwencyjnych uruchomieniach na pliku tekstowym 137mb.

Normalny dostęp do pliku:

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 dostęp do pliku:

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

Te terminy nie zawierają print Oświadczenia (wykluczyłem go). Po tych numerach powiedziałbym, że dostęp do plików mapowanych w pamięci jest nieco szybszy.

Edit 2: używając python -m cProfile test.py otrzymałem następujące wyniki:

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}

Jeśli się nie mylę to mmap jest trochę szybszy.

Dodatkowo wydaje się, że not len(line) działa gorzej niż line == '', przynajmniej tak interpretuję wyjście profilera.

 15
Author: hochl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-27 00:56:54

Następujące są dość zwięzłe:

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

Zauważ, że line zachowuje nowy wiersz, więc możesz chcieć go usunąć. Jest to również powód, dla którego if line == "" robi właściwe rzeczy(pusta linia jest zwracana jako "\n").

Oryginalna iteracja działa tak, jak działa, ponieważ mmap próbuje wyglądać zarówno jak plik, jak i łańcuch znaków. Wygląda jak ciąg dla celów iteracji.

Nie mam pojęcia, dlaczego nie może (lub nie chce) dostarczyć readlines()/xreadlines().

 1
Author: NPE,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-16 13:24:25

Python 2.7 32bit w Windows jest ponad dwa razy szybszy na pliku mm:

Na 27MB, 509k pliku tekstowego linii (moja funkcja 'parse' nie jest interesująca, głównie tylko readline () jest bardzo szybko):

with open(someFile,"r") as f:
    if usemmap:
        m=mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
    else:
        m=f
        e.parse(m)

Z MMAP:

read in 0.308000087738

Bez MMAP:

read in 0.680999994278
 0
Author: Richard Aplin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-12-29 03:48:08