0

我有一个文件,它被“\n\n”分成两部分——第一部分不是太长的字符串,第二部分是字节数组,它可能很长。

我正在尝试按如下方式读取文件:

    byte[] result;
    try (final FileInputStream fis = new FileInputStream(file)) {

        final InputStreamReader isr = new InputStreamReader(fis);
        final BufferedReader reader = new BufferedReader(isr);

        String line;
        // reading until \n\n
        while (!(line = reader.readLine()).trim().isEmpty()){
            // processing the line
        }

        // copying the rest of the byte array
        result = IOUtils.toByteArray(reader);
        reader.close();
    }

即使结果数组是它应该的大小,它的内容也被破坏了。如果我尝试toByteArray直接在fisor上使用isr,结果的内容是空的。

如何正确有效地读取文件的其余部分?

谢谢!

4

3 回答 3

1

您的内容被破坏的原因是该IOUtils.toByteArray(...)函数将您的数据作为默认字符编码的字符串读取,即它使用您的默认编码规定的任何逻辑将 8 位二进制值转换为文本字符。这通常会导致许多二进制值被破坏。

根据字符集的具体实现方式,这可能会起作用:

result = IOUtils.toByteArray(reader, "ISO-8859-1");

ISO-8859-1 每个字符只使用一个字节。并非所有字符值都已定义,但许多实现无论如何都会传递它们。也许你很幸运。

但是一个更简洁的解决方案是首先将字符串作为二进制数据读取,然后通过将其转换为文本,new String(bytes)而不是将最后的二进制数据作为字符串读取,然后再将其转换回来。

但是,这可能意味着您需要实现自己的 BufferedReader 版本以提高性能。

您可以通过明显的 Google 搜索找到标准 BufferedReader 的源代码,这将(例如)引导您到这里:

http://www.docjar.com/html/api/java/io/BufferedReader.java.html

它有点长,但从概念上讲并不难理解,所以希望它可以作为参考。

于 2013-02-27T05:28:37.987 回答
1

或者,您可以将文件读入字节数组,找到 \n\n 位置并将数组拆分为行和字节

    byte[] a = Files.readAllBytes(Paths.get("file"));
    String line = "";
    byte[] result = a;
    for (int i = 0; i < a.length - 1; i++) {
        if (a[i] == '\n' && a[i + 1] == '\n') {
            line = new String(a, 0, i);
            int len = a.length - i - 1;
            result = new byte[len];
            System.arraycopy(a, i + 1, result, 0, len);
            break;
        }
    }
于 2013-02-27T05:55:31.497 回答
0

感谢所有评论 - 最终实现是这样完成的:

    try (final FileInputStream fis = new FileInputStream(file)) {

        ByteBuffer buffer = ByteBuffer.allocate(64);

        boolean wasLast = false;
        String headerValue = null, headerKey = null;
        byte[] result = null;

        while (true) {
            byte current = (byte) fis.read();
            if (current == '\n') {
                if (wasLast) {
                    // this is \n\n
                    break;
                } else {
                    // just a new line in header
                    wasLast = true;
                    headerValue = new String(buffer.array(), 0, buffer.position()));
                    buffer.clear();
                }
            } else if (current == '\t') {
                // headerKey\theaderValue\n
                headerKey = new String(buffer.array(), 0, buffer.position());
                buffer.clear();
            } else {
                buffer.put(current);
                wasLast = false;
            }
        }
        // reading the rest
        result = IOUtils.toByteArray(fis);
    }
于 2013-02-27T07:04:04.867 回答