Java:散布字节和字符

时间:2009-11-04 19:00:45

标签: java io

我有一个测试设备,我可以使用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并且必须转换字节 - >字符并查找换行符,看起来它肯定会起作用,但也会是一个真正的痛苦。

6 个答案:

答案 0 :(得分:1)

使用BufferedReader时,您可以使用String#getBytes()String行中获取字节数。不要忘记考虑字符编码。我建议始终使用UTF-8

仅供参考:另一方面,如果您只有字节而想构建字符,请使用new String(bytes)。另外不要忘记在这里考虑字符编码。

[编辑]毕竟,最好使用BufferedInputStream并为单行构造字节缓冲区(填充直到字节与换行符匹配)并测试其开头的字符表示是否与其中一个预定义字符串匹配

答案 1 :(得分:1)

不要使用ReaderInputStream并尝试在两者之间来回切换,而是尝试使用一个回调接口,一个方法用于二进制数据,另一个用于字符数据。 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