Java - Splitting grand fichier texte SQL sur délimiter à l'aide du scanner (outofMemoryError)

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

  •  25-08-2022
  •  | 
  •  

Question

J'essaie d'écrire une application qui prendra un très grand fichier texte SQL ~ 60 Go (257 millions de lignes) et divisera chacune des instructions de copie en fichiers texte séparés.

Cependant, le code que j'utilise actuellement provoque une overofMemoryError en raison des lignes dépassant la limite de tampon de scanner. La première déclaration va durer environ 40 millions de lignes.

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");
}

Veuillez fournir une recommandation quant à savoir s'il s'agit de la mauvaise méthode pour effectuer ceci ou des modifications à la méthode existante.

Merci

Était-ce utile?

La solution

Tout d'abord, pourquoi vous créez ou un autre processus crée un fichier de 60 Go! Vous devez peut-être jeter un œil à ce processus pour corriger ce processus pour générer un fichier texte SQL plus petit au lieu de créer un nouveau processus. Cependant, s'il s'agit d'une chose unique que vous devez faire, cela pourrait être bien, mais pour répondre à votre question, j'utiliserais le BufferedReader pour lire et traiter les enregistrements s'il s'agit d'un fichier important comme vous l'avez indiqué.

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

Autres conseils

Moi personnellement: j'utilise BufferedReader à la place du scanner. Il a également une méthode Readline () pratique et je n'ai jamais eu de problèmes de performances avec. La seule chose est que vous devez vérifier manuellement si une lecture de ligne est celle que vous souhaitez traiter, mais c'est généralement aussi simple que d'appliquer les méthodes de classe de chaîne.

Ce n'est pas une réponse à votre question réelle, mais je le considère comme une alternative facile à utiliser.

Essayez quelque chose comme ça (mais plus joli):

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

Cela décore le tout avec un BufferedReader, ce qui signifie que tout le contenu du fichier ne sera pas chargé en mémoire à la fois. Vous pouvez utiliser le scanner de la même manière.

Essayez d'utiliser un BufferedReader. Utilisation directe du scanner avec un fichier ou des flux de fichiers bruts pour charger les données en mémoire et ne pas le éliminer sur GC. L'approche des paris consiste à utiliser BufferedReader et à lire une ligne à la fois et à effectuer des vérifications manuelles de chaîne et une division. Si vous faites correctement de cette façon, vous pouvez donner au GC suffisamment l'occasion de récupérer la mémoire en cas de besoin

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top