How do I track reading of a a file using .readLine

2019-09-19 02:53发布

问题:

I am reading a file using bufferedREader ,the file is a text file with lot of text

here is how I am reading it

 while(true)  //I know the loop is not perfect just ignore it for now, i wanna concentrate on the tracking
                {
                      try
                      {
                       br.readLine();
                      }
                      catch(IOException e)
                      {
                      break;
                      }
                      catch (Exception e)
                      {
                      break;
                      }
                }

I want to track what percentage of the file I have read so I can use that percentage value in my progress bar like this:

while(true)
                {
                      try
                      {
                       br.readLine();
                       progressBar.setValue(percentageRead);//how do I get percentageRead value dynamically?
                      }
                      catch(IOException e)
                      {
                      break;
                      }
                      catch (Exception e)
                      {
                      break;
                      }
                }

回答1:

There are any number ways to achieve this, but you need to keep four things in mind...

  1. You need to know how much you are reading
  2. You need to know how much you have read
  3. You should never performing any action within context of the Event Dispatching Thread that might block it (such as long running loops or blocking I/O)
  4. You should never modify or change the state of the UI from any thread other then the Event Dispatching Thread

This example simply uses a SwingWorker to read the file in a background thread and uses it's progress functionality to post updates back to the context of the EDT.

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ReadFile {

    public static void main(String[] args) {
        new ReadFile();
    }

    public ReadFile() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                final JProgressBar pb = new JProgressBar(0, 100);
                final ReadFileWorker worker = new ReadFileWorker();
                worker.addPropertyChangeListener(new PropertyChangeListener() {
                    @Override
                    public void propertyChange(PropertyChangeEvent evt) {
                        if ("progress".equalsIgnoreCase(evt.getPropertyName())) {
                            pb.setValue(worker.getProgress());
                        }
                    }
                });

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new GridBagLayout());
                frame.add(pb);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                worker.execute();
            }
        });
    }

    public class ReadFileWorker extends SwingWorker<List<String>, String> {

        @Override
        protected List<String> doInBackground() throws Exception {
            List<String> lines = new ArrayList<>(25);
            File textFile = new File("Test.txt");
            long byteLength = textFile.length();

            System.out.println("Reading " + byteLength + " bytes...");

            try (InputStream is = new FileInputStream(textFile)) {

                byte[] content = new byte[1024];
                int bytesRead = -1;
                long totalBytes = 0;
                String lastText = "";
                while ((bytesRead = is.read(content)) != -1) {

                    totalBytes += bytesRead;
                    setProgress(Math.round(((float) totalBytes / (float) byteLength) * 100f));

                    String text = lastText + new String(content);
                    boolean keepEnd = !text.endsWith("\n");
                    String[] parts = text.split("\n");

                    for (int count = 0; count < (keepEnd ? parts.length - 1 : parts.length); count++) {
                        lines.add(parts[count]);
                        publish(parts[count]);
                    }

                    if (keepEnd) {
                        lastText = parts[parts.length - 1];
                    } else {
                        lastText = "";
                    }

                    // This is only here to slow the demonstration down
                    Thread.sleep(5);

                }

                System.out.println("Read " + totalBytes + " bytes...");
                System.out.println("Read " + lines.size() + " lines...");

            } finally {

            }

            return lines;
        }

        @Override
        protected void done() {
            try {
                List<String> lines = get();
            } catch (InterruptedException | ExecutionException ex) {
                ex.printStackTrace();
            }
        }

    }

}

Now, you could incorporate the SwingWorker with one of the other "ProgressInputStream" implementations as well. Take a look at Concurrency in Swing for more details



回答2:

Use a FileInputStream, javax.swing.ProgressMonitorInputStream, InputStreamReader, and a BufferedReader. Then it all happens automatically.



回答3:

Easy

private class myProgressBar{
     private int read;

     //override constructor and such... 

     @Override 
     public int read(byte[] data, int offset, int length) throws IOException
      {
        int t = super.read(data, offset, length);
        if ( t > 0 )
        {
         read += t;
        }
        return t;
       }

  }

then just use standard getter methods. You can get maximum by using myInputStream.availble();

link to relevant source code: http://developer.classpath.org/doc/javax/swing/ProgressMonitorInputStream-source.html



回答4:

As a quick 'hack' you can implement a counting FilterInputStream, and use it in a way that EJP suggests:

public class ProgressInputStream extends FilterInputStream {

    private final double maxbytes;
    private long current = 0;

    public ProgressInputStream(InputStream in, long bytestoexpect) {
        super(in);
        maxbytes = (double)bytestoexpect;
    }

    /**
     * return a value between 0.0 and 1.0 to represent the progress.
     * should do some division-by-zero checking here too.
     */
    public double getProgress() {
        return current / maxbytes;
    }

    @Override
    public int read() throws IOException {
        final int ret = super.read();
        if (ret >= 0) {
            current++;
        }
        return ret;
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        final int ret = super.read(b, off, len);
        current += ret;
        return ret;
    }

    @Override
    public int read(byte[] b) throws IOException {
        // TODO Auto-generated method stub
        final int ret = super.read(b);
        current += ret;
        return ret;
    }

    @Override
    public long skip(long n) throws IOException {
        final long ret = super.skip(n);
        current += ret;
        return ret;
    }

}

Then, your code can do:

final File infile = new File("path/to/file");
final long insize = infile.length();
final ProgresInputStream pis = new ProgressInputStream(new FileInputStream(infile), insize);
BufferedReader br = new BufferedReader(new InputStreamReader(pis));
String line = null;
try {
    while((line = br.readLine()) != null) {
        final int pct = (int)(pis.getProgress() * 100.0);
        // assume progressbar is final, etc.
        SwingUtilities.invokeLater(new Runnable() {
           public void run() {
                progressBar.setValue(pct);
           }
        });
    }
} catch(IOException e) {
    // do proper handling here.....
}