Java Vaadin FileDropTarget糟糕的性能
我正在尝试将Vaadin 8 FileDropTarget与Tomcat服务器一起使用。示例代码有点长,但可能适合这里:Java Vaadin FileDropTarget糟糕的性能,java,performance,tomcat,streaming,vaadin8,Java,Performance,Tomcat,Streaming,Vaadin8,我正在尝试将Vaadin 8 FileDropTarget与Tomcat服务器一起使用。示例代码有点长,但可能适合这里: import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.OutputStream; import com.vaadin.server.StreamVariable; import com.vaadin.ui.Alignment; import com.vaad
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import com.vaadin.server.StreamVariable;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Label;
import com.vaadin.ui.Notification;
import com.vaadin.ui.ProgressBar;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.dnd.FileDropTarget;
import hu.dynaxpress.base.mvc.DynaAbstractController;
@SuppressWarnings({ "serial", "rawtypes" })
public class FileStreamController extends DynaAbstractController {
private VerticalLayout layout;
private ProgressBar progress;
@Override
protected void onInit() {
super.onInit();
System.err.println("FileStreamController.onInit");
}
@Override
protected void onEnter() {
System.err.println("FileStreamController.onEnter");
// https://vaadin.com/docs/v8/framework/components/components-upload.html
layout = new VerticalLayout();
final Label infoLabel = new Label("DROP A FILE ON THIS TEXT");
infoLabel.setWidth(240.0f, Unit.PIXELS);
final VerticalLayout dropPane = new VerticalLayout(infoLabel);
dropPane.setComponentAlignment(infoLabel, Alignment.MIDDLE_CENTER);
dropPane.addStyleName("drop-area");
dropPane.setSizeUndefined();
dropPane.setWidth("100%");
progress = new ProgressBar();
progress.setIndeterminate(false);
progress.setVisible(false);
progress.setWidth("100%");
dropPane.addComponent(progress);
layout.addComponent(dropPane);
new FileDropTarget<>(dropPane, fileDropEvent -> {
final long fileSizeLimit = 20 * 1024 * 1024 * 1024; // 20GB
fileDropEvent.getFiles().forEach(html5File -> {
// html5File.getFileSize() always returns zero, but why?
if (false && ( html5File.getFileSize() > fileSizeLimit) ) {
Notification.show(
"File rejected. Max size=" +fileSizeLimit+ ", actual="+html5File.getFileSize(),
Notification.Type.WARNING_MESSAGE);
} else {
Label lbl = new Label(html5File.getFileName() + " size=" + html5File.getFileSize() + " " + html5File.getType());
lbl.setWidth("100%");
layout.addComponent(lbl);
final StreamVariable streamVariable = new StreamVariable() {
@Override
public OutputStream getOutputStream() {
try {
return new FileOutputStream("F:\\"+html5File.getFileName());
} catch (FileNotFoundException e) {
e.printStackTrace();
throw new Error("F:\\"+html5File.getFileName());
}
}
@Override
public boolean listenProgress() { return false; }
@Override
public void onProgress(final StreamingProgressEvent event) {
progress.setValue(
event.getBytesReceived() / event.getContentLength()
);
}
@Override
public void streamingStarted(
final StreamingStartEvent event) {
progress.setVisible(true);
progress.setCaption(event.getFileName());
}
@Override
public void streamingFinished(
final StreamingEndEvent event) {
progress.setVisible(false);
}
@Override
public void streamingFailed(final StreamingErrorEvent event) {
progress.setVisible(false);
}
@Override
public boolean isInterrupted() { return false; }
};
html5File.setStreamVariable(streamVariable);
progress.setVisible(true);
}
});
});
setCompositionRoot(layout);
}
}
import java.io.FileNotFoundException;
导入java.io.FileOutputStream;
导入java.io.OutputStream;
导入com.vaadin.server.StreamVariable;
导入com.vaadin.ui.Alignment;
导入com.vaadin.ui.Label;
导入com.vaadin.ui.Notification;
导入com.vaadin.ui.ProgressBar;
导入com.vaadin.ui.VerticalLayout;
导入com.vaadin.ui.dnd.FileDropTarget;
导入hu.dynaxpress.base.mvc.DynaAbstractController;
@SuppressWarnings({“serial”、“rawtypes”})
公共类FileStreamController扩展DynaAbstractController{
私人垂直布局;
私人进度条进度;
@凌驾
受保护的void onInit(){
super.onInit();
System.err.println(“FileStreamController.onInit”);
}
@凌驾
受保护的void onEnter(){
System.err.println(“FileStreamController.oneter”);
// https://vaadin.com/docs/v8/framework/components/components-upload.html
布局=新的垂直布局();
最终标签infoLabel=新标签(“在此文本上放置文件”);
设置宽度(240.0f,单位像素);
最终垂直布局下拉窗格=新垂直布局(信息标签);
dropPane.setComponentAlignment(信息标签,Alignment.MIDDLE_CENTER);
dropPane.addStyleName(“放置区域”);
dropPane.setSizeUndefined();
dropPane.setWidth(“100%”);
进度=新的进度条();
进度。设置不确定(false);
进度。setVisible(false);
进度。设置宽度(“100%”);
dropPane.addComponent(进度);
layout.addComponent(dropPane);
新的FileDropTarget(dropPane、fileDropEvent->{
最终长文件大小限制=20*1024*1024*1024;//20GB
fileDropEvent.getFiles().forEach(HTML5文件->{
//html5File.getFileSize()总是返回零,但为什么?
if(false&(html5File.getFileSize()>fileSizeLimit)){
通知.显示(
“文件被拒绝。Max size=“+fileSizeLimit+”,actual=“+html5File.getFileSize(),
通知。类型。警告消息);
}否则{
Label lbl=新标签(html5File.getFileName()+“size=“+html5File.getFileSize()+”“+html5File.getType());
lbl.设置宽度(“100%”);
布局。添加组件(lbl);
最终StreamVariable StreamVariable=新StreamVariable(){
@凌驾
public OutputStream getOutputStream(){
试一试{
返回新的FileOutputStream(“F:\\”+html5File.getFileName());
}catch(filenotfounde异常){
e、 printStackTrace();
抛出新错误(“F:\\”+html5File.getFileName());
}
}
@凌驾
公共布尔listenProgress(){return false;}
@凌驾
public void onProgress(最终StreamingProgressEvent事件){
progress.setValue(
event.getBytesReceived()/event.getContentLength()
);
}
@凌驾
公共空间开始流动(
最终StreamingStartEvent(事件){
进度。setVisible(true);
progress.setCaption(event.getFileName());
}
@凌驾
公共空间流线化完成(
最终StreamingEndEvent事件){
进度。setVisible(false);
}
@凌驾
public void streamingFailed(最终StreamingErrorEvent事件){
进度。setVisible(false);
}
@凌驾
公共布尔值isInterrupted(){return false;}
};
html5File.setStreamVariable(streamVariable);
进度。setVisible(true);
}
});
});
setCompositionRoot(布局);
}
}
这段代码可以工作,但它的性能非常糟糕。在此MWE中,程序将所有丢弃的文件写入F:\驱动器。它是一个闪存驱动器(我想模拟大文件流,看看随着时间的推移消耗了多少内存)。但是我发现这个程序在20秒内写出一个40MB的文件。这是2MB/秒的速度。服务器在localhost上运行,源文件和目标F:drive都在我的本地计算机上。如果我只是简单地将同一个文件复制到驱动器上,则所需时间不到2秒
我也尝试过另一个(速度非常慢的)闪存驱动器,也得到了类似的结果。当tomcat对文件进行流式传输时,速度大约慢10-20倍
有没有办法让这更快?我做错了什么?我看不到任何加速的方法,因为流发生在组件内部
第二个重要的(没有相关的)问题是,为什么我不能获得文件大小?请参阅代码中的注释:“html5File.getFileSize()总是返回零,但为什么?”我已经检查了firefox调试器中的POST头,浏览器在发送实际文件数据之前以JSON/RPC调用发送文件大小。因此,服务器应该在第一个字节到达之前知道文件大小。还尝试在硬盘上写入1.5GB文件。Vaadin+Tomcat的速度为16.6MB/s。一个简单的拷贝速度为106MB/秒。我的朋友也试过同样的方法