zoukankan      html  css  js  c++  java
  • 文件下载

    一.使用java IO

    下载文件最基本的方法是java IO,使用URL类打开待下载文件的连接。为有效读取文件,我们使用openStream() 方法获取 InputStream:

    BufferedInputStream in = new BufferedInputStream(new URL(FILE_URL).openStream())

    从InputStream读取文件时,强烈建议使用BufferedInputStream去包装InputStream,用于提升性能。
    使用缓存可以提升性能。read方法每次读一个字节,每次方法调用意味着系统调用底层的文件系统。当JVM调用read()方法时,程序执行上下文将从用户模式切换到内核模式并返回。

    从性能的角度来看,这种上下文切换非常昂贵。当我们读取大量字节时,由于涉及大量上下文切换,应用程序性能将会很差。

    为了读取URL的字节并写至本地文件,需要使用FileOutputStream 类的write方法:

    try (BufferedInputStream in = new BufferedInputStream(new URL(FILE_URL).openStream());
      FileOutputStream fileOutputStream = new FileOutputStream(FILE_NAME)) {
        byte dataBuffer[] = new byte[1024];
        int bytesRead;
        while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
            fileOutputStream.write(dataBuffer, 0, bytesRead);
        }
    } catch (IOException e) {
        // handle exception
    }

    使用BufferedInputStream,read方法按照我们设置缓冲器大小读取文件。示例中我们设置一次读取1024字节,所以BufferedInputStream 是必要的。

    上述示例代码冗长,幸运的是在Java7中Files类包含处理IO操作的助手方法。可以使用File.copy()方法从InputStream中读取所有字节,然后复制至本地文件:

    InputStream in = new URL(FILE_URL).openStream();
    Files.copy(in, Paths.get(FILE_NAME), StandardCopyOption.REPLACE_EXISTING);

    上述代码可以正常工作,但缺点是字节被缓冲到内存中。Java为我们提供了NIO包,它有方法在两个通道之间直接传输字节,而无需缓冲。下面我们会详细讲解。

    二.使用NIO
    java NIO包提供了无缓冲情况下在两个通道之间直接传输字节的可能。

    为了读来自URL的文件,需从URL流创建ReadableByteChannel :

    ReadableByteChannel readableByteChannel = Channels.newChannel(url.openStream());

    从ReadableByteChannel 读取字节将被传输至FileChannel:

    FileOutputStream fileOutputStream = new FileOutputStream(FILE_NAME);
    FileChannel fileChannel = fileOutputStream.getChannel();

    然后使用transferFrom方法,从ReadableByteChannel 类下载来自URL的字节传输到FileChannel:

    fileOutputStream.getChannel()
    .transferFrom(readableByteChannel, 0, Long.MAX_VALUE);

    transferTo() 和 transferFrom() 方法比简单使用缓存从流中读更有效。依据不同的底层操作系统,数据可以直接从文件系统缓存传输到我们的文件,而不必将任何字节复制到应用程序内存中。

    在Linux和UNIX系统上,这些方法使用零拷贝技术,减少了内核模式和用户模式之间的上下文切换次数。

    三.javaweb实现文件下载(包含.txt文件等默认在浏览器中打开的文件)

    jsp:

    <a href="javascript:void(0)" id="zip" >src.zip</a><br><br>

    js

    $(document).ready(function(){
        
        $("#zip").click(function() {        
            location.href= path + "/device/downloadFile";
        });
        
        
    });

    后台代码

     @RequestMapping(value="/downloadFile")
         @ResponseBody
         public void downloadDeviceLog(HttpServletRequest request, HttpServletResponse response) throws Exception {
             String logUrl = "http://localhost:8080/dm/img/in.zip";
                try {
                    String [] logUrlArray = logUrl.split("/");
                    String fileName = logUrlArray[logUrlArray.length-1];
                    URL url = new URL(logUrl);
                    URLConnection uc = url.openConnection();
                    response.setContentType("application/octet-stream");//设置文件类型
                    response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
                    response.setHeader("Content-Length", String.valueOf(uc.getContentLength()));
                    ServletOutputStream out = response.getOutputStream();
                    IOUtils.copy(uc.getInputStream(), out);
                } catch (Exception e) {
                    e.printStackTrace();
                }
        
         }

      运行结果

    注:

    1、其中关键的一句是给响应头设置“content-disposition”属性,关于它的介绍可参考文章《Content-Disposition 响应头,设置文件在浏览器打开还是下载》

    2、contenType也可以设置成专门针对某种文件类型的,比如文中是.txt类型,就可以这样设置:

    response.setContentType("text/plain");//设置文件类型

    3、最近将代码放在两台服务器上(两台tomcat编码相同),一台正常,一台报Server returned HTTP response code: 400 for URL,报错的地方在 IOUtils.copy(uc.getInputStream(), out);后来发现代码引用的url里面含中文,去掉中文之后发现好了,但是还是不知道为什么两台服务器会出现不一样的情况,先贴出来,以后找到问题原因再补充。
    后边也可以自行设计代码copy

          OutputStream outp = null;
          FileInputStream in = null;
          try
          {
              outp = response.getOutputStream();
              in = new FileInputStream(filedownload); 
     
              byte[] b = new byte[1024];
              int i = 0;
     
              while((i = in.read(b)) > 0)
              {
                  outp.write(b, 0, i);
              }
              outp.flush();
          }
          catch(Exception e)
          {
              System.out.println("Error!");
              e.printStackTrace();
          }
          finally
          {
              if(in != null)
              {
                  in.close();
                  in = null;
              }
              if(outp != null)
              {
                  outp.close();
                  out.clear();
                  outp = null;
              }
          }
    !
  • 相关阅读:
    Change MYSQL data directory
    Docker distrubution in django
    mongo&node
    理解Docker单机容器网络
    auto dock
    django_restframework_angularjs
    Javascript异步编程的4种方法
    DockerProblem
    Javascript面向对象编程
    scrapy post请求 multipart/form-data
  • 原文地址:https://www.cnblogs.com/lukelook/p/11066275.html
Copyright © 2011-2022 走看看