Snedden27
Snedden27

Reputation: 1930

How do I track reading of a a file using .readLine() in java?

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

Upvotes: 0

Views: 2176

Answers (4)

rolfl
rolfl

Reputation: 17707

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.....
}

Upvotes: 0

MadProgrammer
MadProgrammer

Reputation: 347314

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

Upvotes: 2

Skylion
Skylion

Reputation: 2752

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

Upvotes: 0

user207421
user207421

Reputation: 311023

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

Upvotes: 3

Related Questions