OVH Cloud OVH Cloud

Java et SHA - Haché d'un gros fichier

7 réponses
Avatar
Benoît
Bonjour,
Comment r=E9alis=E9 une empreint en sha, pour un gros fichier coimme un
film par exemple?
En fait, mon programme doit comparer deux fichiers pour voir s'ils sont
identiques...
Cela marche tr=E9s bien avec des petits fichiers, mais un
java.lang.OutOfMemory surient avec des plus gros...

try {
byte[] data =3D readFile(monfichier.getAbsolutePath());
MessageDigest md =3D MessageDigest.getInstance("SHA");
md.update(data);
byte[] digest =3D md.digest();
System.out.println("Hexadecimal: " +
monfichier.getAbsolutePath()+new BigInteger(digest).toString(16));
}catch (Exception e) {
System.out.println(e);
}

.=2E.

private static byte[] readFile(String filename) {
try {
RandomAccessFile raf =3D new RandomAccessFile(filename, "r");
byte[] data =3D new byte[(int)raf.length()];
raf.readFully(data);
raf.close();
System.out.println("He");
return data;
}
catch (FileNotFoundException e) {}
catch (IOException e) {}
return null;
}


Merci pour vos r=E9ponses

7 réponses

Avatar
ekse
Bonjour,
Comment réalisé une empreint en sha, pour un gros fichier coimme un
film par exemple?
En fait, mon programme doit comparer deux fichiers pour voir s'ils sont
identiques...
Cela marche trés bien avec des petits fichiers, mais un
java.lang.OutOfMemory surient avec des plus gros...

try {
byte[] data = readFile(monfichier.getAbsolutePath());
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(data);
byte[] digest = md.digest();
System.out.println("Hexadecimal: " +
monfichier.getAbsolutePath()+new BigInteger(digest).toString(16));
}catch (Exception e) {
System.out.println(e);
}

...

private static byte[] readFile(String filename) {
try {
RandomAccessFile raf = new RandomAccessFile(filename, "r");
byte[] data = new byte[(int)raf.length()];
raf.readFully(data);
raf.close();
System.out.println("He");
return data;
}
catch (FileNotFoundException e) {}
catch (IOException e) {}
return null;
}


Merci pour vos réponses



Salut, tu veux instantier un tableau de byte de la taille d'un film,
c'est pas courant et de toute manière déconseillé. MessageDigest permet
d'utiliser plusieurs fois la fonction update pour au final récupérer un
digest, il faut s'en servir. Tu peux par exemple lire 65535 caractères à
la fois, puis les donner à ton MessageDigest, et continuer ainsi sur
tout le fichier :

try {
int buffSize = 65535;
File file = new File("UN_PATH");
RandomAccessFile ras = new RandomAccessFile(file, "r");
byte[] buff = new byte[buffSize];
MessageDigest md = MessageDigest.getInstance("SHA");
while(ras.read(buff) >= 0)
md.update(buff);
byte[] digest = md.digest();
System.out.println("Hexadecimal: " + file.getAbsolutePath()
+ new BigInteger(digest).toString(16));
ras.close();
} catch (Exception e) {
e.printStackTrace();
}

Je met 27 secondes sur un P4 à 2.6 pour 700Mo, 30 avec un FileInputStream

Avatar
TestMan
Bonjour,

Bien vu !

ekse wrote:

Bonjour,
Comment réalisé une empreint en sha, pour un gros fichier coimme un
film par exemple?
En fait, mon programme doit comparer deux fichiers pour voir s'ils sont
identiques...
Cela marche trés bien avec des petits fichiers, mais un
java.lang.OutOfMemory surient avec des plus gros...

try {
byte[] data = readFile(monfichier.getAbsolutePath());
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(data);
byte[] digest = md.digest();
System.out.println("Hexadecimal: " +
monfichier.getAbsolutePath()+new BigInteger(digest).toString(16));
}catch (Exception e) {
System.out.println(e);
}

...

private static byte[] readFile(String filename) {
try {
RandomAccessFile raf = new RandomAccessFile(filename, "r");
byte[] data = new byte[(int)raf.length()];
raf.readFully(data);
raf.close();
System.out.println("He");
return data;
}
catch (FileNotFoundException e) {}
catch (IOException e) {}
return null;
}


Merci pour vos réponses



Salut, tu veux instantier un tableau de byte de la taille d'un film,
c'est pas courant et de toute manière déconseillé. MessageDigest permet
d'utiliser plusieurs fois la fonction update pour au final récupérer un
digest, il faut s'en servir. Tu peux par exemple lire 65535 caractères à
la fois, puis les donner à ton MessageDigest, et continuer ainsi sur
tout le fichier :

try {
int buffSize = 65535;
File file = new File("UN_PATH");
RandomAccessFile ras = new RandomAccessFile(file, "r");
byte[] buff = new byte[buffSize];
MessageDigest md = MessageDigest.getInstance("SHA");
while(ras.read(buff) >= 0)
md.update(buff);
byte[] digest = md.digest();
System.out.println("Hexadecimal: " + file.getAbsolutePath()
+ new BigInteger(digest).toString(16));
ras.close();
} catch (Exception e) {
e.printStackTrace();
}

Je met 27 secondes sur un P4 à 2.6 pour 700Mo, 30 avec un FileInputStream



Et si tu modifies cette version en intégrant un map en utilisant les NIO
tu devrais encore plus booster ...

Voir un exemple dans :
http://developers.sun.com/learning/javaoneonline/2004/corej2se/TS-2460.pdf
Attention, dans cete exemple il n'utilisent pas de buffer "petit" donc
il faut modifier ça et rajouter l'update multiple du digest.

Ah les joies de la crypto :)


A+

TM


Avatar
Pierre Gilquin
peut etre peux tu augmenter la atille de ta VM avec les option -Xm (je sais
pas par coeur) ?

Pierre


"Benoît" a écrit dans le message de news:

Bonjour,
Comment réalisé une empreint en sha, pour un gros fichier coimme un
film par exemple?
En fait, mon programme doit comparer deux fichiers pour voir s'ils sont
identiques...
Cela marche trés bien avec des petits fichiers, mais un
java.lang.OutOfMemory surient avec des plus gros...

try {
byte[] data = readFile(monfichier.getAbsolutePath());
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(data);
byte[] digest = md.digest();
System.out.println("Hexadecimal: " +
monfichier.getAbsolutePath()+new BigInteger(digest).toString(16));
}catch (Exception e) {
System.out.println(e);
}

...

private static byte[] readFile(String filename) {
try {
RandomAccessFile raf = new RandomAccessFile(filename, "r");
byte[] data = new byte[(int)raf.length()];
raf.readFully(data);
raf.close();
System.out.println("He");
return data;
}
catch (FileNotFoundException e) {}
catch (IOException e) {}
return null;
}


Merci pour vos réponses
Avatar
ekse
Bonjour,

Bien vu !

ekse wrote:


Bonjour,
Comment réalisé une empreint en sha, pour un gros fichier coimme un
film par exemple?
En fait, mon programme doit comparer deux fichiers pour voir s'ils sont
identiques...
Cela marche trés bien avec des petits fichiers, mais un
java.lang.OutOfMemory surient avec des plus gros...

try {
byte[] data = readFile(monfichier.getAbsolutePath());
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(data);
byte[] digest = md.digest();
System.out.println("Hexadecimal: " +
monfichier.getAbsolutePath()+new BigInteger(digest).toString(16));
}catch (Exception e) {
System.out.println(e);
}

...

private static byte[] readFile(String filename) {
try {
RandomAccessFile raf = new RandomAccessFile(filename, "r");
byte[] data = new byte[(int)raf.length()];
raf.readFully(data);
raf.close();
System.out.println("He");
return data;
}
catch (FileNotFoundException e) {}
catch (IOException e) {}
return null;
}


Merci pour vos réponses



Salut, tu veux instantier un tableau de byte de la taille d'un film,
c'est pas courant et de toute manière déconseillé. MessageDigest
permet d'utiliser plusieurs fois la fonction update pour au final
récupérer un digest, il faut s'en servir. Tu peux par exemple lire
65535 caractères à la fois, puis les donner à ton MessageDigest, et
continuer ainsi sur tout le fichier :

try {
int buffSize = 65535;
File file = new File("UN_PATH");
RandomAccessFile ras = new RandomAccessFile(file, "r");
byte[] buff = new byte[buffSize];
MessageDigest md = MessageDigest.getInstance("SHA");
while(ras.read(buff) >= 0)
md.update(buff);
byte[] digest = md.digest();
System.out.println("Hexadecimal: " + file.getAbsolutePath()
+ new BigInteger(digest).toString(16));
ras.close();
} catch (Exception e) {
e.printStackTrace();
}

Je met 27 secondes sur un P4 à 2.6 pour 700Mo, 30 avec un FileInputStream



Et si tu modifies cette version en intégrant un map en utilisant les NIO
tu devrais encore plus booster ...

Voir un exemple dans :
http://developers.sun.com/learning/javaoneonline/2004/corej2se/TS-2460.pdf
Attention, dans cete exemple il n'utilisent pas de buffer "petit" donc
il faut modifier ça et rajouter l'update multiple du digest.

Ah les joies de la crypto :)


A+

TM


C'est intéressant, mais j'ai essayé ce code :

RandomAccessFile file = new RandomAccessFile("UN_PATH", "r");
long len = Math.min(file.length(), Integer.MAX_VALUE);
ByteBuffer buffer = file.getChannel().map(READ_ONLY, 0, (int)len);
MessageDigest md = MessageDigest.getInstance("SHA1");
md.update(buffer);
byte[] digest = md.digest();
System.out.println("Hexadecimal: " + new BigInteger(digest).toString(16));

Et c'est effectivement court et nouveau, mais chez moi, ca a mis 5
minutes au moins. Le problème c'est que je suis monté à 270 Mo en
mémoire, comme je n'en ai que 512 ca swappait, bref pas génial.

Je ne sais pas ce que ca donne sur d'autres config, avec le code
précédent je ne dépasse pas les 6 Mo en mémoire et 1min40 ce soir (comme
quoi).

Eric



Avatar
Benoît
Merci pour ta réponse, j'ai essayé et ça fonctionne à peu près
dans les mêmes conditions.
Ta solution me convient tres bien!

Ben
Avatar
TestMan
ekse wrote:
<..>
C'est intéressant, mais j'ai essayé ce code :

RandomAccessFile file = new RandomAccessFile("UN_PATH", "r");
long len = Math.min(file.length(), Integer.MAX_VALUE);
ByteBuffer buffer = file.getChannel().map(READ_ONLY, 0, (int)len);
MessageDigest md = MessageDigest.getInstance("SHA1");
md.update(buffer);
byte[] digest = md.digest();
System.out.println("Hexadecimal: " + new BigInteger(digest).toString(16));

Et c'est effectivement court et nouveau, mais chez moi, ca a mis 5
minutes au moins. Le problème c'est que je suis monté à 270 Mo en
mémoire, comme je n'en ai que 512 ca swappait, bref pas génial.

Je ne sais pas ce que ca donne sur d'autres config, avec le code
précédent je ne dépasse pas les 6 Mo en mémoire et 1min40 ce soir (comme
quoi).

Eric


Bonjour Eric,

Et tu as essayé de mélanger avec un ByteBuffer de 64k au lieu d'allouer
un map de la taille de ton fichier (d'où l'utilisation de 270Mo) ?

Càd, metant à jour le hash à chaque passe du map pour un nouveau segment.

Je serais currieux du résultat, car s'il est bon, on a un gagnant :)
(64k de mémoire et utilisation des NIO)

A+

TM

Avatar
Rémy
"Benoît" a écrit dans le message de news:

Bonjour,
...

En fait, mon programme doit comparer deux fichiers pour voir s'ils sont
identiques...



Remarque en passant, ce n'est pas parce que deux fichiers ont la même
empreinte qu'ils sont identiques.
S'ils ont la même empreinte, alors il faut faire une comparaison "octet par
octet" pour vérifier qu'ils sont identiques.

Par contre s'ils ont des empreintes différentes, ils sont différents.

Pour gagner du temps, on commence en général par vérifier s'ils ont la même
taille ;-)