# Parser: Datei auslesen, Datei erstellen - Geschwindigkeit



## redbomber (22. Jan 2009)

Hi zusammen, ich habe mal eine Frage:

Mein Parser liest Daten aus einer Datei und speichert diese in verschiedenen Datentypen:


```
private static LinkedList<String> probeNames = new LinkedList<String>();
private static LinkedList<LinkedList<Double>> allProbeValues= new LinkedList<LinkedList<Double>>();
private static LinkedList<String> chrome = new LinkedList<String>();
private static LinkedList<Double> positions = new LinkedList<Double>();
private static LinkedList<Integer> strand = new LinkedList<Integer>();
```

Danach schreibe ich die ganzen Daten wieder in eine neue Datei (ich brauch einfach eine spezielle Formatierung)


Das File das ich auslese ist sehr gross (Tabulatorgetrennte Werte etwa 120 MB).

Nun das was mich verwundert:
Das Auslesen der Datei geht sogar noch recht schnell (1-2 Minuten vielleicht).
Aber dann die neue Datei erstellen (wieder eine tabulatorgetrennte Datei) ... da warte ich eeewig. Alle paar Minuten schafft der vielleicht 10.000 Zeilen
(sind insgesamt 120.000 Zeilen).

Woran liegt das? Mache ich irgendwo einen Fehler? Gibt es Unterschiede wie man Daten in ein File schreibt?
Oder dauert das schreiben einfach länger?


----------



## SlaterB (22. Jan 2009)

Schreiben soll schon länger dauern als lesen, aber nicht mehr als 5-10 Min,
(ohne Tests mal eben vermutet),

wenn das Parsen aufwendig ist gegenüber Formatieren zur Datei hin (Strings oder Bytes?), dann kann das Schreiben sogar schneller sein als das Lesen

ohne Code kann man über die Gründe nur raten, zwei Tipps:
1. sparsam Strings zusammensetzten, nicht ständig a = b +c
2. BufferedWriter benutzen, nicht jedes Byte einzeln auf die Festplatte schreiben, sondern nur große Blöcke


----------



## Ariol (22. Jan 2009)

Poste doch mal die Methode mit der du schreibst.


----------



## Wildcard (22. Jan 2009)

Große Dateien lassen sich wesentlich effizienter mit java.nio handhaben.


----------



## redbomber (22. Jan 2009)

also das dauert bei mir deutlich länger als 5-10 Minuten mehr.


Hier mal mein Code:


```
public static void createFile(int experimentNumber) {

		System.out.println("Creating file");
		try {
			String nameOfAnalysisFile = "C:\\Data\\datafile.csv";
			File analysisDataFile = new File(nameOfAnalysisFile);
			analysisDataFile.createNewFile();
			BufferedWriter buffWriter = new BufferedWriter(new FileWriter(
					analysisDataFile));

			// Write comment lines
			buffWriter.write("Id"+"\t");
			for(int i = 1; i <= eNumber; i++){
				buffWriter.write(i + "\t");
			}
			buffWriter.write("Info"+"\n");			
			
			
			// write other lines
			int probeCounter = 0;
			for(String probeName: probeNames){
				// write probe name and experiment values
				buffWriter.write(probeName+"\t");
				LinkedList<Double> values = allProbeValues.get(probeCounter);
					
				for(Double val : values){
					buffWriter.write(val + "\t");
				}
				
				// write lociInfo
				String chromeName = chrome.get(probeCounter);
				Double position = positions.get(probeCounter);
				Integer strandName = strand.get(probeCounter);
				if(strandName == 0){
					buffWriter.write("\"species> " + chromeName + ":" + position.intValue() + "-" + (position.intValue() + 25) +":" + "+\"" + "\n");
				} else if(strandName == 1){
					buffWriter.write("\"species> " + chromeName + ":" + position.intValue() + "-" + (position.intValue() + 25) + ":" + "-\"" + "\n");
				} else {
					System.err.println("Error: strand is neither plus nor minus");
				}

				probeCounter++;
			}
			
			buffWriter.close();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
```


----------



## Wildcard (22. Jan 2009)

Wie gesagt: nio ist wesentlich schneller bei großen Daten, das wird also den größten Unterschied machen.
Wenn du aus irgendeinem Grund kein nio verwenden möchtest, dann vermeide zB solche Dinge:


> buffWriter.write(probeName+"\t");


zweimal write ist effizienter als erst zwei String zusammen zu setzen und sie dann zu schreiben


----------



## SlaterB (22. Jan 2009)

bei LinkedList ist es nicht besonders effizient, mit get(index) zuzugreifen,
da muss jedes Mal ganz vorne angefangen und dann die Link-Kette durchlaufen werden,

kann mir vorstellen, dass das bei 120.000 allein schon ne Weile dauert,

such dir testweise einmalig eine feste Menge von Testdaten raus und schreibe die 120.000x hintereinander

für die richtigen Daten verwende dann Iterator,
4 Iterator gleichzeitig zu durchlaufen ist allerdings unschön,

wenn die Daten alle gut zusammenpassen, dann verwende nur EINE LinkedList<MyDataObject>, in MyDataObject sind Name, Double-List usw alles enthalten,
bei nur einer Liste brauchst du dann auch gar keinen Iterator, sondern alternativ eine for-each-Schleife wie du sie derzeit für probeName schon verwendest

---

allein um den Unterschied zu testen, kannst du bei der
> buffWriter.write("Info"+"\n");
Frage auch einfach mal das \n weglassen


----------



## Ebenius (22. Jan 2009)

Zeile 24 ist wahrscheinlich das schlimmste... Wahlfreier Zugriff auf eine LinkedList. Wandele vorher die LinkedList in eine ArrayList um. Dann wirst Du wahrscheinlich den größten Brocken erledigt haben. Darüber hinaus hat Wildcard natürlich auch noch recht.

[ edit ] Slater, wir sollten uns absprechen.  Landei auch noch. :lol:


----------



## Landei (22. Jan 2009)

```
LinkedList<Double> values = allProbeValues.get(probeCounter);
```
Per Index auf LinkedList zuzugreifen ist auch nicht das Wahre, falls selbige etwas größer ist. Teste mal, ob ArrayList da schneller ist, oder nimm Iteratoren.


----------



## Ebenius (22. Jan 2009)

redbomber, hab ich Dich auf das Problem mit der LinkedList nicht schon hier hingewiesen?  :x


----------



## Ariol (22. Jan 2009)

Das sollte schonmal ein paar Punkte in Sachen Geschwindigkeit bringen.

```
public static void createFile(int eNumber) {

      System.out.println("Creating file");
      try {
         String nameOfAnalysisFile = "datafile.csv";
         File analysisDataFile = new File(nameOfAnalysisFile);
         analysisDataFile.createNewFile();
         
         StringBuilder sb = new StringBuilder();
         BufferedWriter buffWriter = new BufferedWriter(new FileWriter(
               analysisDataFile));

         // Write comment lines
         sb.append("Id");
         sb.append("\t");
         for(int i = 1; i <= eNumber; i++){
            sb.append(i);
            sb.append("\t");
         }
         sb.append("Info");
         sb.append("\n");         
         buffWriter.write(sb.toString());
         sb.setLength(0);
         
         // write other lines
         int probeCounter = 0;
         for(String probeName: probeNames){
            // write probe name and experiment values
            buffWriter.write(probeName+"\t");
            LinkedList<Double> values = allProbeValues.get(probeCounter);
               
            for(Double val : values){
               sb.append(val);
               sb.append("\t");
            }
            
            // write lociInfo
            String chromeName = chrome.get(probeCounter);
            Double position = positions.get(probeCounter);
            Integer strandName = strand.get(probeCounter);
            if(strandName == 0){
               sb.append("\"species> ");
               sb.append(chromeName);
               sb.append(":");
               sb.append(position.intValue());
               sb.append("-");
               sb.append(position.intValue() + 25);
               sb.append(":");
               sb.append("+\"");
               sb.append("\n");
            } else if(strandName == 1){
              sb.append("\"species> ");
               sb.append(chromeName);
               sb.append(":");
               sb.append(position.intValue());
               sb.append("-");
               sb.append(position.intValue() + 25);
               sb.append(":");
               sb.append("-\"");
               sb.append("\n");
            } else {
               System.err.println("Error: strand is neither plus nor minus");
            }

            buffWriter.write(sb.toString());
            sb.setLength(0);
            
            probeCounter++;
         }
         
         buffWriter.close();

      } catch (Exception e) {
         e.printStackTrace();
      }
   }
```


----------



## didjitalist (22. Jan 2009)

musst du die datei tatsächlich erst vollständig einlesen?


----------



## Ebenius (22. Jan 2009)

Vor allem: Die LinkedList's entfernen. Der Rest macht vergleichsweise nix aus!


----------



## redbomber (22. Jan 2009)

Sorry Ebenius, 
ja wie so oft hast du mich auch schon darauf hingewiesen 

Ich habe jetzt alle LinkedList, auf denen Indexzugriff stattfinden.
Ebenso vermeide ich das zusammensetzen von Strings
und teste gerade das Ergebnis.

Vielen Dank euch allen.


@ didjitalist

Ne eigentlich kann ich von der Datei eine Zeile einlesen
und dann gleich die Zeile umformatiert in die neue Datei ausgeben... stimmt, da könnte ich mir das ganze Durchlaufen der Listen sparen.
Ich dachte zuerst dass ich alle Daten brauche, da ich in jeder zeile eine Wert berechnen muss, dies brauch ich scheins aber doch nicht.


----------



## redbomber (22. Jan 2009)

wow  :shock: schon fertig, hat gerade mal ne minute gebraucht!


----------



## Ebenius (22. Jan 2009)

Didn't I tell you?


----------



## didjitalist (23. Jan 2009)

zeile für zeile abzuarbeiten wird noch schneller sein. und es kommt mit wesentlich weniger speicher aus.


----------

