FileInputStream / FileOutputStream blocking?

I have the following code which successfully copies a file. However, there are two problems with it:

  1. The System.out.println() immediately after the progressBar.setValue() does not print intervals between 0 and 100 (just prints "0" till the end where it prints "100")
  2. Besides the fact that the value for the progress bar might be wrong somehow due to question #1, in the actual code I am making other visual changes too, but they don't show until the entire file is processed. I thought the FileInputStream/FileOutputStream functions were non-blocking. How can I change the following code so that the progress bar is in fact updated during the operation?

startJob method:

private void startJob(File inFile, File outFile) {
        long offset = 0;
        int numRead = 0;
        byte[] bytes = new byte[8192];
        long fileLength = inFile.length();
        Boolean keepGoing = true;

        progressBar.setValue(0);

        try {
            inputStream = new FileInputStream(inFile);
            outputStream = new FileOutputStream(outFile, false);
            System.out.println("Total file size to read (in bytes) : " + inputStream.available());
        } catch (FileNotFoundException err) {
            inputStream = null;
            outputStream = null;
            err.printStackTrace();
        } catch (IOException err) {
            inputStream = null;
            outputStream = null;
            err.printStackTrace();
        }

        if (inputStream != null && outputStream != null) {
            while (keepGoing) {
                try {
                    numRead = inputStream.read(bytes);
                    outputStream.write(bytes, 0, numRead);
                } catch (IOException err) {
                    keepGoing = false;
                    err.printStackTrace();
                }
                if (numRead > 0) {
                    offset += numRead;
                }

                if (offset >= fileLength) {
                    keepGoing = false;
                }

                progressBar.setValue(Math.round(offset / fileLength) * 100);
                System.out.println(Integer.toString(Math.round(offset / fileLength) * 100));
            }
        }
        if (offset < fileLength) {
            //error
        } else {
            //success
        }

        try {
            inputStream.close();
            outputStream.close();
        } catch (IOException err) {
            err.printStackTrace();
        }
    }

Answers


I suspect you are calling your lengthy method from the EDT. Remove your operation from the EDT by placing it in it's own Runnable for instance and then call

SwingUtilities.invokeLater(new Runnable() {

    @Override
    public void run() {
        progressBar.setValue(value);
        // or any other GUI changes you want to make
    }       
});

Otherwise, your operation blocks the EDT until it is done, and with the EDT blocked no events like repaint etc will can be processed -> no GUI changes visible until the end.


The value of expression Math.round(offset / fileLength) will always equal 0 (zero), because offset < fileLength.

UPD:

If you want to do this calculation correctly, you have to change it to:

Math.round(((double)offset / (double)fileLength) * 100)

Need Your Help

Understanding the job of routes in Node.js (api) when utilizing Backbone.js (frontend)

node.js backbone.js routing routes views

I am just beginning to learn using Backbone.js. Previously I have used a web framework built on top of Node.js to handle all the routes and responses. With Backbone is the possibility of a SPA (sin...

Android : map : how to alert when Current Location is out of screen

android map currentlocation

How can I find out, in an Android app, whether the "current location" marker shown on the map is outside the bounds of the currently displayed map?