我试图将一个大的视频/图像文件从本地文件系统发布到http路径,但是在一段时间后我遇到内存不足错误…
这里是代码
public boolean publishFile(URI publishTo,String localPath) throws Exception { InputStream istream = null; OutputStream ostream = null; boolean isPublishSuccess = false; URL url = makeURL(publishTo.getHost(),this.port,publishTo.getPath()); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); if (conn != null) { try { conn.setDoOutput(true); conn.setDoInput(true); conn.setRequestMethod("PUT"); istream = new FileInputStream(localPath); ostream = conn.getOutputStream(); int n; byte[] buf = new byte[4096]; while ((n = istream.read(buf,buf.length)) > 0) { ostream.write(buf,n); //<--- ERROR happens on this line.......??? } int rc = conn.getResponseCode(); if (rc == 201) { isPublishSuccess = true; } } catch (Exception ex) { log.error(ex); } finally { if (ostream != null) { ostream.close(); } if (istream != null) { istream.close(); } } } return isPublishSuccess; }
HEre是我正在收到的错误…
Exception in thread "Thread-8773" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:2786) at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:94) at sun.net.www.http.PosterOutputStream.write(PosterOutputStream.java:61) at com.test.HTTPClient.publishFile(HTTPClient.java:110) at com.test.HttpFileTransport.put(HttpFileTransport.java:97)
解决方法
HttpUrlConnection正在缓冲数据,以便它可以设置Content-Length头(每
HTTP spec).
一种替代方案,如果您的目标服务器支持它,则使用“chunked”传输.这将一次缓冲一小部分数据.然而,并不是所有的服务都支持它(例如,Amazon S3)不支持.
另一个选择(而且更好的一个)是使用Jakarta HttpClient.您可以在文件的请求中设置“实体”,并且连接代码将适当地设置请求头.
编辑:nos评论说OP可以调用HttpURLConnection.setFixedLengthStreamingMode(long length).我不知道这种方法;它在1.5中被添加,从那时起我还没有使用这个类.
但是,我仍然建议使用Jakarta HttpClient,因为它减少了OP必须维护的代码量.代码是样板,但仍然有潜在的错误:
> OP正确处理在输入和输出之间复制的循环.通常当我看到一个例子,海报没有正确检查返回的缓冲区大小,或者不断重新分配缓冲区.恭喜,但您现在必须确保您的继任者非常小心.
>异常处理不太好.是的,OP记得在一个最后的块中关闭连接,再次恭喜你.除了close()调用可能抛出IOException之外,保持另一个不执行.而且整个方法抛出异常,所以编译器不会帮助捕获类似的错误.
>我计算31行代码来设置和执行响应(不包括响应代码检查和URL计算,但包括try / catch / finally).使用HttpClient,这将在几十个LOC的范围内.
即使OP完美地编写了这段代码,并将其重构成类似于Jakarta Commons IO的方法,他/他不应该这样做.此代码已经被其他人编写和测试.我知道这是浪费我改写的时间,并怀疑这是浪费OP的时间.