我有一个文件被"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();
}
尽管结果数组的大小符合预期,但它的内容被破坏了。如果我尝试在fis
或isr
上直接使用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);
}