我有一个Web实例,它通过使用文件servlet为动态名称提供下载。我当前的文件名是A.apk,我可以下载为A_username.apk。到目前为止一切都还可以。但是,即使文件下载过程成功,它也总是抛出异常。
我的代码:
public class FileServlet extends HttpServlet {
private static final int DEFAULT_BUFFER_SIZE = 10240; // 10KB.
private String filePath;
public void init() throws ServletException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
String tag = "" + request.getParameter("tag");
String name = "MyApp";
try {
String requestedFile = request.getPathInfo();
this.filePath = "C:/WEBROOT/Test/build/web/andrapp";
// Check if file is actually supplied to the request URI.
if (requestedFile == 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 file = new File(filePath, URLDecoder.decode(requestedFile, "UTF-8"));
// Check if file actually exists in filesystem.
if (!file.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=\"" + name + ".apk" + "\"");
// 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[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
System.out.println("Download Success");
} finally {
// Gently close streams.
close(output);
close(input);
}
} catch (Exception ex) {
System.out.println("Download Cancelled");
ex.printStackTrace();
}
}
// 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();
}
}
}
}
如果下载正常,则输出“下载成功”和“下载已取消”两者。如果我取消下载,它只输出“下载已取消”。
例外日志:
CORE3282: stdout: Download Cancelled
CORE3283: stderr: java.io.IOException: WEB8001: Write failed
CORE3283: stderr: at com.iplanet.ias.web.connector.nsapi.NSAPIConnector.write(NSAPIConnector.java:789)
CORE3283: stderr: at com.iplanet.ias.web.connector.nsapi.NSAPIResponseStream.write(NSAPIResponseStream.java:75)
CORE3283: stderr: at org.apache.catalina.connector.ResponseBase.flushBuffer(ResponseBase.java:824)
CORE3283: stderr: at org.apache.catalina.connector.HttpResponseBase.flushBuffer(HttpResponseBase.java:794)
CORE3283: stderr: at com.iplanet.ias.web.connector.nsapi.NSAPIResponse.flushBuffer(NSAPIResponse.java:127)
CORE3283: stderr: at org.apache.catalina.connector.ResponseBase.write(ResponseBase.java:788)
CORE3283: stderr: at org.apache.catalina.connector.ResponseStream.write(ResponseStream.java:361)
CORE3283: stderr: at java.io.BufferedOutputStream.write(BufferedOutputStream.java:122)
CORE3283: stderr: at com.newwap.developer.tools.FileServlet.doGet(FileServlet.java:120)
CORE3283: stderr: at javax.servlet.http.HttpServlet.service(HttpServlet.java:787)
CORE3283: stderr: at javax.servlet.http.HttpServlet.service(HttpServlet.java:908)
CORE3283: stderr: at org.apache.catalina.core.StandardWrapperValve.invokeServletService(StandardWrapperValve.java:771)
CORE3283: stderr: at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:322)
CORE3283: stderr: at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:509)
CORE3283: stderr: at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:218)
CORE3283: stderr: at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:509)
CORE3283: stderr: at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:209)
CORE3283: stderr: at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:509)
CORE3283: stderr: at com.iplanet.ias.web.connector.nsapi.NSAPIProcessor.process(NSAPIProcessor.java:157)
CORE3283: stderr: at com.iplanet.ias.web.WebContainer.service(WebContainer.java:579)
CORE3282: stdout: Download Success
它表示exaclty行:output.write(buffer,0,length);
有什么想法吗?
答案 0 :(得分:0)
我会建议尝试不同的解决方案:)。
编写如下所示的私有方法,将文件内容返回为bytes
private byte[] getApkAsBytes(String apkPath)
throws FileNotFoundException, IOException {
File apkFile = new File(apkPath);
byte[] binaryAPKFile = new byte[(int) apkFile.length()];
FileInputStream fileInputStream = new FileInputStream(apkFile);
// convert file into array of bytes
fileInputStream.read(binaryAPKFile);
fileInputStream.close();
return binaryAPKFile;
}
然后简单地调用如下,而不是使用BufferedOutputStream
并关闭它。
byte[] apkBytes = getApkAsBytes();
String bytesAsString = JSON.encode(apkBytes);
response.getWriter().write(bytesAsString);
import org.apache.commons.codec.binary.Base64;
public final class JSON {
private JSON() {}
public static byte[] decode(String s) {
return Base64.decodeBase64(s);
}
public static String encode(byte[] bytes) {
return Base64.encodeBase64String(bytes);
}
}
在这种情况下,JSON
是用于编码byte[]
到String
以及从String
到byte[]