Java:分两部分读取文件——一部分作为String,一部分作为byte[]



我有一个文件被"nn"分成两部分-第一部分是不太长的字符串,第二部分是字节数组,可以很长。

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

    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 nn
        while (!(line = reader.readLine()).trim().isEmpty()){
            // processing the line
        }
        // copying the rest of the byte array
        result = IOUtils.toByteArray(reader);
        reader.close();
    }

尽管结果数组的大小符合预期,但它的内容被破坏了。如果我尝试在fisisr上直接使用toByteArray,结果内容为空。

我怎样才能正确有效地读取文件的其余部分?

谢谢!

您的内容被打破的原因是因为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

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

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

    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;
        }
    }

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

    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 nn
                    break;
                } else {
                    // just a new line in header
                    wasLast = true;
                    headerValue = new String(buffer.array(), 0, buffer.position()));
                    buffer.clear();
                }
            } else if (current == 't') {
                // headerKeytheaderValuen
                headerKey = new String(buffer.array(), 0, buffer.position());
                buffer.clear();
            } else {
                buffer.put(current);
                wasLast = false;
            }
        }
        // reading the rest
        result = IOUtils.toByteArray(fis);
    }

最新更新