How to use ProgressMonitorInputStream

前端 未结 2 1883
盖世英雄少女心
盖世英雄少女心 2020-12-12 00:08

I know I must be missing something very obvious, but whenever I try to use the ProgressMonitorInputStream when copying a file, I never get the ProgressDialog popup.

<
相关标签:
2条回答
  • 2020-12-12 00:19

    Your program works on files, but when it comes to server and client streams, it fails.

    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());
            } 
        }
    }
    
    0 讨论(0)
  • 2020-12-12 00:20

    You are calling copyFile from within the context of the Event Dispatching Thread, this means the EDT is unable to respond to new events or paint requests until after the method returns.

    Try placing the call within it's own Thread context...

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

    Equally, you could use a SwingWorker, it's a little bit of overkill, but you get the benefit of the PropertyChangeListener or it's done method, which could be used to re-enable the JButton, should you want to prevent people from clicking the button while a copy operation is in progress

    See Concurrency in Swing and Worker Threads and SwingWorker for more details

    Updated with example

    Copying a 371mb file, across the local disk...

    Copy

    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();
        }
    }
    

    Remember, there is overhead involved in setting up the window and displaying, which needs to be factored in. The system may "want" to display a window, but by the time the system has set it up and is prepared to display it, the steam may have finished copying...

    Extended Example

    nb: I don't really like the ProgressMonitor API as I've not been able to find where the UI is synchronised with the EDT, this can cause issues in Java 7 & 8

    You could formalise the idea into a self contained worker, for example...

    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) {
            }
        }
    
    }
    

    This attempts to contain the functionality, but also deals with the cleanup of the ProgressMonitorInputStream within the done method, making sure that it's done within the EDT. I'd personally attach a PropertyChangeListener to it and monitor the done property to determine when the worker has completed and examine the return result in order to pick up any exceptions, this gives you the ability to handle the exceptions in your own way and de-couples the worker from your process

    0 讨论(0)
提交回复
热议问题