简体   繁体   中英

How to get the progress of reading a file

I'm trying to read a large object from a file in my application. Since this can take some time I'd like to somehow connect the reading of the file with a JProgressBar. Is there any easy way to find the progress of reading a file? (The loading itself is done in a swingworker thread so updating a progress bar should not be a problem.) I've been thinking about overriding the readByte() method in the FileInputStream to return a progress value of sorts but that seems such a devious way. Any suggestions on how to realize this are more than welcome.

Here is the code for reading the file:

public class MapLoader extends SwingWorker<Void, Integer> {

String path;
WorldMap map;

public void load(String mapName) {
    this.path = Game.MAP_DIR + mapName + ".map";
    this.execute();
}

public WorldMap getMap() {
    return map;
}

@Override
protected Void doInBackground() throws Exception {
    File f = new File(path);
    if (! f.exists())
        throw new IllegalArgumentException(path + " is not a valid map name.");
    try {
        FileInputStream fs = new FileInputStream(f);
        ObjectInputStream os = new ObjectInputStream(fs);
        map = (WorldMap) os.readObject();
        os.close();
        fs.close();
    } catch (IOException | ClassCastException | ClassNotFoundException e) {
        e.printStackTrace();
    }
    return null;
}

@Override
protected void done() {
    firePropertyChange("map", null, map);
}
}

If it were me, I would not mess with overriding FileInputStream. I think the decorator might be a good fit here. The idea is you create a decorator input stream that you pass to your ObjectInputStream. The decorator takes care of updating the progress of your read, then delegates to the real input stream.

Perhaps the easiest solution is to use CountingInputStream from Apache commons-io . The basic steps would be:

  • Create subclass of CountingInputStream as a non-static inner class of your map loader
  • Override the afterRead method. Call super.afterRead, then publish your updated status
  • Pass an instance of your new decorator input stream to output stream, passing the file input stream to the constructor of your decorator

Using RandomAccessFile you may call getFilePointer() to known how many bytes was read.

Time consuming operation may be executed in a background thread, remember using SwingUtilities.invokeLater() to communicate between background task and GUI threads.

If you are considering to override read() in FileInputStream , what you could legitimately consider is making your own wrapper InputStream class that accepts a progress-monitor callback. However, you'll find out that it not as easy as implementing read() since it is very inefficient to spend a method invocation for each byte. Instead you'll need to deal with read(byte[], int, int) , which is a bit more involved.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM