0

底部的问题

我正在使用 netty 将文件传输到另一台服务器。由于 WebSocket 协议,我将文件块限制为 1024*64 字节 (64KB)。以下方法是一个本地示例,文件将发生什么:

public static void rechunck(File file1, File file2) {

    FileInputStream is = null;
    FileOutputStream os = null;

    try {

        byte[] buf = new byte[1024*64];

        is = new FileInputStream(file1);
        os = new FileOutputStream(file2);

        while(is.read(buf) > 0) {
            os.write(buf);
        }

    } catch (IOException e) {
        Controller.handleException(Thread.currentThread(), e);
    } finally {

        try {

            if(is != null && os != null) {
                is.close();
                os.close();
            }

        } catch (IOException e) {
            Controller.handleException(Thread.currentThread(), e);
        }

    }

}

该文件由InputStreamByteBuffer 加载并直接写入OutputStream. 在这个过程中文件的内容不能改变。

要获取md5-hashes文件,我编写了以下方法:

public static String checksum(File file) {

    InputStream is = null;

    try {

        is = new FileInputStream(file);
        MessageDigest digest = MessageDigest.getInstance("MD5");
        byte[] buffer = new byte[8192];
        int read = 0;

        while((read = is.read(buffer)) > 0) {
            digest.update(buffer, 0, read);
        }

        return new BigInteger(1, digest.digest()).toString(16);

    } catch(IOException | NoSuchAlgorithmException e) {
        Controller.handleException(Thread.currentThread(), e);
    } finally {

        try {
            is.close();
        } catch(IOException e) {
            Controller.handleException(Thread.currentThread(), e);
        }

    }

    return null;

}

所以:理论上它应该返回相同的哈希值,不是吗?问题是它返回两个不同的哈希值,每次运行都没有区别。文件大小保持不变,内容也一样。当我运行该方法一次时in: file-1out: file-2再次使用in: file-2out: file-3file-2 和 file-3 的哈希值是相同的!这意味着该方法每次都会以相同的方式正确更改文件。

1. 58a4a9fbe349a9e0af172f9cf3e6050a
2. 7b3f343fa1b8c4e1160add4c48322373
3. 7b3f343fa1b8c4e1160add4c48322373

这是一个小测试,比较所有缓冲区是否相等。测试呈阳性。所以没有任何区别。

File file1 = new File("controller/templates/Example.zip");
File file2 = new File("controller/templates2/Example.zip");

try {

    byte[] buf1 = new byte[1024*64];
    byte[] buf2 = new byte[1024*64];

    FileInputStream is1 = new FileInputStream(file1);
    FileInputStream is2 = new FileInputStream(file2);

    boolean run = true;
    while(run) {

        int read1 = is1.read(buf1), read2 = is2.read(buf2);
        String result1 = Arrays.toString(buf1), result2 = Arrays.toString(buf2);
        boolean test = result1.equals(result2);

        System.out.println("1: " + result1);
        System.out.println("2: " + result2);
        System.out.println("--- TEST RESULT: " + test + " ----------------------------------------------------");

        if(!(read1 > 0 && read2 > 0) || !test) run = false;

    }

} catch (IOException e) {
    e.printStackTrace();
}

问题:你能帮我在不改变哈希的情况下分块文件吗?

4

2 回答 2

1
while(is.read(buf) > 0) {
    os.write(buf);
}

带有数组参数的read()方法将返回从流中读取的文件数。当文件的结尾不完全是字节数组长度的倍数时,此返回值将小于字节数组长度,因为您到达了文件结尾。

但是,您的os.write(buf);调用会将整个字节数组写入流,包括文件结束后的剩余字节。这意味着写入的文件最终会变大,因此哈希值发生了变化。

有趣的是,您在更新消息摘要时并没有犯错误:

while((read = is.read(buffer)) > 0) {
    digest.update(buffer, 0, read);
}

当你“重新分块”你的文件时,你只需要做同样的事情。

于 2018-03-31T14:57:52.780 回答
0

您的 rechunk 方法中有一个错误。由于那里有一个固定的缓冲区,因此您的文件被拆分为 ByteArray 部分。但是文件的最后一部分可能比缓冲区小,这就是你在新文件中写入太多字节的原因。这就是为什么您不再拥有相同的校验和的原因。可以像这样修复错误:

public static void rechunck(File file1, File file2) {

    FileInputStream is = null;
    FileOutputStream os = null;

    try {

        byte[] buf = new byte[1024*64];

        is = new FileInputStream(file1);
        os = new FileOutputStream(file2);
        int length;
        while((length = is.read(buf)) > 0) {
            os.write(buf, 0, length);
        }

    } catch (IOException e) {
        Controller.handleException(Thread.currentThread(), e);
    } finally {

        try {

            if(is != null)
                is.close();
            if(os != null)
                os.close();

        } catch (IOException e) {
            Controller.handleException(Thread.currentThread(), e);
        }

    }

}

由于长度变量,write方法知道直到字节数组的字节x,只有文件关闭,那么里面还有旧字节不再属于文件。

于 2018-03-31T15:50:05.863 回答