文件md5散列更改时(对于netty传输)(File md5 hash changes when chunking it (for netty transfer))

底部的问题

我使用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);
        }

    }

}

该文件由InputStream加载到ByteBuffer中,并直接写入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-3运行一次方法时, in: file-2out: 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();
}

问题: 你能帮我在不更改散列的情况下分块文件吗?


Question at the bottom

I'm using netty to transfer a file to another server. I limit my file-chunks to 1024*64 bytes (64KB) because of the WebSocket protocol. The following method is a local example what will happen to the file:

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);
        }

    }

}

The file is loaded by the InputStream into a ByteBuffer and directly written to the OutputStream. The content of the file cannot change while this process.

To get the md5-hashes of the file I've wrote the following method:

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;

}

So: just in theory it should return the same hash, shouldn't it? The problem is that it returns two different hashes that do not differ with every run.. file size stays the same and the content either. When I run the method once for in: file-1, out: file-2 and again with in: file-2 and out: file-3 the hashes of file-2 and file-3 are the same! This means the method will properly change the file every time the same way.

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

Here is a little test that compares all buffers if they are equivalent. Test is positive. So there aren't any differences.

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();
}

Question: Can you help me chunking the file without changing the hash?


原文:https://stackoverflow.com/questions/49588868
2022-10-18 07:10

相关问答

更多

Log4j 配置与使用 java.sql

你这个打印的是error级别的,你把error换成debug再试试

Java ResultSet如何检查是否有任何结果(Java ResultSet how to check if there are any results)

这是正确的,最初ResultSet的游标指向第一行之前,如果第一个调用next()返回false则ResultSet没有数据。 如果您使用此方法,则可能必须立即调用beforeFirst()来重置它,因为它已经将自己定位在第一行之后。 然而,应该注意的是, Seifer的答案是对这个问题的更为优雅的解决方案。 That's correct, initially the ResultSet's cursor is pointing to before the first row, if the fi...

ColdFusion查询到java.sql.ResultSet(ColdFusion Query to java.sql.ResultSet)

coldfusion.sql.QueryTable实现了javax.sql.RowSet,它扩展了java.sql.ResultSet 因此,正如你发现的那样,你不需要做任何事情。 ColdFusion查询已经是Java ResultSet。 coldfusion.sql.QueryTable implements javax.sql.RowSet, which extends java.sql.ResultSet Thus, as you discovered, you don't need t...

ResultSet异常 - 结果集开始之前(ResultSet exception - before start of result set)

基本上您将光标定位在第一行之前,然后请求数据。 您需要将光标移动到第一行。 result.next(); String foundType = result.getString(1); 在if语句或循环中这样做是很常见的。 if(result.next()){ foundType = result.getString(1); } Basically you are positioning the cursor before the first row and then request...

如何格式化java.sql时间戳显示?(How to format a java.sql Timestamp for displaying?)

java.sql.Timestamp扩展java.util.Date 。 你想要这样的东西: String S = new SimpleDateFormat("MM/dd/yyyy").format(myTimestamp); 包括时间: String S = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss").format(myTimestamp); java.sql.Timestamp extends java.util.Date. You can do...

如何处理ResultSet,你知道它只有一个记录(How to process ResultSet you know has only one record in it)

DarkSquirrel42是对的 - 您无法使用?替换select列列表? 参数标记。 相反,您也可以将String.format格式化为例如。 坏: *select ? from INVENTORY_TABLE_NAME where SKU = ? 好: select QUANTITY_IN_STOCK from INVENTORY_TABLE_NAME where SKU = ? DarkSquirrel42 is right -- you can't replace the colum...

java.sql.SQLException:ResultSet已关闭(java.sql.SQLException: ResultSet closed)

你不应该重用一个Statement。 创建新查询时,需要使用新的Statement对象。 替换rs1 = stmt.executeQuery("SELECT ASK FROM '" + title + "' ;"); rs1=c.createStatement().executeQuery("SELECT ASK FROM '" + title + "' ;"); you should not reuse a Statement. When you create a new Query, you ...

JDBC格式ResultSet作为表格字符串?(JDBC format ResultSet as tabular string? [closed])

你需要自己处理ResultSet对象rs 。 while(rs.next()){ String ign = rs.getString("IGN"); // ... get uuid and admin level System.out.println(ign + uuid ...); } 如果您不知道列名称,请使用ResultSet#getMetaData() : ResultSetMetaData rsmd = rs.getMetaData(); int columnCount =...

是否可以直接从Groovy返回java.sql.ResultSet?(Is it possible to directly return the java.sql.ResultSet from Groovy?)

不是真的。 使用Groovy的Sql主要原因之一是自动处理资源(这就是为什么有些方法使用闭包与ResultSet进行交互,但是没有返回它的方法 - 以确保它们被关闭)。 我强烈建议您重新考虑为什么要传递对ResultSet引用(可以保留服务器资源),而不是使用表示这些结果的POJO / POGO。 但是,如果您坚持使用ResultSet ,并且只需要很少的便捷方法,我想一个选项就是将这些方法复制到您的代码库中。 正如您从源代码中看到的那样, Sql是一个比普通旧JDBC更薄的包装器。 但是,就你所...

java:为什么ResultSet不是Serializable?(java: Why ResultSet is not Serializable?)

据我所知,ResultSet不“包含”数据。 如果您调用http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html#next(),ResultSet将从与数据库的基础(JDBC)连接获取数据。 如果ResultSet是序列化并传输到另一台计算机,则这是不可能的。 那里的连接将无法使用。 As far as I know the ResultSet does not "contain" the data. If you call ...

相关文章

更多

收藏的几个国内国外MD5在线解密网站

转自:http://www.cnblogs.com/dyygtfx/archive/2013/06/0 ...

[Netty 1] 初识Netty

1. 简介 最早接触netty是在阅读Zookeeper源码的时候,后来看到Storm的消息传输层也由 ...

Netty基于流的传输处理

​在TCP/IP的基于流的传输中,接收的数据被存储到套接字接收缓冲器中。不幸的是,基于流的传输的缓冲器 ...

Netty环境配置

netty是一个java事件驱动的网络通信框架,也就是一个jar包,只要在项目里引用即可。

Netty开发环境配置

最新版本的Netty 4.x和JDK 1.6及更高版本

Netty源码分析

Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户 ...

storm学习之Netty代替ZMQ

整理自 http://www.csdn.net/article/2014-08-04/2821018/ ...

Netty入门实例-时间服务器

Netty中服务器和客户端之间最大的和唯一的区别是使用了不同的Bootstrap和Channel实现

Netty入门实例-使用POJO代替ByteBuf

使用TIME协议的客户端和服务器示例,让它们使用POJO来代替原来的ByteBuf。

在Twitter,Netty 4 GC开销降为五分之一

原文:http://www.infoq.com/cn/news/2013/11/netty4-twit ...

最新问答

更多

获取MVC 4使用的DisplayMode后缀(Get the DisplayMode Suffix being used by MVC 4)

我用Google搜索了一个解决方案。 “EnumDisplayModeProvider”是我自己设置网站的各种模式的枚举。 public EnumDisplayModeProvider GetDisplayModeId() { foreach (var mode in DisplayModeProvider.Instance.Modes) if (mode.CanHandleContext(HttpContext)) {

如何通过引用返回对象?(How is returning an object by reference possible?)

这相对简单:在类的构造函数中,您可以分配内存,例如使用new 。 如果你制作一个对象的副本,你不是每次都分配新的内存,而是只复制指向原始内存块的指针,同时递增一个也存储在内存中的引用计数器,使得每个副本都是对象可以访问它。 如果引用计数降至零,则销毁对象将减少引用计数并仅释放分配的内存。 您只需要一个自定义复制构造函数和赋值运算符。 这基本上是共享指针的工作方式。 This is relatively easy: In the class' constructor, you allocate m

矩阵如何存储在内存中?(How are matrices stored in memory?)

正如它在“熵编码”中所说的那样,使用Z字形图案,与RLE一起使用,在许多情况下,RLE已经减小了尺寸。 但是,据我所知,DCT本身并没有给出稀疏矩阵。 但它通常会增强矩阵的熵。 这是compressen变得有损的点:输入矩阵用DCT传输,然后量化量化然后使用霍夫曼编码。 As it says in "Entropy coding" a zig-zag pattern is used, together with RLE which will already reduce size for man

每个请求的Java新会话?(Java New Session For Each Request?)

你是如何进行重定向的? 您是否事先调用了HttpServletResponse.encodeRedirectURL()? 在这里阅读javadoc 您可以使用它像response.sendRedirect(response.encodeRedirectURL(path)); The issue was with the path in the JSESSIONID cookie. I still can't figure out why it was being set to the tomca

css:浮动div中重叠的标题h1(css: overlapping headlines h1 in floated divs)

我认为word-break ,如果你想在一个单词中打破行,你可以指定它,这样做可以解决问题: .column { word-break:break-all; } jsFiddle演示。 您可以在此处阅读有关word-break属性的更多信息。 I think word-break, with which you can specify if you want to break line within a word, will do the trick: .column { word-break

无论图像如何,Caffe预测同一类(Caffe predicts same class regardless of image)

我认为您忘记在分类时间内缩放输入图像,如train_test.prototxt文件的第11行所示。 您可能应该在C ++代码中的某个位置乘以该因子,或者使用Caffe图层来缩放输入(请查看ELTWISE或POWER图层)。 编辑: 在评论中进行了一次对话之后,结果发现在classification.cpp文件中错误地删除了图像均值,而在原始训练/测试管道中没有减去图像均值。 I think you have forgotten to scale the input image during cl

xcode语法颜色编码解释?(xcode syntax color coding explained?)

转到: Xcode => Preferences => Fonts & Colors 您将看到每个语法高亮颜色旁边都有一个简短的解释。 Go to: Xcode => Preferences => Fonts & Colors You'll see that each syntax highlighting colour has a brief explanation next to it.

在Access 2010 Runtime中使用Office 2000校对工具(Use Office 2000 proofing tools in Access 2010 Runtime)

你考虑过第三方拼写检查吗? 您可以将在C#中开发的自定义WinForms控件插入访问数据库吗? VB6控件怎么样? 如果你能找到一个使用第三方库进行拼写检查的控件,那可能会有效。 Have you considered a third party spell checker? Can you insert a custom WinForms controls developed in C# into an access database? What about a VB6 control? If

从单独的Web主机将图像传输到服务器上(Getting images onto server from separate web host)

我有同样的问题,因为我在远程服务器上有两个图像,我需要在每天的预定义时间复制到我的本地服务器,这是我能够提出的代码... try { if(@copy('url/to/source/image.ext', 'local/absolute/path/on/server/' . date("d-m-Y") . ".gif")) { } else { $errors = error_get_last(); throw new Exception($err

从旧版本复制文件并保留它们(旧/新版本)(Copy a file from old revision and keep both of them (old / new revision))

我不确定我完全明白你在说什么。 你能编辑你的帖子并包含你正在做的Subversion命令/操作的特定顺序吗? 最好使用命令行svn客户端,以便容易为其他人重现问题。 如果您只是想获取文件的旧副本(即使该文件不再存在),您可以使用如下命令: svn copy ${repo}/trunk/moduleA/file1@${rev} ${repo}/trunk/moduleB/file1 其中${repo}是您的存储库的URL, ${rev}是您想要的文件的版本。 这将恢复该文件的旧版本,包括最高版本