Java - Dividi un file di testo SQL di grandi dimensioni sul delimetro usando lo scanner (outofmemoryerror)

StackOverflow https://stackoverflow.com/questions/20353915

  •  25-08-2022
  •  | 
  •  

Domanda

Sto cercando di scrivere un'applicazione che prenderà un file di testo SQL molto grande ~ 60 GB (257 milioni di righe) e dividerà ciascuna delle istruzioni di copia in file di testo separati.

Tuttavia, il codice che sto utilizzando attualmente provoca un OutOFMemoryError a causa delle linee che superano il limite del buffer scanner. La prima affermazione sarà lunga circa 40 milioni di righe.

public static void readFileByDelimeter(String fileName, String requestType, String output) throws FileNotFoundException {

//creating file instance
File file = new File(fileName);

//create scanner instance
Scanner scanner = new Scanner(file, "latin1");

//set custom delimeter
scanner.useDelimeter("COPY");

int number = 0;
System.out.println("Running......");
while (scanner.hasNext()){
    String line = scanner.next();
    if (line.length() > 20) {
        //save statements to seperate SQL files
        PrintWriter out = new PrintWriter("statement" + number + ".sql");
        out.println("COPY" + line.trim());
        out.close();
        }
        number++;
    }

System.out.println("Completed");
}

Si prega di fornire una raccomandazione sul fatto che questo sia il metodo sbagliato per eseguire questo o alterazioni al metodo esistente.

Grazie

È stato utile?

Soluzione

Innanzitutto, perché stai creando o qualche altro processo è la creazione di file da 60 GB! Forse devi dare un'occhiata a quel processo per correggere quel processo per generare un file di testo SQL più piccolo invece di creare un nuovo processo. Tuttavia, se questa è una cosa che devi fare, potrebbe andare bene, ma per rispondere alla tua domanda userei il bufferedReader per leggere ed elaborare i record se si tratta di un file di grandi dimensioni come indicato.

BufferedReader br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
   // process the line. and write into your output file and close the file.
   }
br.close();

Altri suggerimenti

Personalmente: uso BufferedReader a posto dello scanner. Ha anche un metodo di readline () comodo e non ho mai avuto problemi di prestazione con esso. L'unica cosa è che dovresti controllare manualmente se una lettura di riga è quella che si desidera elaborare, ma di solito è semplice come applicare i metodi della classe di stringhe.

Non è una risposta alla tua vera domanda, ma lo considero un'alternativa decente da usare.

Prova qualcosa del genere (ma più bello):

Scanner sc = new Scanner(new BufferedReader(new FileReader(file)));

Questo decora il tutto con un bufferedReader, il che significa che non tutto il contenuto del file verrà caricato in memoria contemporaneamente. È possibile utilizzare lo scanner allo stesso modo.

Prova a usare un bufferedReader. Uso diretto dello scanner con file o flussi di file grezzi Woudl caricare i dati in memoria e non farli scaricare su GC. L'approccio delle scommesse è utilizzare BufferedReader e leggere una riga alla volta e eseguire controlli di stringa manuale e dividere. Se fatto correttamente in questo modo puoi dare al GC sufficiente opportunità per recuperare la memoria quando necessario

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top