Java:读取文件分为两部分 - 部分为String,部分为byte []

时间:2013-02-27 05:14:17

标签: java file stream

我有一个由“\ 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();
    }

即使生成的数组应该是它的大小,它的内容也会被破坏。如果我尝试直接在toByteArrayfis上使用isr,则结果内容为空。

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

谢谢!

3 个答案:

答案 0 :(得分: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

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

答案 1 :(得分: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;
        }
    }

答案 2 :(得分: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);
    }