从InputStream中读取文本和二进制数据

8
我试图从二进制流中读取数据,其中部分应该被解析为UTF-8。
直接使用InputStream来处理二进制数据,并在其上使用InputStreamReader来处理UTF-8文本是不起作用的,因为即使告诉读取器最多只读取n个字符,它也会向前读取并破坏随后的二进制数据。
我知道这个问题与在多个格式中从InputStream中读取非常相似,但那里提出的解决方案是针对HTTP流的,对我没有帮助。
我想到了将所有内容都读取为二进制数据,然后将相关部分转换为文本。但是,我只有以字符形式表示的字符数据的长度信息,而没有以字节表示的长度信息。因此,我需要从流中读取字符的东西要知道编码方式。
是否有一种方法可以告诉InputStreamReader不要向前读取超过读取给定数量的字符所需的内容?或者是否有一种读取器,支持二进制数据和文本编码,并可以在运行时在这些模式之间切换?
2个回答

2

首先需要阅读二进制部分。当您识别到需要进行UTF-8解码的字节部分时,您需要提取这些字节并对其进行解码。

DataInputStream dis = 
// read a binary type.
int num = dis.readInt();
int len = dis.readUnsignedShort();
// read a UTF-8 portion.
byte[] bytes = new byte[len];
dis.readFully(bytes);
String text = new String(bytes, "UTF-8");
// read some binary
double d = dis.readDouble();

2
问题在于,使用UTF8编码时,字节数可能与字符数不同。因此,我需要找出字符串中多字节字符的数量,读取更多字节并再次转换,直到数字匹配为止。 - tajmahal
我会说你的格式不太容易解码,如果可以的话,我会修复它。但是,如果您知道字符数,您可以自己解析UTF-8。(但发送实际字节数会更简单) - Peter Lawrey
另一种方法是读取比所需更多的数据。取预期的字符数,例如substring(),并转换为UTF-8以确定长度。使用mark()和reset()读取长度,现在您已经知道了。 (仅当UTF-8编码完全相同时才有效:|例如,空字节\0有两种不同的编码方式。(其他字符也可能如此) - Peter Lawrey
一个经验法则是,如果你需要让编码或解码更加困难,那么就让编码更加困难而让解码更加容易。 - Peter Lawrey
好的,我决定改变格式,因为这似乎是最简单的方法。 - tajmahal

2

我认为你不应该使用StreamReader。读取器处理文本,而你需要同时处理文本和二进制数据。

没有其他办法。你必须读取二进制缓冲区并自己解释格式,即找到文本提取字节的位置并将其转换为字符串。

为了简化这个任务,我建议你创建自己的类(比如ProtocolRecord)。它应该是可序列化的,并包含所有字段。

现在你有两个选择:

(1)简单的方法-使用Java序列化机制。在这种情况下,你只需用DataInputStream进行读取和DataOutputStream进行写入,然后读取/写入对象即可。这种方法的缺点是你无法控制你的协议。

(2)自己实现readObject()和writeObject()方法。现在按照上面的说明使用DataInputStream和DataOutputStream。在这种情况下,你确实需要实现序列化协议,但至少它被封装在你的类中。

我认为你需要的是DataInputStream。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接