Newsgroup: it.comp.java
Titolo: Come mescolare le righe di un file di testo ed evitare "java.lang.OutOfMemoryError: Java heap space"

Salve a tutti,
ho un file di testo composto da circa 1.500.000 righe che devo
mescolarle.
Attualmente inserisco ogni riga in un ArrayList, poi lo mescolo
tramite  Collections.shuffle per poi ciclare l'ArrayList mescolato e
creare il nuovo file.
Esiste un approccio che mi eviti l'eccezione
""java.lang.OutOfMemoryError: Java heap space" e che non mi costringa
ad aumentare l'heap space?
grazie anticipatamente

Salve a tutti,
ho un file di testo composto all'incirca da 1.500.000 righe che devo
mescolare.
L'unica soluzione che mi è venuta in mente, per fare questo, è quello
di inserire ogni riga in un ArrayList, mescolarlo e poi salvare il
nuovo file. Questo però mi genera problemi di memoria.
Avete da suggerirmi qualche altro approccio per evitare ciò e che non
riguardi l'aumento  dell'heap space?
grazie anticipatamente

 riguardi l'aumento  dell'heap space?
Comunque, una soluzione (di certo piu' lenta, pero') potrebbe essere: apri 
il file, conti quante righe sono, richiudi il file.
generi un list di integer, da 1 a $N_RIGHE
mescoli quello
apri il file sorgente in lettura, quello destinazione in append
per ogni numero di riga
  leggi la riga dal file in lettura
  scrivi in fondo la riga sul file in scrittura
-- 
By ZeD

 file di 15 mega...
Uno zero mancante, se sono 1,5*10^8 byte sono 150 MB.

 mega...
intanto come è stato fatto notare hai sbagliato di un ordine di 
grandezza. inoltre un file di testo caricato su stringhe in java diventa 
unicode quindi l'occupazione nell'heap è ancora (almeno) raddoppiata. 
infine se il sistema fosse a 64 bit raddoppierebbe anche la dimensione 
dei 1,5 milioni di puntatori...

 dei 1,5 milioni di puntatori...
hai soluzioni da proporre?
Un'alternativa sarebbe delegare il compito ad un db: fare una insert per 
riga in una tabella con 3 colonne: n° riga, contentuto riga, numero random;
poi fare una serie di query (magari recuperando un 100, 1000 o 10000 righe 
per volta) selezionando i primi (ordinati per la colonna random) elementi 
non ancora scritti, scrivendoli in append sul file destinazione e infine 
cancellandoli dal db (usando il n° riga come chiave).
-- 
By ZeD


1) L'ovvietà, ma hai provato ad aggiungere ram all'heap, vero? 150Mb
di heap non sono molti.... una jvm su 32 bit ne tiene più di 1000...
Al limite il SO userà la memoria virtuale.
2) Se vuoi qualcosa di 'pseudo infinitamente' scalabile (2 int[] di
dimensione del n. di righe li dovrai cmq avere...), ti dico la prima
cosa che mi viene in mente:
Leggi il file e memorizzi in ram (ArrayList<Integer> o meglio int[])
la sommatoria delle posizioni degli 'acapi' (per es se la prima riga
ha 100 bytes, la seconda 80 e la terza 20, memorizzi 100,180,200)
Ti prepari un'altra lista di interi da 1 a N (N è il numero di righe)
e la mescoli
Poi leggi il file in modialità 'random access' usando il primo array
come punto di lettura e facendo append sull'output.
Dovesse essere troppo lento (mi aspetto che lo sarà), puoi tentare di
aumentare le prestazioni memorizzando una parte delle stringhe in una
memoria 'cache' (adesso non ricordo di preciso, ma del tipo "phantom/
weak/soft reference (credo sia la soft)") così quando si tratta di
leggere da qualcosa in cache la velocità è istantanea. (NB, purtroppo
non esiste una SoftHashMap nel JDK. Devi aggiungere una dipendenza o
dalle Apache Collections o dalle Google Collections)

 By ZeD
alla fine penso che utilizzerò la soluzione del database: inserisco
1.500.000 righe nel db,
li "randomizzo" tramite query e poi li salvo su file.

Nide wrote:

l'unica cosa, fai attenzione a come mischi: 
http://www.robweir.com/blog/2010/02/microsoft-random-browser-ballot.html
http://www.codinghorror.com/blog/2007/12/shuffling.html
http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
(anche se dipende molto da quante volte dovrai fare quest'operazione)
-- 
By ZeD