Java Vaadin FileDropTarget糟糕的性能

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

我正在尝试将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.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/秒。我的朋友也试过同样的方法