如何使用ProgressMonitorInputStream

我知道我必须遗漏一些非常明显的东西,但每当我在复制文件时尝试使用ProgressMonitorInputStream时,我都不会得到ProgressDialog弹出窗口。

我看到的示例除了在ProgressMonitorInputStream中包装其输入流之外似乎没有做太多其他事情。

文档说:

这将创建一个进度监视器来监视读取输入流的进度。 如果需要一段时间,将弹出ProgressDialog以通知用户。 如果用户点击取消按钮,则下次读取时将抛出InterruptedIOException。 当流关闭时,完成所有正确的清理。

这是一个非常简单的例子,即使我将setMillisToPopup()为一个非常小的数字,我也不会弹出带有大文件的对话框。

 import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.ProgressMonitorInputStream; import javax.swing.SwingWorker; public class ProgressBarDemo extends JFrame { private static final long serialVersionUID = 1L; private JButton button; ProgressBarDemo() { button = new JButton("Click me!"); ButtonActionListener bal = new ButtonActionListener(); button.addActionListener(bal); this.getContentPane().add(button); } private class ButtonActionListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub Worker worker = new Worker(); worker.execute(); button.setEnabled(false); } } public void go() { this.setLocationRelativeTo(null); this.setVisible(true); this.pack(); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } private class Worker extends SwingWorker { private void copyFile() { File file = new File("/Users/mypath/Desktop/WirelessDiagnostics.tar.gz"); BufferedInputStream bis; BufferedOutputStream baos; try { bis = new BufferedInputStream(new FileInputStream(file)); ProgressMonitorInputStream pmis = new ProgressMonitorInputStream( ProgressBarDemo.this, "Reading... " + file.getAbsolutePath(), bis); pmis.getProgressMonitor().setMillisToPopup(10); baos = new BufferedOutputStream(new FileOutputStream("/Users/mypath/Desktop/NewWirelessDiagnostics.tar.gz")); byte[] buffer = new byte[2048]; int nRead = 0; while((nRead = pmis.read(buffer)) != -1) { baos.write(buffer, 0, nRead); } pmis.close(); baos.flush(); baos.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override protected Void doInBackground() throws Exception { // TODO Auto-generated method stub copyFile(); return null; } @Override protected void done() { button.setEnabled(true); } } } public class TestProj { public static void main(String[] args) { ProgressBarDemo demo = new ProgressBarDemo(); demo.go(); } } 

有什么建议么?

您正在Event Dispatching Thread的上下文中调用copyFile ,这意味着在方法返回之前,EDT无法响应新事件或绘制请求。

尝试将调用放在它自己的Thread上下文中……

 Thread t = new Thread(new Runnable( public void run() { copyFile(); } )); t.start(); 

同样,你可以使用SwingWorker ,这有点过分,但你可以获得PropertyChangeListener或它的done方法的好处,如果你想阻止人们点击按钮,它可以用来重新启用JButton复制操作正在进行中

有关更多详细信息,请参阅Swing和工作线程中的 并发 和SwingWorker

更新了示例

在本地磁盘上复制371mb文件…

复制

 import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.ProgressMonitorInputStream; import javax.swing.SwingWorker; public class ProgressBarDemo extends JFrame { private static final long serialVersionUID = 1L; private JButton button; ProgressBarDemo() { button = new JButton("Click me!"); ButtonActionListener bal = new ButtonActionListener(); button.addActionListener(bal); this.getContentPane().add(button); } public void go() { this.setLocationRelativeTo(null); this.setVisible(true); this.pack(); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } private void copyFile() { File file = new File("..."); BufferedInputStream bis; BufferedOutputStream baos; try { bis = new BufferedInputStream(new FileInputStream(file)); ProgressMonitorInputStream pmis = new ProgressMonitorInputStream( this, "Reading... " + file.getAbsolutePath(), bis); pmis.getProgressMonitor().setMillisToPopup(10); baos = new BufferedOutputStream(new FileOutputStream("...")); byte[] buffer = new byte[2048]; int nRead = 0; while ((nRead = pmis.read(buffer)) != -1) { baos.write(buffer, 0, nRead); } pmis.close(); baos.flush(); baos.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private class ButtonActionListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { button.setEnabled(false); SwingWorker worker = new SwingWorker() { @Override protected Object doInBackground() throws Exception { copyFile(); return null; } @Override protected void done() { button.setEnabled(true); } }; worker.execute(); } } public static void main(String[] args) { ProgressBarDemo demo = new ProgressBarDemo(); demo.go(); } } 

请记住,设置窗口和显示需要花费开销,需要将其考虑在内。系统可能“想要”显示一个窗口,但是当系统设置好并准备显示它时,蒸汽可能已完成复制……

扩展示例

nb:我不太喜欢ProgressMonitor API,因为我无法找到UI与EDT同步的位置,这可能会导致Java 7和8中出现问题

你可以将这个想法forms化为一个自成一体的工人,例如……

 public class CopyWorker extends SwingWorker { private File source; private File dest; private Component parent; private ProgressMonitorInputStream pmis; public CopyWorker(Component parent, File source, File dest) { this.parent = parent; this.source = source; this.dest = dest; } @Override protected Object doInBackground() throws Exception { try (InputStream is = new FileInputStream(source)) { try (OutputStream os = new FileOutputStream(dest)) { pmis = new ProgressMonitorInputStream( parent, "Copying...", is); pmis.getProgressMonitor().setMillisToPopup(10); byte[] buffer = new byte[2048]; int nRead = 0; while ((nRead = pmis.read(buffer)) != -1) { os.write(buffer, 0, nRead); } } } return null; } @Override protected void done() { try { pmis.close(); } catch (Exception e) { } } } 

这会尝试包含该function,但也会在done方法中处理ProgressMonitorInputStream的清理,确保它在EDT中完成。 我个人将一个PropertyChangeListener附加到它并监视done属性以确定worker何时完成并检查返回结果以便获取任何exception,这使您能够以自己的方式处理exception并且将工人与您的过程结合起来

您的程序适用于文件,但是当涉及到服务器和客户端流时,它会失败。

 import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.Socket; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JProgressBar; import javax.swing.ProgressMonitorInputStream; import javax.swing.SwingWorker; public class FileReceive extends JFrame { private static final long serialVersionUID = 1L; private BufferedInputStream bufferInput; private FileOutputStream fout; private BufferedOutputStream bufferOutput; private Socket client; private JButton button; private File fileinfo; ProgressMonitorInputStream pois; FileReceive() { setLocationRelativeTo(null); setVisible(true); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); pack(); receiveFile(); } public static void main(String arg[]) { new FileReceive(); } public void receiveFile() { try { fileinfo=new File(filepath); client=new Socket("localhost",9090); fout=new FileOutputStream(fileinfo); bufferOutput=new BufferedOutputStream(fout); bufferInput=new BufferedInputStream(client.getInputStream()); pois=new ProgressMonitorInputStream(this, "reading", bufferInput); int ch; byte[] b=new byte[2048]; System.out.println("Receiving File"); while(-1!=(ch=pois.read(b))) { bufferOutput.write(b,0,ch); } pois.close(); bufferInput.close(); bufferOutput.close(); fout.close(); client.close(); } catch (IOException e) { JOptionPane.showMessageDialog(null, e.getMessage()); } } }