如何找出从流中读取了多少个字符或字节?

时间:2012-06-17 23:51:09

标签: java io

Java有LineNumberReader,它让我可以跟踪我所在的行,但是如何跟踪流中的字节(或字符)位置?

我希望C中的文件与lseek(<fd>,0,SEEK_CUR)类似。

编辑: 我正在使用LineNumberReader in = new LineNumberReader(new FileReader(file))阅读文件,我希望能够偶尔打印“处理文件的XX%”之类的内容。我知道最简单的方法是首先查看file.length()并按其划分当前文件位置。

2 个答案:

答案 0 :(得分:1)

我建议按如下方式扩展FilterInputStream

public class ByteCountingInputStream extends FilterInputStream {

    private long position = 0;

    protected ByteCountingInputStream(InputStream in) {
        super(in);
    }

    public long getPosition() {
        return position;
    }

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

    @Override
    public int read(byte[] b) throws IOException {
        int bytesRead = super.read(b);
        if (bytesRead > 0) {
            position += bytesRead;
        }
        return bytesRead;
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        int bytesRead = super.read(b, off, len);
        if (bytesRead > 0) {
            position += bytesRead;
        }
        return bytesRead;
    }

    @Override
    public long skip(long n) throws IOException {
        long skipped;
        skipped = super.skip(n);
        position += skipped;
        return skipped;
    }

    @Override
    public synchronized void mark(int readlimit) {
        return;
    }

    @Override
    public synchronized void reset() throws IOException {
        return;
    }

    @Override
    public boolean markSupported() {
        return false;
    }

}

你会像这样使用它:

File f = new File("filename.txt");
ByteCountingInputStream bcis = new ByteCountingInputStream(new FileInputStream(f));
LineNumberReader lnr = new LineNumberReader(new InputStreamReader(bcis));
int chars = 0;
String line;
while ((line = lnr.readLine()) != null) {
    chars += line.length() + 2;
    System.out.println("Chars read: " + chars);
    System.out.println("Bytes read: " + bcis.getPosition());
}

你会注意到一些事情:

  1. 此版本计算字节数,因为它实现了InputStream。
  2. 在客户端代码中自己计算字符或字节可能更容易。
  3. 此代码将在从文件系统读取到缓冲区后立即对字节进行计数,即使它们尚未由LineNumberReader处理。您可以将计数字符放在LineNumberReader的子类中,而不是解决这个问题。不幸的是,你不能轻易地产生一个百分比,因为与字节不同,没有廉价的方法来知道文件中的字符数。

答案 1 :(得分:1)

ByteCountingInputStream 解决方案的缺点是,即使在 LineNumberReader 处理之前,它也会对输入字节进行计数。这不是我报告所需要的,我想出了一个替代方案。我假设输入文件是带有Unix样式行结尾的ASCII文本(单个 LF 字符)。

我已经构建了 LineNumberReader 的子集,可以添加位置报告:

import java.io.*;

public class FileLineNumberReader {
    private final LineNumberReader lnr;
    private final long length;
    private long pos;

    public FileLineNumberReader(String path) throws IOException {
        lnr = new LineNumberReader(new FileReader(path));
        length = new File(path).length();
    }

    public long getLineNumber() {
        return lnr.getLineNumber();
    }

    public String readLine() throws IOException {
        String res = lnr.readLine();
        if (res != null) {
            pos += res.length() + 1;
        }
        return res;
    }

    public long getPercent() {
        return 100*pos/length;
    }
}

请注意,此类隐藏了为封装的 LineNumberReader 定义的许多方法,这些方法与我的目的无关。