Thomas Darimont
Erfahrenes Mitglied
Hallo!
Schau mal hier:
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
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