这是一个奇怪的事情,已经花了我一整天:
如果将一个简单的字符串(如"1")写入文件并立即读取,则该字符串将获取equals原始字符串.
但是如果String是由某个哈希函数生成的,则获取的String 不再相同.
以下代码打印true false,我想知道场景背后的技巧.
非常感谢你.
public static void main(String[] args) {
try {
String s1 = "1";
File f1 = new File("f1");
write (s1, f1);
System.out.println(read(f1).equals(s1));
MessageDigest md = MessageDigest.getInstance("SHA-512");
String s2 = foo(new File("1.jpg"), md);
File f2 = new File("f2");
write (s2, f2);
System.out.println(read(f2).equals(s2));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// Hash <i>f</i> by <i>md</i>
static String foo (File f, MessageDigest md) throws IOException {
FileInputStream fis = new FileInputStream(f);
DigestInputStream dis = new DigestInputStream(fis, md);
byte[] b = new byte[1024];
while (dis.read(b, 0, 1024) != -1) {
}
md = dis.getMessageDigest();
String s = new String(md.digest());
dis.close();
fis.close();
return s;
}
static void write (String s, File f) throws IOException {
FileWriter fw = new FileWriter(f);
BufferedWriter bw = new BufferedWriter(fw);
bw.write(s);
bw.newLine();
bw.close();
fw.close();
}
static String read (File f) throws IOException {
FileReader fr = new FileReader(f);
BufferedReader bf = new BufferedReader(fr);
String s;
s = bf.readLine();
bf.close();
fr.close();
return s;
}
Run Code Online (Sandbox Code Playgroud)
这是你的第一个问题:
String s = new String(md.digest());
Run Code Online (Sandbox Code Playgroud)
您正在使用平台默认编码创建包含任意二进制数据的字符串.它可能不会是在平台默认的编码有效的文本数据.换句话说,你正在丢失数据.使用base-64对其进行编码 - 这样您将始终拥有一个包含ASCII字符的字符串,并且可以可靠地返回原始二进制数据.
你的第二个普遍问题是使用FileReader和FileWriter.这些总是使用默认的平台编码,这是一个糟糕的 API决定,因为它在我看来几乎没用.您应该几乎总是指定编码 - 我倾向于使用UTF-8.使用FileInputStream/ FileOutputStream和InputStreamReader/ InputStreamWriter用文件读/写文本.(或者使用Guava帮助程序.)