我使用Jersey将文件上传到我的应用程序进行处理。我实现了一个用于上传TXT和CSV文件的版本。但是当我上传一个XLS文件时,我得到了这个:
Exception in thread "Thread-12" org.jvnet.mimepull.MIMEParsingException: java.io.IOException: Stream Closed
我使用ApachePOI来读取文件,但即使在xls
方法中,如果我检查流中有多少字节可用,我也会得到零。我正在测试的文件中肯定有数据,并且是一个有效的XLS文件,但我不能理解为什么它认为流已关闭。
我的xls
方法如下:
@POST
@NewUpload
@Path(FILE_PATH)
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN)
@AccessLog
public Response xls(
@QueryParam(USER_PARAM) final String userID,
@FormDataParam(FILE_PARAM) final InputStream upload,
@FormDataParam(FILE_PARAM) final FormDataContentDisposition detail,
@FormDataParam(TYPE_PARAM) final String type)
{
try {
System.out.println("Available bytes " + upload.available());
} catch (IOException e) {
System.out.println(ExceptionUtils.getFullStackTrace(e));
}
return upload(userID, upload, detail, type);
} //xls
TXT和CSV的方法完全相同,只是设置为不同的地址,方法upload(userID, upload, detail, type)
适当地处理不同的流。
有没有办法重置流,以便我可以在此之后正确读取它?或者有不同的方式来读取XLS文件?
另外对于大文件来说,最好采用另一种方式,即从上传文件保存到磁盘然后读取它?
提前致谢, 阿列克谢蓝。
编辑1:
我添加了一个对IOUtils的调用,以便在xls
方法中读取一些Stream,并设法读取大量字节,因此我猜测Stream正被其他东西关闭。
byte [] buffer = new byte[10000];
try {
System.out.println("Bytes read " + IOUtils.read(upload, buffer));
} catch (IOException e) {
System.out.println(ExceptionUtils.getFullStackTrace(e));
}
我会尝试创建一个单元测试来模拟发生了什么,这样我就可以看到流的关闭位置。
编辑2: 客户端是作为前端Web应用程序编写的,用冷融合编写:
<cfoutput>
<legend>Upload File</legend>
<div id ="uploadfile">
<form class = "form-horizontal" id="upload_file_form" method="post" name="upload_file">
<div class="control-group">
<label class="control-label">File To Upload</label>
<div class="controls">
<input id="filetoupload" class="filetoupload" type="file" name="file">
</div>
</div>
<div class="control-group">
<input type="button"
value="Submit"
name="submit"
class="btn btn-success"
id="submit"
onclick="doUpload(upload_file_form);" />
</div>
</form>
</div>
</cfoutput>
doUpload
脚本:
function doUpload(form) {
var id = $('[name="id"]').val();
var fileExtension = getFileExtension(form);
$.ajax({
type: "POST",
data: new FormData(form),
processData: false,
contentType: false,
url: "/application/rest/upload/" + fileExtension + "/file/?id=" + id,
success:function(data) {
// get the upload id
var uploadID = data;
window.location ="index.cfm?controller=project&action=status&id=" + id + "&uploadID='" + uploadID + "'";
}
});
}
目前我在组件测试中运行上传,这让我意识到文件的标题已被读取,但组件测试中的文件属于BufferedInputStream
类型但运行代码时的流来自客户端是org.jvnet.mimepull.DataHead$ReadMultiStream
所以它可能是mimepull依赖的一个问题,任何想法?
干杯, 阿列克谢蓝。
编辑3:我想我发现了这个问题。在我的上传方法中,我在另一个线程中关闭了该过程,以确保请求不会等待。 Jersey必须在从方法返回时关闭流,并且CSV和TXT是非常简单的文件类型,它们必须在返回起始线程之前在线程中处理。我明天需要确认这一点,因为我今天已经没时间了,但我一定要发布结果。上传方法如下:
protected Response upload(
final String id,
final InputStream input,
final FormDataContentDisposition detail,
final String type)
{
String id = UUIDs.timeBased().toString();
factory
.set(id, uploadID)
.setFilename(detail.getFileName())
.setType(type);
new Thread(new Runnable()
{
@Override
public void run()
{
upload.process(input);
} //run
}).start();
return Response.ok(uploadID).build();
} //upload
答案 0 :(得分:0)
原来Jersey正在关闭流,所以我不能只是启动一个新线程将处理部分放到后台。这不是问题,因为可以通过轮询状态URL来获取上载状态,这样用户仍然可以在AJax界面中获得响应。
新的上传方法,即没有线程。
protected Response upload(
final String id,
final InputStream input,
final FormDataContentDisposition detail,
final String type)
{
String id = UUIDs.timeBased().toString();
factory
.set(id, uploadID)
.setFilename(detail.getFileName())
.setType(type);
upload.process(input);
return Response.ok(uploadID).build();
} //upload