Reputation: 660
I am trying to create a method that allows users to download a file on the file system via a Servlet. Right now, the correct filename
shows on the download and a file is downloaded but the contents of the file are always null.
I've also tried to get the file contents to print to the console but nothing is showing up.
Can anyone suggest what I've done wrong here?
Thanks
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();
Annotations
@WebServlet(urlPatterns =
{ "/Routing/*" })
@MultipartConfig(location = "/tmp", fileSizeThreshold = 1024 * 1024, maxFileSize = 1024 * 1024 * 5, maxRequestSize = 1024 * 1024 * 5 * 5)
public class Routing extends HttpServlet
{
Upvotes: 2
Views: 3416
Reputation: 29
Just add outStream.setContentLength(inStream.available); after outStream.write( bytes );
Upvotes: 0
Reputation: 89189
This solution is a modified solution from BalusC File Servlet blog.
The reason I use this solution is because it reset()
the HttpServletResponse response
before writing data.
@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();
}
}
}
}
I hope this helps.
Upvotes: 2
Reputation: 7519
I recommend several tests to isolate the problem since there are still too many unknowns here. I had no problems running your code, so it is likely a configuration issue with your servlet container, or an assumption about the filesystem.
The key to isolating the problem is start with the basics. Try to return a String instead of a file, to ensure that the communication with the server is actually behaving properly. If you get the same response, then you know the problem isn't with the file 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();
If the above test worked, then you know the problem is with the file or the method you are using to read the file. You code currently makes a lot of assumptions about everything being perfect with the file that is being requested. Perform some rigorous testing to make certain the file is accessible:
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);
and finally check the file size reported by the filesystem against the number of bytes that were read:
byte[] bytes = Files.readAllBytes( downloadFile.getAbsoluteFile().toPath() );
int bytesRead = bytes.length;
System.out.println("bytes read: " + bytesRead);
The results of these tests should narrow down the problem for you.
Upvotes: 2
Reputation: 714
maybe the file is empty add this line to make sure the file is not empty
System.out.println("File size: " + bytes.length);
Upvotes: 0