2016-04-24 30 views
6

Ho un file .txt 30MB, con una riga di dati (30 milioni Numero Digit)
Purtroppo, ogni metodo che ho provato (mmap.read(), readline(), allocare 1 GB di RAM, per i loop) richiede più di 45 minuti per leggere completamente il file. Ogni metodo che ho trovato su internet sembra funzionare sul fatto che ogni riga è piccola, quindi il consumo di memoria è grande solo quanto la riga più grande del file. Ecco il codice che ho usato.lettura molto grande Liner Text File

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 

Diverso dal suddividere il numero da una linea a varie linee; che preferirei non fare, esiste un metodo più pulito che non richiederà la parte migliore di un'ora?

A proposito, non devo necessariamente usare file di testo.

ho: Windows 8.1 a 64 bit, 16 GB di RAM, Python 3.5.1

+1

Leggere un file di 30 MB è veloce. È il 'int (filecontent)' che è lento. –

+0

Sei consapevole che la conversione genererà un'approssimazione su di essa, più o meno a seconda del tipo che scegli? Non manterrai tutte le cifre di Gazillion di esso. – Roberto

+0

... Voglio dire, ovviamente potresti essere in grado di lavorare su quel numero, ma i tipi standard non contengono 30 milioni di cifre significative in un unico numero. Saranno approssimativi. Dovrai cercare o implementare un modo per farlo. – Roberto

risposta

1

Ho usato il modulo gmpy2 per convertire la stringa in numero.

start = time.clock() 
z=open('Number.txt','r+') 
data=z.read() 
global a 
a=gmpy2.mpz(data) 
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,secs,start,z,data 

ha funzionato in 3 secondi, molto più lento, ma almeno mi ha dato un valore intero.

Grazie a tutti per le vostre risposte inestimabili, tuttavia vado a contrassegnarlo al più presto possibile.

3

Un file di testo 30 MB non dovrebbe richiedere molto tempo per leggere, moderni hard disk dovrebbero essere in grado di farlo in meno di un secondo (senza contare il tempo di accesso)

Utilizzando il file standard di Python IO dovrebbe funzionare bene, in questo caso:

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

Usando questo sul mio portatile produce volte molto meno di un secondo.

Tuttavia, la conversione di quei 30 MB per un intero è il collo di bottiglia, in quanto Python non può rappresentare questo con il long tipo di dati.

È possibile provare con il modulo Decimal, tuttavia è progettato principalmente per l'aritmetica in virgola mobile.

Oltre a ciò, naturalmente è presente un numpy, che potrebbe essere più veloce (e dato che probabilmente vorresti fare un po 'di lavoro con il numero più tardi, sarebbe logico usare una tale libreria).

+0

Tuttavia Numpy non ha lo stesso problema? Stanno entrambi cercando di convertire una stringa molto grande in un numero. –

11

Il file di lettura è veloce (< 1s):

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

conversione di una stringa di 30 milioni di cifre per un numero intero, che è lento:

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

Se si memorizza il numero come grezzo dati binari big o little-endian, quindi int.from_bytes(data,'big') è molto più veloce.

Se ho fatto il mio diritto di matematica (Nota _ significa "la risposta di ultima linea" in interprete interattivo di Python):

>>> 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: Cordiali saluti, la mia matematica non era giusto, ma ho riparato. Grazie per 10 upvotes senza accorgersene: ^)

+0

Se provo a usare int.from_bytes (data, 'big'), ottengo un "TypeError: non posso convertire l'oggetto unicode in byte" –

+1

@ Master-chip Leggilo con 'rb' per ottenere dati binari. –

+0

Oops, era imbarazzante. Funziona benissimo, lo legge in 0.39 secondi, grazie. –