Bereiche innerhalb einer Datei löschen / verschieben / kopieren / überschreiben

Thomas Darimont

Erfahrenes Mitglied
Hallo!

Schau mal hier:
Code:
     /**
       * 
       */
      package de.tutorials;
      
      import java.io.File;
      import java.io.RandomAccessFile;
      
      /**
       * @author Tom
       * 
       */
      public class FileShrinkExample {
      
      	/**
      	 * @param args
      	 */
      	public static void main(String[] args) throws Exception {
      		File file = new File("c:/FileShrinkExample.dat");
      		if (file.exists()) {
      			file.delete();
      		}
      
      		RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
      
      		createDummyData(randomAccessFile);
      		// Unser File hat jetzt (binär) folgenden Aufbau:
      		// 2147483647 (10000 mal) Schreibvorgang A
      		// 2147483647
      		// 2147483647
      		// ...
      		// 2147483647
      		// -2147483648 (10000 mal) Schreibvorgang B
      		// -2147483648
      		// -2147483648
      		// ...
      		// -2147483648
      		// 2147483647 (10000 mal) Schreibvorgang C
      		// 2147483647
      		// 2147483647
      		// ...
      		// 2147483647
      
      		// Ein int hat in Java 4 bytes deshalb hat unser File eine Grösse von:
      		// 4 * 10000 + 4* 10000 + 4* 10000 = 120000 bytes
      		System.out.println(file.length());
      
      		// Hier wollen wir nun den Inhalt ab dem Offset:
      		// Schreibvorgang A | Schreibvorgang B -> Beginn Schreibvorgang C
      		// 4 * (10000) + 4 * 10000 = 4 * 20000 -> 80000
      
 		// Der wir wollen nun (Blockweise, jeweils 16384 bytes )den Inhalt von Schreibvorgang C komplett an die
      		// start Position von Schreibvorgang B verschieben. 
      		// Dazu besorgen wir uns den Offset des starts von
      		// Schreibvorgang B 
      		// -> Offset des Endes des Schreibvorgangs A -> 10000 * 4
      
      
      		// Die Länge des Blocks den wir verschieben wollen ist 10000 bytes
      		moveContent(randomAccessFile, 20000 * 4, 10000 * 4, 4 * 10000);
      		// Durch das verschieben haben wir den von Schreibvorgang B erzeugten
      		// Inhalt
      		// überschrieben.
      		// zusätzlich haben wir zum Schluss die Datei Groesse um den
      		// entsprechenden Betrag reduziert.
      
      		// Die neue Dateigröesse beträgt nun:
      		// Schreibvorgang A + Schreibvorgang C
      		// 4 * 10000 + 4 * 10000 = 80000 bytes
      		System.out.println(file.length());
      
      		// Unsere Datei enthält nun (binär) nur noch die Werte von
      		// Integer.MAX_VALUE.
      
      	}
      
      	private static void moveContent(RandomAccessFile randomAccessFile,
 			long sourcePosition, long destionationPosition, long lengthInBytes)
      			throws Exception {
      		byte[] buffer = new byte[16384];
      		int currentByteCount = 0;
      		int bytesRead = 0;
      		int bytesWritten = 0;
      
      		long currentSourcePosition = sourcePosition;
      		long currentDestinationPosition = destionationPosition;
      
      		randomAccessFile.seek(currentSourcePosition);
      
      		
      		//bewegen wir gerade einen kompletten Block der bis zum Dateiende geht?
 		boolean movedCompleteBlockFromEnd = (currentDestinationPosition + lengthInBytes) == sourcePosition;
      
      		do {
      			randomAccessFile.seek(currentSourcePosition);
      			currentByteCount = randomAccessFile.read(buffer);
      			bytesRead += currentByteCount;
      			if (bytesRead > lengthInBytes) {
 		 	currentByteCount = ((int) lengthInBytes) - bytesWritten;
      			}
      			bytesWritten += currentByteCount;
      			randomAccessFile.seek(currentDestinationPosition);
 			randomAccessFile.write(buffer, 0, currentByteCount);
      			currentSourcePosition += currentByteCount;
      			currentDestinationPosition += currentByteCount;
      			randomAccessFile.seek(currentSourcePosition);
      		} while (bytesWritten < lengthInBytes);
      
      		// Der zu verschiebende Bereich hat sich bis zum Dateiende erstreckt...
      		// Datei kleiner machen.
      		if (movedCompleteBlockFromEnd) {
  			randomAccessFile.setLength(currentDestinationPosition);
      		}
      
      	}
      
   	private static void createDummyData(RandomAccessFile randomAccessFile)
      			throws Exception {
      
      		// Schreibvorgang A
      		for (int i = 0; i < 10000; i++) {
      			randomAccessFile.writeInt(Integer.MAX_VALUE);
      		}
      
      		// Schreibvorgang B
      		for (int i = 0; i < 10000; i++) {
      			randomAccessFile.writeInt(Integer.MIN_VALUE);
      		}
      
      		// Schreibvorgang C
      		for (int i = 0; i < 10000; i++) {
      			randomAccessFile.writeInt(Integer.MAX_VALUE);
      		}
      
      		randomAccessFile.getFD().sync();
      	}
      }

Dieses Beispiel verdeutlicht, dass man bei Dateiinternen Manipulationen auf einige Dinge achten muss.
Beispiel:
Wird ein kompletter Block von hinten nach vorne zurück verschoben? -> Datei kleiner manchen.
Wird ein Block mitten in der Datei verschoben? -> Wie sollen die leeren Stellen füllt werden?
Wird ein Block von vorne nach hinten verschoben? -> Wie sollen die leeren Stellen füllt werden?
...
etc.

Gruss Tom
 
Zurück