Lesen Sie große Dateien in Java

Ich brauche den Rat von jemandem, der Java sehr gut kennt und die Gedächtnisprobleme. Ich habe eine große Datei (etwa 1,5 GB) und ich muss diese Datei in viele (100 kleine Dateien zum Beispiel) kleinere Dateien schneiden.

Ich weiß allgemein, wie man es macht (mit einem BufferedReader ), aber ich würde gerne wissen, ob Sie irgendwelche Ratschläge bezüglich des Gedächtnisses oder Tipps haben, wie man es schneller macht.

Meine Datei enthält Text, ist nicht binär und ich habe etwa 20 Zeichen pro Zeile.

Erstens, wenn Ihre Datei Binärdaten enthält, wäre die Verwendung von BufferedReader ein großer Fehler (weil Sie die Daten in String konvertieren würden, was unnötig ist und die Daten leicht beschädigen könnte); Sie sollten stattdessen einen BufferedInputStream verwenden. Wenn es sich um Textdaten handelt und Sie diese entlang von Zeilenumbrüchen teilen müssen, ist die Verwendung von BufferedReader OK (vorausgesetzt, die Datei enthält Zeilen mit einer sinnvollen Länge).

Was Speicher betrifft, sollte es kein Problem geben, wenn Sie einen anständig großen Puffer verwenden (ich würde mindestens 1 MB verwenden, um sicherzustellen, dass die HD hauptsächlich sequenzielles Lesen und Schreiben ausführt).

Wenn sich die Geschwindigkeit als Problem herausstellt, können Sie sich die java.nio Pakete java.nio – diese sind angeblich schneller als java.io ,

Um Speicher zu sparen, speichern / duplizieren Sie die Daten nicht unnötig im Speicher (dh ordnen Sie sie nicht Variablen außerhalb der Schleife zu). Verarbeiten Sie die Ausgabe sofort , sobald die Eingabe eintrifft.

Es ist wirklich egal, ob Sie BufferedReader oder nicht. Es wird nicht viel mehr Speicher kosten, wie einige implizit zu suggerieren scheinen. Es wird höchstens ein paar Prozent von der Performance abschneiden. Das Gleiche gilt für die Verwendung von NIO. Es verbessert nur die Skalierbarkeit, nicht die Speicherbelegung. Es wird nur interessant, wenn Hunderte von Threads in derselben Datei ausgeführt werden.

Einfach die Datei durchlaufen, jede Zeile beim Einlesen sofort in eine andere Datei schreiben, die Zeilen zählen und 100 erreichen, dann zur nächsten Datei wechseln, und so weiter.

Kickoff-Beispiel:

 String encoding = "UTF-8"; int maxlines = 100; BufferedReader reader = null; BufferedWriter writer = null; try { reader = new BufferedReader(new InputStreamReader(new FileInputStream("/bigfile.txt"), encoding)); int count = 0; for (String line; (line = reader.readLine()) != null;) { if (count++ % maxlines == 0) { close(writer); writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("/smallfile" + (count / maxlines) + ".txt"), encoding)); } writer.write(line); writer.newLine(); } } finally { close(writer); close(reader); } 

Sie können über FileChannel s Verwendung von Memory-Mapped-Dateien in Betracht ziehen .

Im Allgemeinen viel schneller für große Dateien. Es gibt Performance-Kompromisse, die es langsamer machen könnten , so YMMV.

Zugehörige Antwort: Java NIO FileChannel versus FileOutputstream performance / Nützlichkeit

Dies ist ein sehr guter Artikel: http://java.sun.com/developer/technicalArticles/Programming/PerfTuning/

Zusammenfassend sollten Sie für eine hervorragende performance Folgendes tun:

  1. Vermeiden Sie den Zugriff auf die Festplatte.
  2. Vermeiden Sie den Zugriff auf das zugrunde liegende Betriebssystem.
  3. Vermeiden Sie Methodenaufrufe.
  4. Vermeiden Sie die individuelle Verarbeitung von Bytes und Zeichen.

Um beispielsweise den Zugriff auf die Festplatte zu reduzieren, können Sie einen großen Puffer verwenden. Der Artikel beschreibt verschiedene Ansätze.

Muss es in Java gemacht werden? Dh muss es plattformunabhängig sein? Wenn nicht, würde ich vorschlagen, den Split -Befehl in * nix zu verwenden. Wenn Sie wirklich wollten, könnten Sie diesen Befehl über Ihr Java-Programm ausführen. Während ich nicht getestet habe, stelle ich mir vor, dass es schneller läuft als jede andere Java IO-Implementierung, die Sie entwickeln könnten.

Sie können java.nio verwenden, das schneller als der klassische Eingabe- / Ausgabestream ist:

http://java.sun.com/javase/6/docs/technotes/guides/io/index.html

Ja. Ich denke auch, dass die Verwendung von read () mit Argumenten wie read (Char [], int init, int end) eine bessere Möglichkeit ist, eine so große Datei zu lesen (zB: read (buffer, 0, buffer.length))

Und ich habe auch das Problem der fehlenden Werte der Verwendung des BufferedReader anstelle von BufferedInputStreamReader für einen binären Dateneingangsstrom erfahren. Daher ist die Verwendung des BufferedInputStreamReader in diesem Fall viel besser.

Verwenden Sie nicht lesen ohne Argumente. Es ist sehr langsam. Lesen Sie besser, um es zu puffern und schnell in die Datei zu verschieben.

Verwenden Sie bufferedInputStream, da es das binäre Lesen unterstützt.

Und es ist alles.

Wenn Sie nicht versehentlich die gesamte Eingabedatei eingelesen haben, anstatt sie Zeile für Zeile zu lesen, ist Ihre primäre Begrenzung die Geschwindigkeit der Festplatte. Sie können versuchen, mit einer Datei zu beginnen, die 100 Zeilen enthält, und sie in 100 verschiedene Dateien schreiben, die jeweils eine Zeile enthalten, und den auslösenden Mechanismus auf die Anzahl der Zeilen anwenden, die in die aktuelle Datei geschrieben werden. Dieses Programm wird leicht auf Ihre Situation skalierbar sein.

 package all.is.well; import java.io.IOException; import java.io.RandomAccessFile; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import junit.framework.TestCase; /** * @author Naresh Bhabat * Following implementation helps to deal with extra large files in java. This program is tested for dealing with 2GB input file. There are some points where extra logic can be added in future. Pleasenote: if we want to deal with binary input file, then instead of reading line,we need to read bytes from read file object. It uses random access file,which is almost like streaming API. * **************************************** Notes regarding executor framework and its readings. Please note :ExecutorService executor = Executors.newFixedThreadPool(10); * for 10 threads:Total time required for reading and writing the text in * :seconds 349.317 * * For 100:Total time required for reading the text and writing : seconds 464.042 * * For 1000 : Total time required for reading and writing text :466.538 * For 10000 Total time required for reading and writing in seconds 479.701 * * */ public class DealWithHugeRecordsinFile extends TestCase { static final String FILEPATH = "C:\\springbatch\\bigfile1.txt.txt"; static final String FILEPATH_WRITE = "C:\\springbatch\\writinghere.txt"; static volatile RandomAccessFile fileToWrite; static volatile RandomAccessFile file; static volatile String fileContentsIter; static volatile int position = 0; public static void main(String[] args) throws IOException, InterruptedException { long currentTimeMillis = System.currentTimeMillis(); try { fileToWrite = new RandomAccessFile(FILEPATH_WRITE, "rw");//for random write,independent of thread obstacles file = new RandomAccessFile(FILEPATH, "r");//for random read,independent of thread obstacles seriouslyReadProcessAndWriteAsynch(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } Thread currentThread = Thread.currentThread(); System.out.println(currentThread.getName()); long currentTimeMillis2 = System.currentTimeMillis(); double time_seconds = (currentTimeMillis2 - currentTimeMillis) / 1000.0; System.out.println("Total time required for reading the text in seconds " + time_seconds); } /** * @throws IOException * Something asynchronously serious */ public static void seriouslyReadProcessAndWriteAsynch() throws IOException { ExecutorService executor = Executors.newFixedThreadPool(10);//pls see for explanation in comments section of the class while (true) { String readLine = file.readLine(); if (readLine == null) { break; } Runnable genuineWorker = new Runnable() { @Override public void run() { // do hard processing here in this thread,i have consumed // some time and ignore some exception in write method. writeToFile(FILEPATH_WRITE, readLine); // System.out.println(" :" + // Thread.currentThread().getName()); } }; executor.execute(genuineWorker); } executor.shutdown(); while (!executor.isTerminated()) { } System.out.println("Finished all threads"); file.close(); fileToWrite.close(); } /** * @param filePath * @param data * @param position */ private static void writeToFile(String filePath, String data) { try { // fileToWrite.seek(position); data = "\n" + data; if (!data.contains("Randomization")) { return; } System.out.println("Let us do something time consuming to make this thread busy"+(position++) + " :" + data); System.out.println("Lets consume through this loop"); int i=1000; while(i>0){ i--; } fileToWrite.write(data.getBytes()); throw new Exception(); } catch (Exception exception) { System.out.println("exception was thrown but still we are able to proceeed further" + " \n This can be used for marking failure of the records"); //exception.printStackTrace(); } } }