2016-04-24 12 views
6

ich eine 30MB .txt-Datei haben, mit eine Datenzeile (30 Millionen stellige Zahl)
Leider jede Methode, die ich versucht habe (mmap.read(), readline(), Zuweisung von 1 GB RAM, für Schleifen) dauert mehr als 45 Minuten, um die Datei vollständig zu lesen. Jede Methode, die ich im Internet gefunden habe, scheint an der Tatsache zu arbeiten, dass jede Zeile klein ist, deshalb ist der Speicherverbrauch nur so groß wie die größte Zeile in der Datei. Hier ist der Code, den ich benutzt habe.Lesen Very Large One Liner Textdatei

start = time.clock() 
z = open('Number.txt','r+') 
m = mmap.mmap(z.fileno(), 0) 
global a 
a = int(m.read()) 
z.close() 
end = time.clock() 
secs = (end - start) 
print("Number read in","%s" % (secs),"seconds.", file=f) 
print("Number read in","%s" % (secs),"seconds.") 
f.flush() 
del end,start,secs,z,m 

Andere als die Aufteilung der Nummer von einer Zeile auf verschiedene Zeilen; was ich lieber nicht machen würde, gibt es eine sauberere Methode, die nicht den besseren Teil einer Stunde benötigt?

Übrigens muss ich nicht unbedingt Textdateien verwenden.

Ich habe: Windows 8.1 64-Bit, 16 GB RAM, Python 3.5.1

+1

Das Lesen einer 30-MB-Datei ist schnell. Es ist der 'int (Dateiinhalt)', der langsam ist. –

+0

Ist Ihnen bewusst, dass die Konvertierung mehr oder weniger Approximation ergibt, je nachdem, welchen Typ Sie wählen? Du wirst nicht all die Milliarden Ziffern davon behalten. – Roberto

+0

... Ich meine, natürlich können Sie vielleicht an dieser Nummer arbeiten, aber die Standardtypen werden nicht 30 Millionen signifikante Ziffern alle in einer Nummer enthalten. Sie werden sich annähern. Sie müssen entweder nach einem Weg suchen oder es implementieren. – Roberto

Antwort

1

Ich benutzte das gmpy2 Modul, um die Zeichenkette in eine Zahl umzuwandeln.

Es funktionierte in 3 Sekunden, viel langsamer, aber zumindest gab es mir einen ganzzahligen Wert.

Vielen Dank für Ihre unschätzbaren Antworten, aber ich werde diese so bald wie möglich markieren.

3

A 30MB Textdatei sollte nicht sehr lange dauern, zu lesen, sollten moderne Festplatten der Lage sein, dies zu tun in weniger als eine Sekunde (nicht Zugriffszeit mitgezählt)

die Standard-python-Datei mit IO sollte in diesem Fall funktionieren:

with open('my_file', 'r') as handle: 
    content = handle.read() 

mit diesem auf meinem Laptop liefert mal viel weniger als eine Sekunde.

Die Umwandlung dieser 30 MB in eine ganze Zahl ist jedoch Ihr Engpass , da Python dies nicht mit dem long-Datentyp darstellen kann.

Sie können versuchen mit dem Dezimal-Modul, aber es ist hauptsächlich für Fließkomma-Arithmetik ausgelegt.

Daneben gibt es natürlich numpy, das könnte schneller sein (und da Sie wahrscheinlich später mit der Nummer arbeiten möchten, wäre es sinnvoll, eine solche Bibliothek zu verwenden).

+0

Würde nicht Numpy das gleiche Problem haben? Sie versuchen beide eine sehr große Saite in eine Zahl zu konvertieren. –

11

Die Datei lesen ist schnell (< 1s):

with open('number.txt') as f: 
    data = f.read() 

einen 30-Millionen-stellige Zeichenfolge in einer ganzen Zahl konvertieren, das ist langsam:

z=int(data) # still waiting... 

Wenn Sie die Zahl als Ausgang speichern Big-oder Little-Endian Binärdaten, dann int.from_bytes(data,'big') ist viel schneller.

Wenn ich meine Mathe richtig gemacht habe (Anmerkung _ bedeutet "Antwort der letzten Zeile" in Python interaktiven Interpreter):

>>> import math 
>>> math.log(10)/math.log(2) # Number of bits to represent a base 10 digit. 
3.3219280948873626 
>>> 30000000*_    # Number of bits to represent 30M-digit #. 
99657842.84662087 
>>> _/8      # Number of bytes to represent 30M-digit #. 
12457230.35582761    # Only ~12MB so file will be smaller :^) 
>>> import os 
>>> data=os.urandom(12457231) # Generate some random bytes 
>>> z=int.from_bytes(data,'big') # Convert to integer (<1s) 
99657848 
>>> math.log10(z) # number of base-10 digits in number. 
30000001.50818886 

EDIT: FYI, meine Mathe nicht richtig war, aber ich regelte es. Danke für 10 upvotes ohne es zu merken: ^)

+0

Wenn ich versuche, die int.from_bytes (Daten, 'groß') zu verwenden, bekomme ich einen "TypeError: kann Unicode-Objekt in Bytes nicht konvertieren" –

+1

@ Master-Chip Lesen Sie es mit 'rb', um Binärdaten zu erhalten. –

+0

Ups, das war peinlich. Es funktioniert super, es hat es in 0,39 Sekunden gelesen, danke. –