Hi,
ich möchte Dateien miteinander vergleichen und überprüfen, ob es sich hierbei um die selben Daten handelt. Eine Datei exakt mit einer anderen zu vergleichen ist nicht schwer (byte-weise lesen und vergleichen). Komplexer wird es allerdings, wenn man eine gewisse Toleranz einbauen möchte, also wenn die Dateien immernoch als identisch angesehen werden soll, auch wenn sie um einen bestimmten grad voneinander abweichen. Hier funktioniert ein Zeichenweiser vergleich natürlich nicht. Sollte nämlich in der einen Datei am Anfang ein byte fehlen, aber ansonsten identisch sein, würde dieser "Algorithmus" die beiden Dateien trotzdem als nicht identisch einstufen. Die einzige Lösung, die mir (bis jetzt) eingefallen ist, wäre das häppchenweise vergleichen der Dateien. Also beide Dateien einlesen, die eine in mehrere Stücke aufteilen und überprüfen ob dieses Stück auch in der anderen Datei vorkommt. Falls ja Position merken und ab dieser Position nach dem nächsten Stück suchen.
Das konnte ich auch schon umsetzen:
(Methode compareGoodwill, goodwillFact = Toleranz in Prozent, bufferSize die Größe der "Stücke")
Jetzt zu meinen Fragen:
1.) Kennt jemand eine bessere Methode (die ich auch halbwegs verstehe)?
2.) Hat jemand Verbesserungsvorschläge für diese Methode (Performance ist erstmal eher unwichtig)?
Das wars auch schon. Danke!
ich möchte Dateien miteinander vergleichen und überprüfen, ob es sich hierbei um die selben Daten handelt. Eine Datei exakt mit einer anderen zu vergleichen ist nicht schwer (byte-weise lesen und vergleichen). Komplexer wird es allerdings, wenn man eine gewisse Toleranz einbauen möchte, also wenn die Dateien immernoch als identisch angesehen werden soll, auch wenn sie um einen bestimmten grad voneinander abweichen. Hier funktioniert ein Zeichenweiser vergleich natürlich nicht. Sollte nämlich in der einen Datei am Anfang ein byte fehlen, aber ansonsten identisch sein, würde dieser "Algorithmus" die beiden Dateien trotzdem als nicht identisch einstufen. Die einzige Lösung, die mir (bis jetzt) eingefallen ist, wäre das häppchenweise vergleichen der Dateien. Also beide Dateien einlesen, die eine in mehrere Stücke aufteilen und überprüfen ob dieses Stück auch in der anderen Datei vorkommt. Falls ja Position merken und ab dieser Position nach dem nächsten Stück suchen.
Das konnte ich auch schon umsetzen:
(Methode compareGoodwill, goodwillFact = Toleranz in Prozent, bufferSize die Größe der "Stücke")
Code:
package tools.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class BinaryCompare {
public boolean compareExactly(File one, File two) throws IOException {
if (one.length()==two.length()) {
FileInputStream fis1 = new FileInputStream(one);
FileInputStream fis2 =new FileInputStream(two);
int temp = 0;
while ((temp = fis1.read()) != -1) {
if (temp != fis2.read()) {
return false;
}
}
return true;
}
return false;
}
public boolean compareGoodwill(File one, File two, int goodwillFact, int bufferSize) throws IOException {
if (one.length() < two.length()) {
String temp = two.getAbsolutePath();
two = new File(one.getAbsolutePath());
one = new File(temp);
}
long diff = one.length() - two.length();
if (diff > one.length() * goodwillFact / 100D) {
System.out.println("Size does matter!");
return false;
}
String[] parts = createParts(readFile(one), bufferSize);
StringBuilder str = new StringBuilder(readFile(two));
int mismatch = 0;
int pos = 0;
int temp = 0;
double maxMismatch = parts.length * goodwillFact / 100D;
for (int i = 0; i < parts.length; i++) {
System.out.println("1: " + System.currentTimeMillis());
temp = str.indexOf(parts[i], pos);
System.out.println("2: " + System.currentTimeMillis());
if (temp != -1) {
if ((temp - pos) / bufferSize + mismatch <= maxMismatch) {
pos = temp + bufferSize;
}
else {
mismatch++;
if (mismatch > maxMismatch) {
System.out.println(mismatch + "/" + maxMismatch);
return false;
}
}
}
else {
mismatch++;
if (mismatch > maxMismatch) {
System.out.println(mismatch + "/" + maxMismatch);
return false;
}
}
}
System.out.println(mismatch + "/" + maxMismatch);
return true;
}
public int[] getOptimizedBufferRange(File file) {
int[] range = new int[2];
range[0] = (int)(file.length() * 0.04D / 100D);
range[1] = (int)(file.length() * 0.14D / 100D);
return range;
}
private String[] createParts(String str, int buffer) {
String[] parts = null;
if (str.length() % buffer == 0) {
parts = new String[str.length() / buffer];
}
else {
parts = new String[str.length() / buffer + 1];
}
for (int i = 0; i < parts.length; i++) {
if (i * buffer + buffer > str.length()) {
parts[i] = str.substring(i * buffer);
}
else {
parts[i] = str.substring(i * buffer, i * buffer + buffer);
}
}
return parts;
}
private String readFile(File file) throws IOException {
StringBuilder build = new StringBuilder();
FileInputStream fis = new FileInputStream(file);
int temp = 0;
while ((temp = fis.read()) != -1) {
build.append((char)temp);
}
return build.toString();
}
public static void main(String[] args) throws IOException {
BinaryCompare fc = new BinaryCompare();
File one = new File("Z:\\BinaryCompareTest\\fahrplan.bmp");
File two = new File("Z:\\BinaryCompareTest\\fahrplan2.bmp");
int proz = 30;
int oneR = fc.getOptimizedBufferRange(one)[0];
int twoR = fc.getOptimizedBufferRange(one)[1];
oneR = (oneR < 5 ? 5 : oneR);
twoR = (twoR < 10 ? 10 : twoR);
System.out.println(fc.compareExactly(one, two));
// System.out.println(fc.compareGoodwill(one, two, proz, 3));
System.out.println(fc.compareGoodwill(one, two, proz, (oneR + twoR) / 2));
System.out.println(fc.compareGoodwill(one, two, proz, oneR));
System.out.println(fc.compareGoodwill(one, two, proz, twoR));
}
}
Jetzt zu meinen Fragen:
1.) Kennt jemand eine bessere Methode (die ich auch halbwegs verstehe)?
2.) Hat jemand Verbesserungsvorschläge für diese Methode (Performance ist erstmal eher unwichtig)?
Das wars auch schon. Danke!