# Strings zu groß um damit zu arbeiten



## Christian76 (18. Jun 2007)

Hallo,

eigentlich passt meine neue Frage noch zu meinen alten Forumseintrag: "FileWriter zu laaaaam". Ich habe gedacht
mein Problem liegt darin das ein sehr großer String zu lange braucht um abgespeichert zu werden. Ja, das stimmt
auch. Aber das liegt nicht nur am FileWriter. Also, meine Strings habe mehr als 1000000 Stellen und die Methode
String.lenght() benötigt für diese Ausgabe einige Minuten. 

Jetzt wollte ich diesen String irgendwie aufteilen und blos weg von der Klasse String. Kennt ihr da eine Möglichkeit?

Gruß
-Christian


----------



## The_S (18. Jun 2007)

StringBuffer, StringBuilder?


----------



## Christian73 (18. Jun 2007)

geht das schon wieder so los? 

Dank dir!


----------



## The_S (18. Jun 2007)

Naja, du wolltest ne alternativ-Klasse zu String ...


----------



## Christian76 (18. Jun 2007)

Der String kommt von der Methode toString() der Klasse BigInteger. 



```
String strWert = bigINT.toString();
```

das dauert so lange, kennst du da einen anderen Weg?


----------



## The_S (18. Jun 2007)

Naja, bei 1 Million stellen ... was musst du denn damit machen? Bzw. für was brauchste so ne rießige Zahl?


----------



## Guest (18. Jun 2007)

schreibe ein Programm um Primzahlen zu testen.


----------



## The_S (18. Jun 2007)

Und die Primzahlen willst du dann in eine Datei schreiben!? Für solche großen Dimensionen sollte es keine arg viel bessere/andere Möglichkeit geben. Evtl. ist ein toByteArray und dann dieses Array schreiben schneller.


----------



## Guest (18. Jun 2007)

ich werde es mal ausprobieren.

Hoffe das Funktioniert so.


----------



## Christian76 (18. Jun 2007)

Habe das gerade überprüft, klappt hervorragend. Kennst du eine Methode, der String ähnlichen Klassen, wie z.B.
BufferedString, der ich dieses Bytearray übergeben kann, und dann irgendwie einen String bekomme?

Ich will nicht die Elemente dieses Byte Arrays mit Array[Nummer] ansprechen.


----------



## The_S (18. Jun 2007)

Dann hast du doch wieder einen String ... ???:L Warum behältst du nicht einfach deinen BigInteger und arbeitest damit weiter? Wozu musst du denn noch die einzelnen Stellen manipulieren?


----------



## Christian76 (18. Jun 2007)

Ok, wie ist mir egal, aber ich muss die Zahl die in dem BigInteger steht irgendwie in eine Datei kriegen. Und beim
Ausführen der Methode:


```
FileWriter.write(BigInteger.toString);
```

geht er in die Knie.


----------



## The_S (18. Jun 2007)

Warum schreibst du nicht einfach das byte-Array?


----------



## Christian76 (18. Jun 2007)

also wenn ich:


```
FileWriter.write(BigInteger.toByteArray());
```

ausführe, steht folgendes in der Datei:

[B@113beb5

???


----------



## The_S (18. Jun 2007)

Bytes schreibt/liest man ja auch nicht mit readern und writern sondern mit Streams!


----------



## Yzebär (18. Jun 2007)

Wie wäre es denn den großen String in mehrere kleine zu zerlegen und diese nacheinander in die Datei zu schreiben, dann kann man nämlich auch noch die Zeilenumbrüche mit einfügen?!


----------



## deleted (19. Jun 2007)

```
import java.io.*;
import java.math.*;

public class Test {
	public static void main(String[] args) throws Throwable {
		
		BigInteger grosseZahl = new BigInteger("109545"); 
		
		byte[] ausgabe = grosseZahl.toByteArray();
		int zahlenLaenge = ausgabe.length;
		FileOutputStream fos = new FileOutputStream ("zahl.txt");
		fos.write(ausgabe);
		fos.close();
		
		byte[] eingabe = new byte[zahlenLaenge];
		FileInputStream fis = new FileInputStream ("zahl.txt");
		fis.read(eingabe);
		
		System.out.println((new BigInteger(eingabe).toString()));
		
	}
}
```

schau dir das mal an, vielleicht hilft es.

Habe es nochmal etwas überarbeitet.
Wie du sehen kannst, ist es kein Problem das Ganze zu speichern und wieder zu lesen.
Du musst nur noch die Länge des ByteArray als Index speichern.
Das kannst zu z.B. in dem Speicherfile vor deiner Zahl erledigen.

Das Ganze ist natürlich nur zur Demonstration.
Das musst du von der Performance noch gründlich überarbeiten


----------



## Guest (20. Jun 2007)

@ R.B.

vielen Dank für deine Hilfe. hat bei mir auch geklappt. Aber ich wollte weg von dem INT. Weil ich druchs INT
begrenzt durch die Summe der Stellen bin. 

@ alle (und besonders an Hobbit  )
Ich habe Folgendes probiert:

Das Speichern klappt wunderbar:


```
FileWriter FW1 = new FileWriter("Wert.txt");

String Wert= new String(new BigInteger("100000000000000000").toByteArray());             
FW1.write(Wert);

FW1.close();
```

nur mit dem Lesen habe ich Probleme. Das Interessante dabei ist: Das meine Ergebnisse in Abhängigkeit
zur Zahlengröße variieren. Bei Kleinen klappt es wunderbar, aber bei Zahlen jenseits der mehrfachen
Millionenstellen klappts nicht mehr. Die eingelesenen Zahlen sind nicht mehr die Gleichen. Ich zeige
jetzt mal meine Codeversuche:

Versuch 1 zum Lesen:


```
String Wert="";
try
{
         File eingabedatei = new File("Wert.txt"); 
         FileReader fr = new FileReader(eingabedatei); 
         BufferedReader br = new BufferedReader(fr); 
         String zeile=br.readLine();
         while ( zeile != null ) 
         { 
                 Wert+= zeile;
                 zeile=br.readLine(); 
         } 
         br.close();  
}
catch (Exception eee){}

byte zahl[] = Wert.getBytes();
BigInteger objBig = new BigInteger(zahl);
```

Versuch 2 zum Lesen:


```
StringBuffer buffer = new StringBuffer();
try
{
        BufferedReader oRead = new BufferedReader(new FileReader("Wert.txt")); 
        
        while (true)
        {
               int gelesenInt = oRead.read();
               if(gelesenInt == -1){break;}
               buffer = buffer.append((char) gelesenInt);
         }
}
catch (Exception eee){}

byte zahl[] = buffer.toString().getBytes();
BigInteger objBig = new BigInteger(zahl);
```

Naja, wie beschrieben, beide funktionieren bis zu einer bestimmten Größe. Hoffe ihr könnt mir da weiterhelfen.

Gruß
-Christian


----------



## The_S (20. Jun 2007)

Nochmal, zum Schreiben/Lesen von bytes solltest du Streams und keine Reader/Writer verwenden!


----------



## deleted (20. Jun 2007)

*edit2*

Ok, hatte das falsch verstanden...
Sorry!

*edit*

Habe den Code nochmal verändert:
Jetz lies das aber bitte durch.
Wenn du es nicht verstehst, frag halt...


```
import java.io.*;
import java.math.*;

public class Test {
	public static void main(String[] args) throws Throwable {
		
		
	
	
		BigInteger grosseZahl = new BigInteger("1");
		BigInteger multi = new BigInteger("10");
		
		for (int i=0; i<10000; i++) {
			grosseZahl = grosseZahl.multiply(multi);
		}
		
		
		byte[] ausgabe = grosseZahl.toByteArray();
		int zahlenLaenge = ausgabe.length; //seperat speichern
		FileOutputStream fos = new FileOutputStream ("zahl");
		fos.write(ausgabe);
		fos.close();
		
		System.out.println("Deine Zahl ist " + (zahlenLaenge) + " Byte groß");
		
		byte[] eingabe = new byte[zahlenLaenge];
		FileInputStream fis = new FileInputStream ("zahl.txt");
		fis.read(eingabe);
		fis.close();
		
		
		System.out.println((new BigInteger(eingabe).toString()));
		
		
		
	}
}
```

Ansonsten nutz lieber Fortran.
Ist in mathematischen Dingen schneller als Java...


----------



## Christian76 (26. Jun 2007)

@ R.B.

Danke für deine Hilfe, mit deinem SC bin ich meinem Problem ein Schritt nächer gekommen. Aber wo wir gerade
beim Thema lesen sind:



> Aber ich wollte weg von dem INT. Weil ich druchs INT
> begrenzt durch die Summe der Stellen bin.




Komischer Weise klappt es wunderbar wenn ich mir die Summe der Stellen ermitteln lassen, aber sobald
ich es anders lesen lassen, geht gar nichts mehr. Ich versuche es gerade so:


                   StringBuffer buffer = new StringBuffer();
                   try
                   {
                       FileInputStream fileStream = new FileInputStream ("Zahl.txt"); 

                       int intzeichen;
                       // ein Zeichen lesen, -1 gibt das Ende der Datei an.
                        while ((intzeichen = fileStream.read()) >=0 ) 
                        {
                            // Das Zeichen ausgeben.
                            buffer.append((char)intzeichen);
                        } 
                        // Datei schließen
                        fileStream.close();

                   }
                   catch (Exception eee){}

ich vermute mal, es liegt daran das ich mir die vorher geschriebenen Bytes als Char konvertiere. Vielleicht 
wäre der Bytebuffer hier richtig, allerdings komme ich mit dem nicht klar.


Gruß
-Christian


@ Admin, wenns nervt, lösch das Topic ruhig.


----------



## Christian76 (26. Jun 2007)

@ R.B.

Danke für deine Hilfe, mit deinem SC bin ich meinem Problem ein Schritt nächer gekommen. Aber wo wir gerade
beim Thema lesen sind:



> Aber ich wollte weg von dem INT. Weil ich druchs INT
> begrenzt durch die Summe der Stellen bin.




Komischer Weise klappt es wunderbar wenn ich mir die Summe der Stellen ermitteln lassen, aber sobald
ich es anders lesen lassen, geht gar nichts mehr. Ich versuche es gerade so:



```
StringBuffer buffer = new StringBuffer();
                   try
                   {
                       FileInputStream fileStream = new FileInputStream ("Zahl.txt"); 
        
                       int intzeichen;
                       // ein Zeichen lesen, -1 gibt das Ende der Datei an.
                        while ((intzeichen = fileStream.read()) >=0 ) 
                        {
                            // Das Zeichen ausgeben.
                            buffer.append((char)intzeichen);
                        } 
                        // Datei schließen
                        fileStream.close();

                   }
                   catch (Exception eee){}
```

ich vermute mal, es liegt daran das ich mir die vorher geschriebenen Bytes als Char konvertiere. Vielleicht 
wäre der Bytebuffer hier richtig, allerdings komme ich mit dem nicht klar.


Gruß
-Christian


@ Admin, wenns nervt, lösch das Topic ruhig.


----------



## The_S (26. Jun 2007)

Äh, wie schon erwähnt, du kannst den byte-output eines BigIntegers nicht so einfach in eine zahl konvertieren. Les die Datei wieder als Byte-Array aus und erzeuge damit dann deinen BigInteger!

btw anstelle auf >= 0 kannste auch einfach auf != -1 prüfen  .


----------



## Christian76 (26. Jun 2007)

jaja, das Thema ist nicht tot zu kriegen.

Bin auch gerade da dran, aber wie kann ich es als Byte Array auslesen?

Habe schon den ByteBuffer benutzt. Aber da muss ich auch ein int als Größendeklaration
übergeben.


----------



## The_S (26. Jun 2007)

Hier einfach so runtergeschrieben:


```
byte[] b = new byte[(int)file.length()];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
bis.read(b, 0, b.length);
```


----------



## Christian76 (26. Jun 2007)

meine Vorgabe ist, ich muss weg von einer INT Begrenzung. Durch INT habe ich eine
limitierte Summe an Stellen in diesem Fall.

Gibt es eine Möglichkeit eines dynamischen Arrays das einfach aus der Datei befüllt wird?


----------



## The_S (26. Jun 2007)

Ich mag zu bezweifeln, dass du Probleme mit der "int-Begrenzung" hast. Vorher sollte dein Speicher voll sein!


----------



## Christian76 (26. Jun 2007)

:lol: jo, das könnte passieren. Ich werde meinen Prof darauf hinweise wenn ich das Problem nicht löse.  :lol:


----------



## The_S (26. Jun 2007)

Ein int bietet dir ein Array von 2147483648 Elementen. Jedes Element besteht aus 8 Bit. Macht eine Zahl der Größenordnung von 2^2147483648 * 8. Sollte reichen  .


----------



## Christian76 (26. Jun 2007)

Ja, das sehe ich eigentlich genauso, aber Vorgabe auf Unendlich viele Stelle ist Tatsache.

Der Computer der irgendwann diese Zahl berechnen kann, wird genug Speicher besitzen.  :lol: 

Ich brauche für eine mit 100000 Stellen schon mehr als 8 Stunden. 

Aber zurück zur Frage, wie machen ich das am Besten? Gibs da was?


----------



## deleted (26. Jun 2007)

@Christian76
An dieser Stelle nur nochmal angemerkt:
Ein String ist für deine Situation in jedem Fall komplett ungeeignet, da Strings vom Compiler speziell behandelt werden.

String a = "test";
String b = "test";
a == b -> true!

Strings werden intern speziell gemanaged und sind für dich nicht absolut kontrollierbar.
Deshalb für mathematische Aufgaben ungeeignet.

Ein Array größer als einen Integer kannst du in Java durchas auch implementieren.
Allerdings nicht als Array sondern z.B. als eine Kette.

Allerdings wenn du wirklich so etwas vorhast, kann ich dir nur nochmal sagen:
Nimm Fortran. Java ist für mathematische Operationen auf Großrechnern nun wirklich nicht die erste Wahl...

btw. welcher Rechner soll eigentlich dein Programm ausführen?
Wenn du uns das verrätst, können wir dir vielleicht bessere Tipps geben...


----------



## Christian76 (26. Jun 2007)

@ R.B.

ich denke mit den Zeichenketten wie du und Hobbit sie mir empfohlen haben, fahre ich nicht schlecht.
Mein Programm kann ja auch Primzahlen in beliebiger Größe überprüfen.

Darüber hinaus ist Java aufgrund der Performance (trozt Hotspot) eh für solche Dinge nicht gerade geeignet.
Fortan wäre durchaus eine Alternative gewesen, aber das Projekt sollte in Java umgesetzt werden.

Zu dem verwendeten Computer, nunja, ich hab hier einen Dualcore mit 2,4 Ghz und der kriegt nur
Zahlen mit ca. 100000 Stellen in ca. 8-10 Stunden hin. Einen praktischen Einsatzt denke ich wird
die Software nie haben. Denke es bleibt wohl ein lustiges Benchmarktool.

Vielen Dank für eure Hilfe.

Gruß
-Christian


----------

