简体   繁体   English

使用Java读写大型二进制文件

[英]Read and Write large binary files with Java

So I have this code which reads the proper installer file from disk (tar.gz, exe or dmg), and streams it to the user (code below). 因此,我有这段代码可以从磁盘(tar.gz,exe或dmg)读取正确的安装程序文件,并将其流式传输给用户(下面的代码)。 The installers are actually archives, which can be extracted and setup can be ran manually (this is specific for Windows, Mac installer needs to be mounted, Unix installer also needs to be extracted) 安装程序实际上是归档文件,可以将其提取并可以手动运行设置(这是特定于Windows的,需要安装Mac安装程序,也需要提取Unix安装程序)

    InputStream in = null;
    OutputStream out = null;

    byte[] buffer = new byte[16384];

    try {
        String bundle = ServletRequestUtils.getRequiredStringParameter(request, "bundle");

        String installerPath = constructFilePath(bundle);
        File installer = new File(installerPath);
        if(!installer.exists()){
            logger.error("Cannot read installer file");
            response.sendRedirect("/somewhere");
        }else{
            in = new FileInputStream(installer);
            response.setContentType(getBundleContentType(bundle)); //application/octet-stream or application/x-gzip or application/x-apple-diskimage
            response.setHeader("Pragma", "private"); 
            response.setHeader("Cache-Control", "private, must-revalidate"); 
            response.addHeader("Content-Disposition", "attachment;filename="+getBundleFileName(bundle)); //Setting new file name
            out = new BufferedOutputStream(response.getOutputStream());

            while((in.read(buffer)) != -1)
                out.write(buffer);
        }
    } catch (Exception e) {
        logger.error("Exception downloading installer file, reason: " + e);
        response.sendRedirect("/somewhere");
    } finally {
        if(in != null){
            in.close();
        }
        if(out != null){
            out.flush();
            out.close();
        }
    }

    return null;

I'll take the Windows (.exe) installer as an example. 我将以Windows(.exe)安装程序为例。 Previously, when I had the code to redirect to http:///somepath/installer.exe for the download, the file would've been downloaded and I was able to extract it with 7zip, but now, when I try to extract it with 7zip, I'm getting : 以前,当我有重定向到http:///somepath/installer.exe的代码进行下载时,该文件将被下载,并且能够使用7zip提取文件,但是现在,当我尝试提取文件时使用7zip,我得到:

Cannot open file as archive.

However, I am able to double-click the .exe and successfully do the install. 但是,我可以双击.exe并成功完成安装。 I am also able to extract it using winRAR as well. 我也可以使用winRAR提取它。

Same thing happened with the Unix installer. Unix安装程序也发生了同样的事情。 When I download it to a Unix machine and try to extract it (by right-click "Extract here") I'm getting this error: 当我将其下载到Unix计算机并尝试将其解压缩时(通过右键单击“在此处提取”),我收到此错误:

gzip: stdin: decompression OK, trailing garbage ignored 
/bin/gtar: Child returned status 2 
/bin/gtar: Error is not recoverable: exiting now

However, I am able to open it with "ark" and properly extract its contents. 但是,我可以使用“ ark”打开它并正确提取其内容。

I should also point out that the bytes of the files do not match after a download (the downloaded one compared to the one on the filesystem, which should be the same). 我还应该指出,下载后文件的字节不匹配(下载的文件与文件系统上的文件相比,应该相同)。

Am I missing something? 我想念什么吗?

You could try write exactly the same data you read: 您可以尝试写入与读取的数据完全相同的数据:

while ((read = in.read(buffer)) != -1) {
    out.write(buffer, 0, read);
}

It is because you are writing the whole buffer. 这是因为您正在写整个缓冲区。

Imagine the file was 16385 bytes. 假设文件为16385字节。

The first in.read(buffer) would fill up the whole buffer and return 16384. You will then write the whole buffer. 第一个in.read(buffer)将填满整个缓冲区并返回16384。然后,您将写入整个缓冲区。 The second time, it will read one byte and again, you will write the whole buffer. 第二次,它将读取一个字节,然后再次写入整个缓冲区。

Someone has beaten me to it, but I was going to add that you could use IOUtils to do this... 有人击败了我,但我要补充一点,您可以使用IOUtils来做到这一点...

http://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/IOUtils.html http://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/IOUtils.html

For example IOUtils.copy(in, out) 例如IOUtils.copy(in, out)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM