用JAVA下载HTTP文件时遇到问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用JAVA下载HTTP文件时遇到问题相关的知识,希望对你有一定的参考价值。

我用JAVA写一个下载文件的工具,但是遇到了问题,就是我下载一个文件时,它过小,不足1KB,只有700多字节,但我获得它的“Content-Length”有16字节,这样搞的我下载下来的文件就只有16字节大小,文件被修改了,导致打不开了。这种情况该怎么办去下载呢?因为下载的文件(压缩包)查看了下

像这个文件的content-length为31118,下载顺利,解压也没问题
我下载另外一个文件(压缩包)时,URL连接后面的201407改为20140904,content-length为16,我用InputStream input = httpConnection.getInputStream()来传输,input.avalilable大小也为16字节,这样就导致了所有很小的文件全部设置大小为16字节了,我甚至用byte[1]设置下载大小,然后对流进行保存,用read函数,这样都无法避免
但是我用浏览器下载后发下压缩包大小为700多字节,占用空间大小为4KB
百思不得其解,希望大神解答。
这种情况改怎么下载呢?

import java.net.*;
import java.io.*;
public class URLConnectionDemo
    public static void main(String[] args)throws Exception
        URL url = new URL("http://www.scp.edu.cn/pantoschoolzz/BG/Bord/Message/DownloadMessageAttachment.aspx?ID=215");
        URLConnection uc = url.openConnection();
        String fileName = uc.getHeaderField(6);
        fileName = URLDecoder.decode(fileName.substring(fileName.indexOf("filename=")+9),"UTF-8");
        System.out.println("文件名为:"+fileName);
        System.out.println("文件大小:"+(uc.getContentLength()/1024)+"KB");
        String path = "D:"+File.separator+fileName;
        FileOutputStream os = new FileOutputStream(path);
        InputStream is = uc.getInputStream();
        byte[] b = new byte[1024];
        int len = 0;
        while((len=is.read(b))!=-1)
            os.write(b,0,len);
        
        os.close();
        is.close();
        System.out.println("下载成功,文件保存在:"+path);
    

//给你一个下载的例子吧,仅供参考。

参考技术A 首先我们观察 HTTP 通信过程发现服务端确实说明了大小是 31118 字节,对吧?
似乎程序得到 Content-Length 的方法有问题,这个过程中有没有发生重定向的事情?
参考技术B 你要flush一下啊,骚年

使用角度 $http 或 jquery.ajax 下载二进制文件时遇到问题

【中文标题】使用角度 $http 或 jquery.ajax 下载二进制文件时遇到问题【英文标题】:Trouble downloading binary file with angular $http or jquery.ajax 【发布时间】:2016-01-13 00:56:12 【问题描述】:

我的问题是我在客户端获取了错误大小的文件。这是我的@Controller ...

@RequestMapping(value = "/download/id", method = RequestMethod.GET)
public ResponseEntity<?> download(final HttpServletRequest request,
                                  final HttpServletResponse response,
                                  @PathVariable("id") final int id) throws IOException 
    try 
        // Pseudo-code for retrieving file from ID.
        Path zippath = getZipFile(id);

        if (!Files.exists(zippath)) 
            throw new IOException("File not found.");
        

        ResponseEntity<InputStreamResource> result;
        return ResponseEntity.ok()
                             .contentLength(Files.size(zippath))
                             .contentType(MediaType.APPLICATION_OCTET_STREAM)
                             .body(new InputStreamResource(new FileInputStream(zippath.toFile())));
     catch (Exception ex) 
        // ErrorInfo is another class, unimportant
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ErrorInfo(ex));
    

...这是我使用 angular-file-saver 的客户端代码...

$http(url: "export/download/" + exportitem.exportId, withCredentials: true)
.then(function(response) 
    function str2bytes(str) 
        var bytes = new Uint8Array(str.length);
        for (var i=0; i<str.length; i++) 
            bytes[i] = str.charCodeAt(i);
        
        return bytes;
    
    var blob = new Blob([str2bytes(response.data)], type: 'application/octet-stream');
    FileSaver.saveAs(blob, "download.zip");
, $exceptionHandler);

原始文件为 935673 字节,但 response.data 为 900728,并将其通过转换传递给 Uint8Array 会产生一个大小为 900728 的 Blob。无论哪种方式,生成的保存文件都是 900728 字节(34945 字节)。此外,它所写的内容也不完全相同。它似乎有点臃肿,但最后一部分似乎被截断了。有什么想法我可能做错了吗?

更新

我刚刚将我的控制器方法更新为以下并得到完全相同的结果。咕噜。

@RequestMapping(value = "/download/id", method = RequestMethod.GET)
public void download(final HttpServletRequest request,
                     final HttpServletResponse response,
                     @PathVariable("id") final int id) throws IOException 
    // Pseudo-code for retrieving file from ID.
    Path zippath = getZipFile(id);

    if (!Files.exists(zippath)) 
        throw new IOException("File not found.");
    

    response.setContentType("application/zip");
    response.setHeader("Content-Disposition",
                        "attachment; filename=download.zip");

    InputStream inputStream = new FileInputStream(zippath.toFile());
    org.apache.commons.io.IOUtils.copy(inputStream, response.getOutputStream());
    response.flushBuffer();
    inputStream.close();

【问题讨论】:

zippath.toFile() 会发生什么? 将 Path 对象转换为 File 对象,以便我可以在 FileInputStream 中使用它。 【参考方案1】:

所以问题原来是 Angular 的 $http 服务。我还尝试了 jQuery 的 ajax 方法。两者都给出了相同的结果。如果我改为使用本机 XMLHttpRequest 它可以正常工作。所以 Java 代码是正确的。我首先通过将文件直接暴露在互联网上来验证这一点,然后使用 curl 和直接在浏览器中访问我设法下载了正确大小的文件。然后我找到了这个解决方案,这样我也可以通过 javascript 下载文件。

var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = "blob";
xhr.withCredentials = true;
xhr.onreadystatechange = function ()
    if (xhr.readyState === 4) 
        var blob = xhr.response;
        FileSaver.saveAs(blob, filename);
    
;
xhr.send();

为什么 Angular 或 jQuery 会给出错误的结果?我仍然不知道,但是如果有人希望给出使用这些答案的答案,将不胜感激。

【讨论】:

同样的事情。不知道为什么 jquery/angular 会增加文件大小并破坏数据。【参考方案2】:

响应类型:blob 做了一个 zip 文件的技巧

角度 2 +

this.http.get('http://localhost:8080/export',  responseType: ResponseContentType.Blob )
  .subscribe((res: any) => 
        const blob = new Blob([res._body],  type: 'application/zip' );
         saveAs(blob, "fileName.zip");

【讨论】:

【参考方案3】:

我刚刚偶然发现 $http 请求中的“responseType”,您可能正在寻找“blob”:https://docs.angularjs.org/api/ng/service/$http#usage

【讨论】:

以上是关于用JAVA下载HTTP文件时遇到问题的主要内容,如果未能解决你的问题,请参考以下文章

8-3下载inception-v3时遇到的问题

抛出 java.io.IOException: 当我尝试从服务器下载 txt 文件时,http:/ 上的流意外结束

在用mvn编译java文件时遇到问题

Java实现SFTP上传下载文件及遇到的问题

Pycharm安装及遇到的问题

JAVA文件下载功能问题解决日志