我的要求是创建2个输入流副本,一个用于Apache Tika File MimeType Detect,另一个用于输出流。
private List<InputStream> copyInputStream(final InputStream pInputStream, final int numberOfCopies) throws UploadServiceException{
final int bytesSize = 8192;
List<InputStream> isList = null;
try(PushbackInputStream pushIS = new PushbackInputStream(pInputStream);
ByteArrayOutputStream baos = new ByteArrayOutputStream();){
byte[] buffer = new byte[bytesSize];
for (int length = 0; ((length = pushIS.read(buffer)) > 0);) {
baos.write(buffer, 0, length);
}
baos.flush();
isList = new ArrayList();
for(int i = 0; i < numberOfCopies ; i++){
isList.add(new ByteArrayInputStream(baos.toByteArray()));
}
} catch (IOException ex) {
throw new MyException(ErrorCodeEnum.IO_ERROR, ex);
} catch (Exception ex) {
throw new MyException(ErrorCodeEnum.GENERIC_ERROR, ex);
}
return isList;
}
我看到一些性能问题
更新
基于反馈
添加了最后一个字节[] byteArrayIS = baos.toByteArray();
private List<InputStream> copyInputStream(final InputStream pInputStream, final int numberOfCopies) throws MyException{
final int bytesSize = 8192;
List<InputStream> isList = null;
try(ByteArrayOutputStream baos = new ByteArrayOutputStream();){
byte[] buffer = new byte[bytesSize];
for (int length = 0; ((length = pInputStream.read(buffer)) > 0);) {
baos.write(buffer, 0, length);
}
baos.flush();
isList = new ArrayList();
final byte[] byteArrayIS = baos.toByteArray();
for(int i = 0; i < numberOfCopies ; i++){
isList.add(new ByteArrayInputStream(byteArrayIS));
}
} catch (IOException ex) {
throw new MyException(ErrorCodeEnum.IO_ERROR, ex);
} catch (Exception ex) {
if(ex instanceof MyException){
throw ex;
}
throw new MyException(ErrorCodeEnum.GENERIC_ERROR, ex);
}
return isList;
}
答案 0 :(得分:3)
字节数组的大小是文件大小的两倍。我打算使用ByteArrayOutputStream(int size),但在上传过程中我没有文件大小。
如果您必须使用ByteArrayOutputStream
并且没有对大小进行良好估计,那么您无能为力。 ByteArrayOutputStream
使用一种简单(且节省时间)的策略,在字节数组填满时将其加倍。
ByteArrayOutputStream
的Apache Commons IO版本使用了一种可以减少复制的替代策略,但它仍然会过度分配内存......
我看到垃圾收集不经常发生,如何处理这种情况。
正确的方法是不处理它。当JVM确定有必要时,让GC运行。到目前为止,这是Java中存储管理的最有效方式。
System.gc()
显式运行GC可能会对性能造成灾难性后果。事实上,GC不经常运行可能是好的事情。
然后......查看你的代码......我可以看到一些东西意味着你将使用比你需要的更多的数据副本。
每次致电toByteArray()
时,都会创建 ByteArrayOutputStream
所捕获数据的新副本。对于你正在做的事情,这是不必要的。相反,您应该在创建单个toByteArray()
后调用byte[]
并将该单个byte[]
包装在多个ByteArrayInputStream
个实例中。您可以确定输入流不会修改byte[]
中的字节。
在您的示例代码中使用PushbackInputStream
并不能实现任何目标......在其他方面无法实现更好的目标。
答案 1 :(得分:1)
首先,为什么要使用PushbackInputStream?这完全无关紧要。如果inputStream尚未缓冲,您可能希望将InputStream包装到BufferedInputStream中。
其次,你是如何测量字节数组大小的? ByteArrayOutputStream自动管理内部分配。如果baos.toByteArray()给你双重数据,请先看看你实际从InputStream中读取了多少(提示:for循环中所有长度的总和)。
至于垃圾收集,它是自动的和不确定的,所以如果你不太了解它,那就别管它了。通常,较少的GC活动意味着有足够的内存可用和/或程序不会产生太多垃圾。这是件好事!但是,您应该确保一旦您不再需要它们就关闭所有流,否则您将收到内存泄漏。特别是,查找pInputStream关闭的位置,以及结果列表中所有InputStreams关闭的位置。