我有一个写入方法,可以将 byte[]
写入磁盘。在极少数设备上,我遇到了一些奇怪的问题,即写入操作成功后写入的 file.length() != byte[].length
。
代码与问题
将文件写入磁盘的代码
private static boolean writeByteFile(File file, byte[] byteData) throws IOException {
if (!file.exists()) {
boolean fileCreated = file.createNewFile();
if (!fileCreated) {
return false;
}
}
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write(byteData);
bos.flush();
fos.getFD().sync(); // sync to disk as recommended: http://android-developers.blogspot.com/2010/12/saving-data-safely.html
fos.close();
if (file.length() != byteData.length) {
final byte[] originalMD5Hash = md.digest(byteData);
InputStream is = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(is);
byte[] buffer = new byte[4096];
while(bis.read(buffer) > -1) {
md.update(buffer);
}
is.close();
final byte[] writtenFileMD5Hash = md.digest();
if(!Arrays.equals(originalMD5Hash, writtenFileMD5Hash)) {
String message = String.format(
"After an fsync, the file's length is not equal to the number of bytes we wrote!\npath=%s, expected=%d, actual=%d. >> " +
"Original MD5 Hash: %s, written file MD5 hash: %s",
file.getAbsolutePath(), byteData.length, file.length(),
digestToHex(originalMD5Hash), digestToHex(writtenFileMD5Hash));
throw new GiantWtfException(message);
}
}
return true;
}
我遇到了 if 语句
,我在其中比较了一些设备上的文件长度。
一个示例输出:
fsync 后,文件的长度不等于我们写入的字节数! path=/mnt/sdcard/.folder/filename, expected=233510, actual=229376 >> 原始MD5哈希:f1d298c0484672c52d9c26d04a3a21dc,写入文件MD5哈希:ab30660bd2b476d9551c15b340207a8a
我目前在 5 台设备上看到这个问题,因为我正在慢慢推出代码。一些设备数据:
问题
还有什么我可以做或改进的吗?
更多统计数据和观察结果
当前系统版本
- 2.3.5
- 2.3.6
型号
- N860(LG)
- GT-I9100G(三星)
- GT-S5300(三星)
- GT-S7500(三星)
- LG-VS410PP (LG)
其他统计数据
在一般崩溃分析(来自 Crittercism)中,问题发生时总是有足够的可用磁盘空间。仍然有一些(不是全部)设备在不同的时间点围绕 no free disk space
抛出 IOExceptions。
一如既往,我从未能够在我拥有的任何测试手机上重现该问题。
假设/观察:
通常,当磁盘已满时,我会期望出现 IOException。尽管如此,我捕获的所有异常写入的字节数仍然少于应有的字节数。
有趣的是,实际写入磁盘的所有字节数都是2^15
的倍数。
编辑: 我添加了一个同样失败的 MD5 校验和验证,并稍微简化了示例代码以提高可读性。它在使用不同的 MD5 哈希值时仍然会失败。
最佳答案
philipp,file.length()
是操作系统报告的文件大小。它可能是文件在磁盘上占用的空间或文件中的字节数。
如果返回的数字是磁盘上的大小,则它与保存文件的簇数有关。例如 NTFS 通常使用 4KB 簇。如果在 NTFS 格式的卷上保存一个包含 3 个 ascii 编码字符的文本文档,则文件大小为 3 个字节,磁盘上的文件大小为 4096 字节。在具有 4KB 簇的 NTFS 上,所有文件在磁盘上都是 4096 字节的倍数。参见 http://en.wikipedia.org/wiki/Data_cluster了解更多。
如果返回的数字是以字节为单位的文件长度(来自底层文件系统的元数据)那么你应该与你写入的字节数完全匹配,尽管我不会赌我的生命.
Android 使用 YAFFS 或 EXT4,如果有帮助的话。
我强烈同意 admdrew,使用散列。 MD5 会很好用。 SHA 甚至 CRC 应该可以很好地完成这项任务。当您将字节写入磁盘时,也将流提供给您的哈希算法。写入文件后,将其读回并将其提供给您的散列器。比较结果。 如果要确保数据干净,文件大小不够。
关于java - android 写入磁盘不可靠 - 写入 file.length !=expected.length,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23640387/