Java 下载超过2GB的文件
2013-12-02 21:05
393 查看
Java 下载超过2GB的文件
I discovered a few days back an issue with our product on HTTP downloads > 2GB.
It appears to be a simple overflow on the HttpServletResponse.setContentLength method.
You can probably excuse the API designers circa 1997 assuming a 32-bit signed Integer with
max value 231-1 (2147483647 bytes) would be sufficient. The Gigabit ethernet standard did not
come for another year (1998)!
Here is the exception seen when you provide a long value greater than 2147483647 bytes to
the setContentLength(int) method:
java.net.ProtocolException: Exceeded stated content-length of: '-XXXX' bytes
at weblogic.servlet.internal.ServletOutputStreamImpl.checkCL(ServletOutputStreamImpl.java:200)
Below is a sample download servlet with workaround for the 2gb limitation.
It has been tested on Firefox 3.6 against WebLogic Server 10.3.6 with a 2.2GB download and worked perfectly.
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class DownloadServlet
extends HttpServlet
{
@SuppressWarnings("compatibility:1533750721037291976")
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
doPost(request, response);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
// if no file parameter specified, download hosts file
String file = request.getParameter("file");
file = (file == null || file.length() == 0) ? "/etc/hosts" : file;
File fileObj = new File(file);
if ((!fileObj.exists()) || (!fileObj.isFile()) || (!fileObj.canRead()))
{
throw new IOException("'file' '" + file + "' cannot be read.");
}
ServletContext context = getServletConfig().getServletContext();
String mimetype = context.getMimeType(file);
response.setContentType(mimetype == null ? "application/octet-stream" :
mimetype);
long length = fileObj.length();
if (length <= Integer.MAX_VALUE)
{
response.setContentLength((int)length);
}
else
{
response.addHeader("Content-Length", Long.toString(length));
}
response.setHeader("Content-Disposition",
"attachment; filename=\"" + fileObj.getName() + "\"");
ServletOutputStream out = response.getOutputStream();
InputStream in = null;
byte[] buffer = new byte[32768];
try
{
in = new FileInputStream(fileObj);
int bytesRead;
while ((bytesRead = in.read(buffer)) >= 0)
{
out.write(buffer, 0, bytesRead);
}
}
finally
{
if (in != null)
{
in.close();
}
}
}
}
I discovered a few days back an issue with our product on HTTP downloads > 2GB.
It appears to be a simple overflow on the HttpServletResponse.setContentLength method.
You can probably excuse the API designers circa 1997 assuming a 32-bit signed Integer with
max value 231-1 (2147483647 bytes) would be sufficient. The Gigabit ethernet standard did not
come for another year (1998)!
Here is the exception seen when you provide a long value greater than 2147483647 bytes to
the setContentLength(int) method:
java.net.ProtocolException: Exceeded stated content-length of: '-XXXX' bytes
at weblogic.servlet.internal.ServletOutputStreamImpl.checkCL(ServletOutputStreamImpl.java:200)
Below is a sample download servlet with workaround for the 2gb limitation.
It has been tested on Firefox 3.6 against WebLogic Server 10.3.6 with a 2.2GB download and worked perfectly.
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class DownloadServlet
extends HttpServlet
{
@SuppressWarnings("compatibility:1533750721037291976")
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
doPost(request, response);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
// if no file parameter specified, download hosts file
String file = request.getParameter("file");
file = (file == null || file.length() == 0) ? "/etc/hosts" : file;
File fileObj = new File(file);
if ((!fileObj.exists()) || (!fileObj.isFile()) || (!fileObj.canRead()))
{
throw new IOException("'file' '" + file + "' cannot be read.");
}
ServletContext context = getServletConfig().getServletContext();
String mimetype = context.getMimeType(file);
response.setContentType(mimetype == null ? "application/octet-stream" :
mimetype);
long length = fileObj.length();
if (length <= Integer.MAX_VALUE)
{
response.setContentLength((int)length);
}
else
{
response.addHeader("Content-Length", Long.toString(length));
}
response.setHeader("Content-Disposition",
"attachment; filename=\"" + fileObj.getName() + "\"");
ServletOutputStream out = response.getOutputStream();
InputStream in = null;
byte[] buffer = new byte[32768];
try
{
in = new FileInputStream(fileObj);
int bytesRead;
while ((bytesRead = in.read(buffer)) >= 0)
{
out.write(buffer, 0, bytesRead);
}
}
finally
{
if (in != null)
{
in.close();
}
}
}
}
相关文章推荐
- FTP下载和上传文件的java实现
- java io 文件下载
- javaWeb更改文件后下载的文件没有变化
- 【Java-Android开发系列】Android SDK for Windows全部文件打包下载【115已死,文件无法下载】
- Java文件下载的几种方式
- Java文件下载
- Java 下载文件模板
- java下载文件代码示例
- Java文件下载处理中文名(使用URLEncoder编码及空格变+解决)
- JXL生成的excel文件+JAVA文件下载功能
- 防浏览器直接打开文件的java下载
- java实现文件下载的两种方式
- Java 文件下载(支持断点续传)(实例2)
- java文件原生方式的上传和下载,适合新手学习
- Java文件上传下载
- EditPlus最新汉化绿色版的下载、破解,以及开发java文件时的一些相关设置操作视频
- JSch____Java实现SFTP文件上传下载…
- 利用java中的多线程和io流,最快速度的下载服务器文件
- Java下载文件的几种方式
- java实现文件上传与下载