Search code examples
javaswingworker

How to get the progress when copying a file using BufferedOutputStream & SwingWorker


I am copying a file from my computer to an external device, such as an SD card, and I would like to get the progress during the file copying process. I am using SwingWorker so that I can have multiple files copying at the same time. I am not sure how to get the current progress and send it to the SwingWorker publish() method. Here is my code to copy the file:

FileInputStream finStream = new FileInputStream(sourceFile);
FileOutputStream foutStream = new FileOutputStream(destFile);

/*
 * Adapted from http://www.java2s.com/Code/Java/File-Input Output/UseBufferedInputStreamandBufferedOutputStreamtocopybytearray.html
 */
BufferedInputStream bufIS = new BufferedInputStream(finStream);     
BufferedOutputStream bufOS = new BufferedOutputStream(foutStream);

byte[] byteBuff = new byte[32 * 1024];
int len;
while ((len = bufIS.read(byteBuff)) > 0){
    bufOS.write(byteBuff, 0, len);
    publish(/*What do I put here?*/);
}

bufIS.close();
bufOS.close();

Solution

  • Swingworker has already a "progress feature", use it instead of publish/process

    long size = file.length();
    
    int count = 0;
    int progress;
    while ((len = bufIS.read(byteBuff)) > 0) {
      ...
      count += len;
      if (size > 0L) {
        progress = (int) ((count * 100) / size);
        setProgress(progress);
      }
    }
    

    Then you can use worker.getProgress() in EDT or a PropertyChangeListener with a progressBar or whatever

    E.g:

    public class MyWorker extends SwingWorker<Void, Void> implements PropertyChangeListener {
    
        public MyWorker() {
          addPropertyChangeListener(this);
        }
    
        ....
        /* Your code */
        ....
    
       @Override
       public void propertyChange(PropertyChangeEvent evt) {
    
          if ("progress".equals(evt.getPropertyName())) {
            myProgressBar.setValue((Integer) evt.getNewValue());
          }
       }
    
    }
    

    Or

    MyWorker worker = new MyWorker();
    worker.addPropertyChangeListener(new PropertyChangeListener() {
    
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if ("progress".equals(evt.getPropertyName())) {
                myProgressBar.setValue((Integer) evt.getNewValue());
            }
        }
    }
    

    If you prefer publish/process then public class MyWorker extends SwingWorker<Void, Integer> and you will be able to call publish with an Integer