2

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

我想要类似于lseek(<fd>,0,SEEK_CUR)C 中的文件的东西。

编辑:我正在阅读一个文件LineNumberReader in = new LineNumberReader(new FileReader(file)),我希望能够不时打印“已处理 XX% 的文件”之类的内容。我知道的最简单的方法是查看第file.length()一个并将当前文件位置除以它。

4

2 回答 2

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 处理。您可以将 count 个字符放在 LineNumberReader 的子类中来解决这个问题。不幸的是,您不能轻易地生成百分比,因为与字节不同,没有便宜的方法可以知道文件中的字符数。
于 2012-06-18T01:45:28.493 回答
1

ByteCountingInputStream解决方案有一个缺点,它甚至在LineNumberReader处理输入字节之前就对其进行计数。这不是我的报告所需要的,我想出了一个替代方案。我假设输入文件是 ASCII 文本,带有 Unix 风格的行尾(单个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定义的方法,这些方法与我的目的无关。

于 2018-04-03T08:40:45.183 回答