我有一个测试设备,我可以使用InputStream
从中读取数据,它散布字节和字符(组织成行),例如:
TEST1
TEST2
500
{500 binary bytes follows here}
TEST3
TEST4
600
{600 binary bytes follows here}
我想使用BufferedReader,所以我可以一次读取一行,但然后切换到InputStream,这样我就可以读取二进制字节了。但这似乎既不起作用,也不是一个好主意。
我该怎么做?我无法从BufferedReader获取字节,如果我在InputStream之上使用BufferedReader,则看起来BufferedReader“拥有”InputStream。
编辑:替代方案,只是在任何地方使用InputStream并且必须转换字节 - >字符并查找换行符,看起来它肯定会起作用,但也会是一个真正的痛苦。
答案 0 :(得分:1)
使用BufferedReader
时,您可以使用String#getBytes()
从String
行中获取字节数。不要忘记考虑字符编码。我建议始终使用UTF-8
。
仅供参考:另一方面,如果您只有字节而想构建字符,请使用new String(bytes)
。另外不要忘记在这里考虑字符编码。
[编辑]毕竟,最好使用BufferedInputStream并为单行构造字节缓冲区(填充直到字节与换行符匹配)并测试其开头的字符表示是否与其中一个预定义字符串匹配
答案 1 :(得分:1)
不要使用Reader
和InputStream
并尝试在两者之间来回切换,而是尝试使用一个回调接口,一个方法用于二进制数据,另一个用于字符数据。 e.g。
interface MixedProcessor {
void processBinaryData(byte[] bytes, int off, int len);
void processText(String line);
}
然后有另一个“分裂者”类:
CharsetDecoder
)分割器类看起来像这样:
class Splitter {
public Splitter(Charset charset) { /* ... */ }
public void readFully(InputStream is, MixedProcessor processor) throws IOException { /* ... */ }
}
答案 2 :(得分:0)
我想我会尝试使用java.nio.ByteBuffer和ByteBuffer.asCharBuffer,这看起来很有希望。仍然需要手动查找换行符,但至少看起来它会正确处理字符转换。
答案 3 :(得分:0)
查看LineNumberInputStream的源代码。该类本身已被弃用,但看起来这正是您所需要的。
此类允许您读取字节行,然后使用常规InputStream
读取方法。
如果您不想将弃用的代码拖到系统中,只需从中借用一些实现细节。
答案 4 :(得分:0)
我对一般情况没有一个好的答案(所以欢迎其他答案),但如果我假设输入是ISO-8859-1(8位字符),以下适用于我,虽然我猜测作为char
的8位字节也不一定能保证ISO-8859-1。
现有的InputStream.read(byte [] b)和InputStream.read(byte [] b,int ofs,int len)允许我读取字节。
public class OctetCharStream extends InputStream {
final private InputStream in;
static final private String charSet = "ISO-8859-1";
public OctetCharStream(InputStream in)
{
this.in=in;
}
@Override public int read() throws IOException {
return this.in.read();
}
public String readLine() throws IOException
{
StringBuilder sb = new StringBuilder();
while (true)
{
/*
* cast from byte to char:
* fine for 8-byte character sets
* but not good in general
*/
char c = (char) read();
if (c == '\n')
break;
sb.append(c);
}
return sb.toString();
}
public String readCharacters(int n) throws IOException
{
byte[] b = new byte[n];
int i = read(b);
String s = new String(b, 0, i, charSet);
return s;
}
}
有趣的是,当我尝试单独使用InputStreamReader而不是将BufferedReader包装在它周围时,即使你只想拔出一个字符,InputStreamReader.read()仍会在某种程度上缓冲,通过阅读“贪婪”多个字符。因此我无法使用InputStreamReader来包装InputStream 和尝试使用InputStream和InputStreamReader来根据我目前所需的字节/字符来读取字节/字符。
答案 5 :(得分:-1)
BufferedReader有read(char[] cbuf, int off, int len)
你不能使用它,将字符转换为字节并用ByteArrayInputStream包装吗?
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
bos.write("TEST1\n".getBytes());
bos.write("10\n".getBytes());
for (int i = 0; i < 10; i++)
bos.write(i);
bos.write("TEST2\n".getBytes());
bos.write("1\n".getBytes());
bos.write(25);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
BufferedReader br = new BufferedReader(new InputStreamReader(bis));
while (br.ready()) {
String s = br.readLine();
String num = br.readLine();
int len = Integer.valueOf(num);
System.out.println(s + ", reading " + len + " bytes");
char[] cbuf = new char[len];
br.read(cbuf);
byte[] bbuf = new byte[len];
for (int i = 0; i < len; i++)
bbuf[i] = (byte) cbuf[i];
for (byte b: bbuf)
System.out.print(b + " ");
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}
输出:
TEST1, reading 10 bytes
0 1 2 3 4 5 6 7 8 9
TEST2, reading 1 bytes
25