下载文件使用缓存(一次性读取到内存),优化性能(注意静态对象修改需要加锁)

1.web.xml的servlet配置

<servlet>
  <servlet-name>downloadServlet</servlet-name>
  <servlet-class>
   com.huawei.download.DownloadServlet
  </servlet-class>
 </servlet>
 <servlet-mapping>
  <servlet-name>downloadServlet</servlet-name>
  <url-pattern>/downloadClient/*</url-pattern>
 </servlet-mapping>

2.DownloadServlet

 public class DownloadServlet extends HttpServlet
{

 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException
 {
  doPost(req, resp);
 }

 @Override
 protected void doPost(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException
 {

  String url = req.getRequestURI();
  String resFileName = url.substring(url.lastIndexOf("/") + 1, url
    .length());
  String realPath = req.getRealPath("/");
  String exeFile = realPath + "download/test.exe";
  String kipFile = realPath + "download/test";
  PrintWriter out = resp.getWriter();
  byte[] bytes = null;
  OutputStream opts=null;
  if (DownloadManager.checkFileExist(exeFile, kipFile))
  {
   try
   {

   // 如果缓存数组为空或源文件有改动,则重新读取并缓存(注意加锁)
    DownloadManager.cheackIsUpdate(exeFile, kipFile);    

    bytes = DownloadManager.getDownloadBytes();

    resp.reset();
    resp.setContentType("application/x-msdownload");
    resp.setHeader("Content-Disposition", "attachment;filename="
      + resFileName);
    opts = resp.getOutputStream();
    opts.write(bytes);
  
    System.out
      .println("*************************************************");
    System.out.println("*    This Is Local Download Server!");
    System.out.println("*    User   IP: " + req.getRemoteAddr());
    System.out.println("*    Download File Time: "
      + new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
        .format(new java.util.Date()));
    System.out
      .println("*************************************************");

   } catch (Exception e)
   {
    System.out.println("read downloadfile error:" + e);
   }
   finally
   {
    opts.close();
   }

  } else
  {
   out.println("<center>download file is not exsit!</center>");
  }
 }
}

3.DownloadManager

 public class DownloadManager
{
 private static byte[] downloadBytes = null;
 private static long exeFileLastModified = 0L;
 private static long kipFileLastModified = 0L;

 /**
  * 重新读取目标文件并缓存
  * 
    */
 public static void reReadDownloadBytes(String exeFile,
   String kipFile) throws Exception
 {

  File exe = new File(exeFile);
  File kip = new File(kipFile);
  setExeFileLastModified(exe.lastModified());
  setKipFileLastModified(kip.lastModified());
  BufferedInputStream buffer = null;
  ByteArrayOutputStream bos = null;
  try
  {
   buffer = new BufferedInputStream(new FileInputStream(exe));
   //目标文件exe文件大概300k,一次性读取
   int dataSize = 1024*300;
   byte[] bt = new byte[dataSize];
   int len = 0;
   bos = new ByteArrayOutputStream();
   while ((len = buffer.read(bt)) > 0)
   {
    bos.write(bt, 0, bt.length);
   }
  } catch (Exception e)
  {
   throw e;
  } finally
  {
   buffer.close();
   bos.close();
  }

  setDownloadBytes(bos.toByteArray());
  System.out.println("-------------reReading------------");
  System.out.println("-------------Time: "
    + new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
      .format(new java.util.Date()));
 }

 /**
  * 检测客户端目标文件是否存在
    */
 public static boolean checkFileExist(String exeFile, String kipFile)
 {
  File exe = new File(exeFile);
  File kip = new File(kipFile);

  if (kip.exists() && exe.exists())
  {
   return true;
  }
  return false;
 }

 /**
  * 检测检测目标文件否更新
  * 
    */
 public static boolean isFileModified(String exeFile, String kipFile)
 {
  File exe = new File(exeFile);
  File kip = new File(kipFile);

  long nowExeFileLastModified = exe.lastModified();
  long nowKipFileLastModified = kip.lastModified();

  if ((nowExeFileLastModified != getExeFileLastModified())
    || (nowKipFileLastModified != getKipFileLastModified()))
  {
   return true;
  }
  return false;
 }

/**
  * 判断是否需要重新读取文件(要加鎖)
  * 此方法虽然加锁,但是不耗时间
  * @throws Exception
  */
 public static synchronized void cheackIsUpdate(String exeFile, String kipFile) throws Exception
 {
  if (null == DownloadManager.getDownloadBytes()
    || DownloadManager.isFileModified(exeFile, kipFile))
  {
   DownloadManager.reReadDownloadBytes(exeFile,kipFile);
  }
 }

 public static byte[] getDownloadBytes()
 {
  return downloadBytes;
 }

 public static void setDownloadBytes(byte[] downloadBytes)
 {
  DownloadManager.downloadBytes = downloadBytes;
 }

 public static long getExeFileLastModified()
 {
  return exeFileLastModified;
 }

 public static long getKipFileLastModified()
 {
  return kipFileLastModified;
 }

 public static void setExeFileLastModified(long exeFileLastModified)
 {
  DownloadManager.exeFileLastModified = exeFileLastModified;
 }

 public static void setKipFileLastModified(long kipFileLastModified)
 {
  DownloadManager.kipFileLastModified = kipFileLastModified;
 }

}

4. 请求下载地址http://localhost:8080/mytest/downloadClient/test.exe

注意:1.缓存下载文件,需要使用静态字节数组保存,样例中使用了两个输出的转换,很重要:

        2.注意静态对象修改需要加锁

File f = new File(exeFile);
    BufferedInputStream buffer = new BufferedInputStream(
      new FileInputStream(f));
    int dataSize = 1024*1024*10;
    byte[] bt = new byte[dataSize];
    int len = 0;
    resp.reset();

    resp.setContentType("application/x-msdownload");
    resp.setHeader("Content-Disposition", "attachment;filename="
      + resFileName);
    OutputStream out1 = resp.getOutputStream();
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    
    //判断
    
    while ((len = buffer.read(bt)) > 0)
    {
     bos.write(bt, 0, bt.length);
     //out1.write(bt, 0, len);
    }
    //bos.toByteArray()可以缓存
    out1.write(bos.toByteArray());
    
    
    buffer.close();
    out1.close();
    bos.close();

原文地址:https://www.cnblogs.com/qqzy168/p/2671619.html