# RandomAccessFile - Bytes vom Anfang der Datei löschen



## AndreasMenzel (13. Jun 2006)

Hallo,
icxh suche eine Methode, mit der ich eine fest definierte Anzahl von Bytes (z.B. 80 bytes) vom Anfang einer Datei löschen kann. Diese wurden vorher hineingeschrieben und sollen nun wieder gelöscht werden.
Es sollen alle Bytes von 0-80 gelöscht werden. Gibt es hierzu eine Möglichkeit für RandomAccessFile?
Vielen Dank.
Andreas.


----------



## Guest (13. Jun 2006)

Nicht direkt bzw. am Anfang der Datei nicht.
Es geht nur durch's Umkopieren.
z.B.
	
	
	
	





```
RandomAccessFile file = new RandomAccessFile("datei.dat", "rw");
// Alle Bytes ab Position 80 an den Anfang der Datei umkopieren
file.getChannel().transferTo(80, file.length(), file.getChannel()); 
// Datei am Ende um 80 Byte verkürzen
file.setLength(file.length()-80);
```
Das dürfte ziemlich schnell sein.
*Achtung. Es ist nicht getestet!*
Prüfe, ob es so funktioniert. Fehler könnten auftauchen, wenn der Lesepuffer
größer ist, als der Schreibpuffer. Also, wenn der Lesezeiger den Schreibzeiger
überholt. Sollte aber nicht der Fall sein. 

Gruß,
semi


----------



## thE_29 (14. Jun 2006)

Aber genau so mache ich meinen weg auch 

Nur ich öffne 2 RandomAccessFile Objekte (einmal nur r und einmal rw) und lese es auch raus und verkürze die Datei!


----------



## AndreasMenzel (14. Jun 2006)

Vielen Dank für die bisherigen Antworten.
Ist denn die Methode mit 2 RandomAccessFile Objekten schneller? Was bringt Sie für Vorteile. Ich arbeit meist mit sehr großen Datei teilweise im zweistelligen GB Bereich. Wie verhält sich das mit dem umkopieren. Dauert das dann nicht ewig? Gibt es vielleicht noch eine andere Art Bytes an den Anfang einer Datei zu schreiben (Header) und nach späterem Auslesen diese wieder zu löschen? Vielen Dank. Andreas.


----------



## thE_29 (14. Jun 2006)

Unter Java gibts das nicht, mit C geht das ...


Ich habs mit 2 gemacht und auch mit byte buffer und mit changles so wie oben beschrieben!

Ich arbeite nur mit Files um die 500 MB und da gehts ruckzuck unter Linux..

Habe es ja nur mit 2 gemacht, weil ich net sicher war ob es mit 1 Objekt auch geht...

Probiers halt mal aus


----------



## AndreasMenzel (14. Jun 2006)

Also mit dem Löschen funktioniert das jetzt. Ich habe mal ein paar Byte im Editor an den Anfang geschrieben und mit der oben stehenden Lösung wieder gelöscht und das hat geklappt. Nun aber ein neues Problem )-:
Beim schreiben per RandomAccessFile in die Datei überschreibt mir die Funktion writeBytes den eigentlichen Inhalt der Datei. Ziel ist es 80byte Informationen an den Anfang einer Datei zu schreiben. Wie kann ich dies realisieren, ohne das der eigentliche Inhalt überschrieben wird. Es müsste also zunächst die Datei vergrößert werden, der Inhalt nach hinten kopiert und der Header an den Anfang geschrieben werden. Ideen??? Vielen Dank. Andreas.


----------



## thE_29 (14. Jun 2006)

Probier mal FileOutputstream da kann man append sagen (im Konstruktor)

Und dort den channel holen oder dgl (oder positionieren am Anfang) und dann am Anfang rein oder alles nach hinten verschieben..


----------



## AndreasMenzel (14. Jun 2006)

Habs grade so probiert:

FileOutputStream file = new FileOutputStream(filename,false);
DataOutputStream out   = new DataOutputStream(file);
out.writeBytes(Beschreibung);
out.flush();
out.close();

Wenn ich append auf true setze wird alles ans Ende der Datei geschrieben und wenn ich es auf false setze, dann steht nur der String"Beschreibung" in der alten Datei. Also noch keine Lösung. Bin für jede Hilfe dankbar.


----------



## thE_29 (14. Jun 2006)

Hier der Supercode von mir dazu :bae:


```
public void storeAtBegin(String text) throws Exception
  {
    RandomAccessFile filow = new RandomAccessFile("C:\\test.txt","rw");
    BufferedReader br = new BufferedReader(
      new InputStreamReader(
        new FileInputStream("C:\\test.txt")));
    byte _text[] = text.getBytes();
    filow.skipBytes(_text.length);
    String lines[] = new String[2];
    while ( ( lines[0] = br.readLine() ) != null)
    {
      if(lines[1] != null)
      {
        StringBuffer strBuf = new StringBuffer(lines[1]);
        strBuf.append("\n"); //unter Linux isses glaube ich \n\r
        filow.write(strBuf.toString().getBytes());
      }
      lines[1] = lines[0];
    }
    if(lines[1] != null)
      filow.write(lines[1].getBytes());
    filow.seek(0); //auf anfang
    filow.write(_text); //jetzt noch den Text fürn Anfang wennst Zeilenumbruch willst, musst den mitübergeben
    br.close();
    filow.close();
  }
```


Achja, das ganze muss natürlich net zeilenweise gelesen werden, könntest du mit byte[] arrays genauso machen...

Zb byte buf[][] = new byte[2][1024]

Und dann via InputStreamReader mit read hinein und auch immer 2 Blöcke lesen...

Glaube mit byte isses schneller!


----------



## AndreasMenzel (14. Jun 2006)

Vielen Dank für den Code. Wenn ich diesen allerdings ausführe, läuft das Programm ohne Fehler allerdings auch ohne Ende. Die Datei wird immer größer und der Inhalt ist völlig durcheinander. Haut also noch nicht ganz hin. Gibt es denn nicht ne einfacherer Variante. Bin nicht so der Java Gott und versteh auch nicht alles was da in dem Code gemacht wird. Vielleicht noch jemand nen Tip für mich? Danke. Andreas.


----------



## thE_29 (14. Jun 2006)

Also bei mir klappt das!

Wie groß isn deine Datei?

Und was schreibst du rein?


----------



## AndreasMenzel (14. Jun 2006)

Es ist eine XML Datei mit Größe 99KB und ich schreibe einen 80 byte großen String rein. wenn ich das programm ein paar sekunden laufen lasse, ist die datei schon über 60 MB.


----------



## AndreasMenzel (14. Jun 2006)

vielleicht liegt es an dem string puffer. wie würde die lösung mit byte puffer denn aussehen?


----------



## AndreasMenzel (14. Jun 2006)

Habs nochmal probiert. Das einzige was das Programm macht, ist den Inhalt in einer Endlosschleife immer wieder in die Datei zu schreiben. Der String wird nicht reingeschrieben.


----------



## thE_29 (14. Jun 2006)

Mhm..

Habs jetzt mit ner 126KB großen XML Datei probiert und habe

"Text am Anfang\n" in die Methode übergeben.

Geht ganz normal..

Wie rufst du die Datei auf?


----------



## AndreasMenzel (14. Jun 2006)

try {
storeAtBegin("TextamAnfang\n");
} catch (Exception e) {
e.printStackTrace();
}
dies rufe ich in meiner main auf.
eine test.txt datei mit dem inhalt "hallo" ergab das ergebnis, dass die datei immer größer wurde und tausende male hallo drin stand.


----------



## thE_29 (14. Jun 2006)

kann aber net sein....

weil die schleife abbrechen müsste...

Hast du nen Fehler beim kopieren gemacht??

Oder hast du unendlich leerzeilen am Ende?!


Weil die Schleife liest 1 Zeile ein und speichert diese, liest die nächste ein.  Wenn nur 1 Zeile drinnen steht, müsste er also jetzt aufhören!

Daher, kann das bei 1er Zeile niemals ne endlosloop machen!


----------



## Leroy42 (14. Jun 2006)

thE_29 hat gesagt.:
			
		

> Unter Java gibts das nicht, mit C geht das ...


 :shock: 
Wie bitte, soll denn das mit C möglich sein. C benutzt doch de facto
das was Java unter RandomAccess-File versteht.

Bei den heutigen Dateisystem in _allen üblichen_ Betriebssystemen
kann es nun mal nicht gehen, einfach einen Teil am Anfang einer Datei
zu löschen. Ich glaube, bin mir aber nicht sicher, daß das mal in einem BS
(VMS!?) von IBM möglich war, indem einfach nur der Zeiger auf den Anfang
einer Datei verschoben wurde; aber das geht natürlich nur, wenn das BS
soetwas unterstützt.


----------



## AndreasMenzel (14. Jun 2006)

Also wenn ich nur eine Zeile habe in der test.txt geht es wirklich. Allerdings habe ich es mit zwei anderen Dateien getestet und da war das Ergebniss wieder fehlerhaft. Wenn kein sauberes Zeilenende existiert, funktioniert der Code nicht. Es muss also eine andere Lösung gefunden werden. Das was Leroy42 gesagt hat ist richtig und leuchtet auch ein. Aber durch umkopieren innerhalb der Datei nach weiter hinten und anschliessendes Schreiben an den Dateianfang müsste das doch zu realisieren sein. Oder?


----------



## thE_29 (14. Jun 2006)

Was glaubst du was mein Code eigentlich macht ^^

Das Problem ist, das anscheinend bei dir ein endlosloop erzeugt wird..

Warum auch immer....


----------



## AndreasMenzel (14. Jun 2006)

Ja genau das habe ich doch eben geschrieben. Mit einer 1 Zeilen Textdatei geht das wudnerbar.Aber es muss mit allen Dateien funktionieren. Auch Binärdateien und Zip Archive und und und. Es muss also absolut zuverlässig arbeiten. Und bei drei getesteten Dateien zwei Fehlerhaft ist nunmal nicht ausreichend. Ist ja nicht bös gemeint aber es funktioniert so eben nicht.


----------



## thE_29 (14. Jun 2006)

@Leoroy42: such mal fread, fwrite, fsetpos

Mit den 3 Befehlen kann man das super machen ...

Habe ja niemals gesagt das es Standardmethoden gibt..


----------



## thE_29 (14. Jun 2006)

@Andreas: binär dateien hören aber selten mit zig Leerzeilen auf oder?!


----------



## Leroy42 (14. Jun 2006)

thE_29 hat gesagt.:
			
		

> @Leoroy42: such mal fread, fwrite, fsetpos



Aber auch mit diesen Funktionen muß kopiert werden. Ein einfaches
"Abschneiden" der ersten Bytes geht unter keinem heutigen BS.

Vielleicht habe ich dein Zitat aber auch aus dem Kontext gerissen
und dich falsch verstanden.

Dann sorry!


----------



## thE_29 (14. Jun 2006)

Macht nix 

Kann sein das man es auffasst das es mit 1em Befehl geht 

Geht aber net 


```
public void storeAtBegin2(String text) throws Exception
  {
    FileInputStream in = new FileInputStream("C:\\ad_block.xml");
    RandomAccessFile out = new RandomAccessFile("C:\\ad_block.xml","rw");    
    byte _text[] = text.getBytes();
    out.skipBytes(_text.length);
    byte buf[][] = new byte[2][1024];
    int x[] = new int[2];
    
    while ( ( x[0] = in.read(buf[0],0,1024)) != -1 )
    {
      if(buf[1] != null) //nur wenn es nicht null ist => ab 2ten Durchlauf
        out.write(buf[1],0,x[1]);

      x[1] = x[0]; //wieviel bytes geschrieben werden müssen
      System.arraycopy(buf[0],0,buf[1],0,1024); //kopiert es rüber
    }
    if(buf[1] != null)
      out.write(buf[1],0,x[1]);
    out.seek(0); //auf den anfang setzen
    out.write(_text);
    in.close();
    out.close();
  }
```

Probier das mal aus!


----------



## AndreasMenzel (15. Jun 2006)

So. Nun hab ich das Schreiben und das Löschen des Headers mit eurer Hilfe hinbekommen. Vielen Dank. Ich habe das ganze an einem XML File getestet. Das Problem liegt nun darin, dass die Datei vorher und nachher eine unterschiedliche Dateigröße haben. Kann das an dem hin und her kopieren innerhalb der datei liegen? Die Dateigröße war vorher  100.929 Bytes   und danach 102.675 Bytes. Ich habe mir die Datei mit dem Editor angeschaut und der Header wurde ordentlich entfernt. Irgendetwas muss sich innerhalb der Datei verändert haben. Woran kann das liegen? Vielen Dank. Andreas.


----------



## André Uhres (15. Jun 2006)

http://www.prestosoft.com/ps.asp?page=edp_examdiff


----------



## AndreasMenzel (15. Jun 2006)

Danke für den Link und das Programm. Ich habe beide XML Files eingelesen und das Ergebniss war schon etwas überaschend. Es wurde kein Unterschied gefunden. )-; Könnte es eventuell daran liegen, dass ich wenn ich die Original Datei mit dem Editor öffne der Text hintereinander mit Trennzeichen (kleines Viereck) dargestellt wird und wenn ich die veränderte Datei öffne diese schön strukturiert als XML Struktur mit Leerzeilen und so weiter dargestellt wird?


----------



## André Uhres (15. Jun 2006)

In ExamDiff kannst du unter View|Options einstellen ob er Leerzeilen usw. ignorieren soll.
Vielleicht hilft das weiter.


----------



## AndreasMenzel (16. Jun 2006)

Also ich habe die Einstellungen unter ExamDiff vorgenommen wie du vorgeschlagen hast. Das Ergebnis war, dass die File identisch sind und keine Unterschiede im Inhalt aufweisen. Allerdings weißen Sie Unterschiede in Ihrer Größe und Ihrer CHecksumme auf. Und das darf nicht sein. Gibt es nicht eine Andere Methode das Propblem zu lösen? Es sollen eine gewisse Anzahl von Bytes an den Anfang eine X beliebigen Datei geschrieben werden. Diese sollen später ausgelesen und wieder gelöscht werden, so dass die Datei wieder der Originaldatei entspricht. Vielen Dank. Andreas.


----------



## AndreasMenzel (16. Jun 2006)

Hab mir die beiden Dateien nochmal mit Beyond Compare angeschaut und einen Unterschied in der Zeilentrennung gefunden:
Hier ein Screenshot:
http://web100.xps9.microserver.de/xml.JPG

Die Kopieroperation hat also das Zeilenende verändert. Wie kann ich dies umgehen?


----------



## Leroy42 (16. Jun 2006)

AndreasMenzel hat gesagt.:
			
		

> ...der Text hintereinander mit Trennzeichen (kleines Viereck) dargestellt wird...



Das hört sich doch stark noch Zeilenseparator-Problem an  :wink: 

Wenn nur das Unix'sche LF (ASCII-10) statt des WinDoof'schen CR LF (ASCII-13 ASCII-10)
in einer Datei stehen, erkennen dies einfache Editoren (Notepad, ...) nicht als Zeilenende an.

Schick doch am besten die vollständige Source der Routine, die du *jetzt* benutzst


----------



## AndreasMenzel (16. Jun 2006)

```
public void writeBytes(String Dateiname,String Beschreibung) throws Exception{

	  			RandomAccessFile ausgabedatei = null;
                
//==========================================================================	  			
	            try {
	                Beschreibung = Beschreibung + "\n";
	            	ausgabedatei = new RandomAccessFile(Dateiname, "rw");
	            	String Headerlaenge = Beschreibung.substring(0,4);
	            	int headerlength = new java.lang.Integer( Headerlaenge );
	            	long filelength = ausgabedatei.length();
	                ausgabedatei.seek(0);
	                if (ausgabedatei != null) {
	                	System.out.println("ByteWriter schreibt die Beschreibung in die Datei: " + Dateiname + "\n");
	           	     FileInputStream in = new FileInputStream(Dateiname); 
	        	     byte _text[] = Beschreibung.getBytes(); 
	        	     ausgabedatei.skipBytes(_text.length); 
	        	     byte buf[][] = new byte[2][1024]; 
	        	     int x[] = new int[2]; 
	        	     
	        	     while ( ( x[0] = in.read(buf[0],0,1024)) != -1 ) 
	        	     { 
	        	       if(buf[1] != null) //nur wenn es nicht null ist => ab 2ten Durchlauf 
	        	    	   ausgabedatei.write(buf[1],0,x[1]); 

	        	       x[1] = x[0]; //wieviel bytes geschrieben werden müssen 
	        	       System.arraycopy(buf[0],0,buf[1],0,1024); //kopiert es rüber 
	        	     } 
	        	     if(buf[1] != null) 
	        	    	 ausgabedatei.write(buf[1],0,x[1]); 
	        	     ausgabedatei.seek(0); //auf den anfang setzen 
	        	     ausgabedatei.write(_text); 
	        	     System.out.println("Die Datei: " + Dateiname + " hat " + ausgabedatei.length() + " Bytes...");
	        	     in.close(); 
	        	     ausgabedatei.close(); 
	                }
	            }
	            catch(Exception e) {
	                e.printStackTrace();
	            }
                
//==========================================================================
                    if (ausgabedatei != null) {
                        System.out.println("Die Datei: " + Dateiname + " hat nun " + ausgabedatei.length() + " Bytes..." + "\n" );
                        System.out.println("=======" );
                        ausgabedatei.close();
                    }
//==========================================================================	   }







public void deleteBytes(String Dateiname) throws Exception{

			RandomAccessFile ausgabedatei = null;
			String Beschreibung = null;
  			try {
                ausgabedatei = new RandomAccessFile(Dateiname, "rw");
                File filename = new File(Dateiname);
            	Beschreibung = ausgabedatei.readLine();
            	String Headerlaenge = Beschreibung.substring(0,4);
            	int headerlength = new java.lang.Integer( Headerlaenge );  
            	String Headertyp = Beschreibung.substring(4,9);
            	int headertyp = new java.lang.Integer( Headertyp ); 

            	System.out.println("ByteDeleter löscht den " + headerlength + " byte " + "Header der Datei: " + filename.getName() + "\n" );
                System.out.println("Die Datei: " + filename.getName() + " hat vor dem Löschen: " + ausgabedatei.length() + " Bytes...");

                ausgabedatei.seek(0);
//              Alle Bytes ab Position headerlength+1 (da Umbruch) an den Anfang der Datei umkopieren 
                ausgabedatei.getChannel().transferTo(headerlength+1, ausgabedatei.length(), ausgabedatei.getChannel()); 
//              Datei am Ende um 80 Byte verkürzen 
                ausgabedatei.setLength(ausgabedatei.length()-headerlength-1);

                System.out.println("Die Datei: " + filename.getName() + " hat nach dem Löschen: " + ausgabedatei.length() + " Bytes..." + "\n");
                ausgabedatei.close();
            }
            catch(Exception e) {
                e.printStackTrace();
            }
}
```


----------

