5

我想逐行读取文件。BufferedReader 比 RandomAccessFile 或 BufferedInputStream 快得多。但问题是我不知道我读了多少字节。如何知道读取的字节数(偏移量)?我试过了。

String buffer;
int offset = 0;

while ((buffer = br.readLine()) != null)
    offset += buffer.getBytes().length + 1; // 1 is for line separator

如果文件很小,我可以工作。但是,当文件变大时,偏移量会小于实际值。我怎样才能得到抵消?

4

5 回答 5

8

BufferedReader由于两种影响,没有简单的方法可以做到这一点:字符结尾编码和行结尾。在 Windows 上,行尾\r\n是两个字节。在 Unix 上,行分隔符是一个字节。BufferedReader将在您不注意的情况下处理这两种情况,因此在 之后readLine(),您将不知道跳过了多少字节。

buffer.getBytes()仅当您的默认编码和文件中数据的编码意外碰巧相同时才返回正确的结果。当使用任何类型的byte[]<->String转换时,您应该始终准确地指定应该使用哪种编码。

您也不能使用计数InputStream,因为缓冲读取器以大块读取数据。因此,在读取第一行(例如 5 个字节)后,内部计数器InputStream将返回 4096,因为读取器总是将那么多字节读入其内部缓冲区。

你可以看看NIO。您可以使用低级别ByteBuffer来跟踪偏移量并将其包装在 aCharBuffer中以将输入转换为行。

于 2013-02-26T15:43:37.237 回答
1

这是应该起作用的东西。它假定为 UTF-8,但您可以轻松更改它。

import java.io.*;

class main {
    public static void main(final String[] args) throws Exception {
        ByteCountingLineReader r = new ByteCountingLineReader(new ByteArrayInputStream(toUtf8("Hello\r\nWorld\n")));

        String line = null;
        do {
            long count = r.byteCount();
            line = r.readLine();
            System.out.println("Line at byte " + count + ": " + line);
        } while (line != null);

        r.close();
    }

    static class ByteCountingLineReader implements Closeable {
        InputStream in;
        long _byteCount;
        int bufferedByte = -1;
        boolean ended;

        // in should be a buffered stream!
        ByteCountingLineReader(InputStream in) {
            this.in = in;
        }

        ByteCountingLineReader(File f) throws IOException {
            in = new BufferedInputStream(new FileInputStream(f), 65536);
        }

        String readLine() throws IOException {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            if (ended) return null;
            while (true) {
                int c = read();
                if (ended && baos.size() == 0) return null;
                if (ended || c == '\n') break;
                if (c == '\r') {
                    c = read();
                    if (c != '\n' && !ended)
                        bufferedByte = c;
                    break;
                }
                baos.write(c);
            }
            return fromUtf8(baos.toByteArray());
        }

        int read() throws IOException {
            if (bufferedByte >= 0) {
                int b = bufferedByte;
                bufferedByte = -1;
                return b;
            }
            int c = in.read();
            if (c < 0) ended = true; else ++_byteCount;
            return c;
        }

        long byteCount() {
            return bufferedByte >= 0 ? _byteCount - 1 : _byteCount;
        }

        public void close() throws IOException {
            if (in != null) try {
                in.close();
            } finally {
                in = null;
            }
        }

        boolean ended() {
            return ended;
        }
    }

    static byte[] toUtf8(String s) {
        try {
            return s.getBytes("UTF-8");
        } catch (Exception __e) {
            throw rethrow(__e);
        }
    }

    static String fromUtf8(byte[] bytes) {
        try {
            return new String(bytes, "UTF-8");
        } catch (Exception __e) {
            throw rethrow(__e);
        }
    }

    static RuntimeException rethrow(Throwable t) {

        throw t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t);
    }
}
于 2018-04-15T11:16:13.490 回答
0

尝试使用RandomAccessFile

     RandomAccessFile raf = new RandomAccessFile(filePath, "r");
     while ((cur_line = raf.readLine()) != null){
        System.out.println(curr_line);
        // get offset
        long rowIndex = raf.getFilePointer();
     }

通过偏移量寻找:

raf.seek(offset);

于 2019-01-02T14:18:31.357 回答
-1

我想知道您的最终解决方案,但是,我认为使用 long 类型而不是 int 可以满足上述代码中的大多数情况。

于 2017-05-23T02:11:22.693 回答
-3

如果您想逐行读取文件,我会推荐以下代码:

import java.io.*;
class FileRead 
{
 public static void main(String args[])
  {
  try{
  // Open the file that is the first 
  // command line parameter
  FileInputStream fstream = new FileInputStream("textfile.txt");
  // Use DataInputStream to read binary NOT text.
  BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
  String strLine;
  //Read File Line By Line
  while ((strLine = br.readLine()) != null)   {
  // Print the content on the console
  System.out.println (strLine);
  }
  //Close the input stream
  in.close();
    }catch (Exception e){//Catch exception if any
  System.err.println("Error: " + e.getMessage());
  }
  }
}

我过去一直使用这种方法,效果很好!

来源:这里

于 2013-02-26T15:30:38.767 回答