我正在尝试创建一种方法,允许用户通过Servlet下载文件系统上的文件。现在,正确的filename
显示在下载中,并且下载了一个文件,但文件的内容始终为空。
我还尝试将文件内容打印到控制台,但没有任何显示。
谁能建议我在这里做错了什么?
谢谢
String filePath = "uploads/" + request.getParameter( "filename" );
File downloadFile = new File( filePath );
String relativePath = getServletContext().getRealPath( "" );
System.out.println( "relativePath = " + relativePath );
ServletContext context = getServletContext();
String mimeType = context.getMimeType( filePath );
if( mimeType == null )
{
mimeType = "application/octet-stream";
}
System.out.println( "MIME type: " + mimeType );
response.setContentType( mimeType );
response.setContentLength( (int) downloadFile.length() );
String headerKey = "Content-Disposition";
String headerValue = String.format( "attachment; filename="%s"", downloadFile.getName() );
response.setHeader( headerKey, headerValue );
byte[] bytes = Files.readAllBytes( downloadFile.getAbsoluteFile().toPath() );
OutputStream outStream = response.getOutputStream();
System.out.println( bytes.toString() );
outStream.write( bytes );
outStream.flush();
outStream.close();
附注
@WebServlet(urlPatterns =
{ "/Routing/*" })
@MultipartConfig(location = "/tmp", fileSizeThreshold = 1024 * 1024, maxFileSize = 1024 * 1024 * 5, maxRequestSize = 1024 * 1024 * 5 * 5)
public class Routing extends HttpServlet
{
此解决方案是来自BalusC File Servlet博客的修改解决方案。
我使用此解决方案的原因是因为它在写入数据之前reset()
HttpServletResponse response
。
@WebServlet(urlPatterns =
{ "/Routing/*" })
@MultipartConfig(location = "/tmp", fileSizeThreshold = 1024 * 1024, maxFileSize = 1024 * 1024 * 5, maxRequestSize = 1024 * 1024 * 5 * 5)
public class FileServlet extends HttpServlet {
// Constants ----------------------------------------------------------------------------------
private static final int DEFAULT_BUFFER_SIZE = 10240; // 10KB.
// Actions ------------------------------------------------------------------------------------
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
// Get requested file by path info.
String filePath = "uploads/" + request.getParameter( "filename" );
// Check if file is actually supplied to the request URI.
if (filePath == null) {
// Do your thing if the file is not supplied to the request URI.
// Throw an exception, or send 404, or show default/warning page, or just ignore it.
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}
// Decode the file name (might contain spaces and on) and prepare file object.
File downloadFile = new File( filePath );
// Check if file actually exists in filesystem.
if (!downloadFile.exists()) {
// Do your thing if the file appears to be non-existing.
// Throw an exception, or send 404, or show default/warning page, or just ignore it.
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}
// Get content type by filename.
String contentType = getServletContext().getMimeType(file.getName());
// If content type is unknown, then set the default value.
// For all content types, see: http://www.w3schools.com/media/media_mimeref.asp
// To add new content types, add new mime-mapping entry in web.xml.
if (contentType == null) {
contentType = "application/octet-stream";
}
// Init servlet response.
response.reset();
response.setBufferSize(DEFAULT_BUFFER_SIZE);
response.setContentType(contentType);
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Disposition", "attachment; filename="" + file.getName() + """);
// Prepare streams.
BufferedInputStream input = null;
BufferedOutputStream output = null;
try {
// Open streams.
input = new BufferedInputStream(new FileInputStream(file), DEFAULT_BUFFER_SIZE);
output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);
// Write file contents to response.
byte[] bytes = Files.readAllBytes( downloadFile.getAbsoluteFile().toPath() );
output.write(buffer, 0, bytes.length);
} finally {
// Gently close streams.
close(output);
close(input);
}
}
// Helpers (can be refactored to public utility class) ----------------------------------------
private static void close(Closeable resource) {
if (resource != null) {
try {
resource.close();
} catch (IOException e) {
// Do your thing with the exception. Print it, log it or mail it.
e.printStackTrace();
}
}
}
}
我希望这有所帮助。
我建议进行一些测试来隔离问题,因为这里仍然有太多的未知数。我在运行您的代码时没有遇到任何问题,因此这可能是您的 servlet 容器的配置问题,或者对文件系统的假设。
隔离问题的关键是从基础开始。尝试返回 String 而不是文件,以确保与服务器的通信实际运行正常。如果得到相同的响应,则表明问题不在于文件 IO:
byte[] bytes = "This is a test.".getBytes();
int contentLength = bytes.length;
String mimeType = "text/plain";
response.setContentType( mimeType );
response.setContentLength( contentLength );
OutputStream outStream = response.getOutputStream();
outStream.write( bytes );
outStream.flush();
outStream.close();
如果上述测试有效,那么您就知道问题出在文件或用于读取文件的方法上。您的代码当前对所请求的文件的所有内容都是完美的做出许多假设。执行一些严格的测试以确保文件可访问:
int fileSize = downloadFile.length();
System.out.println("File path: " + downloadFile.getAbsolutePath());
System.out.println("exists: " + downloadFile.exists());
System.out.println("canRead: " + downloadFile.canRead());
System.out.println("File size: " + fileSize);
最后根据读取的字节数检查文件系统报告的文件大小:
byte[] bytes = Files.readAllBytes( downloadFile.getAbsoluteFile().toPath() );
int bytesRead = bytes.length;
System.out.println("bytes read: " + bytesRead);
这些测试的结果应该可以为您缩小问题范围。
也许文件是空的,添加此行以确保文件不为空
System.out.println("File size: " + bytes.length);
只需添加outStream.setContentLength(inStream.available);在 outStream.write( bytes ) 之后 ;