java:字节和字符的穿插

dgsult0t  于 2021-06-30  发布在  Java
关注(0)|答案(6)|浏览(366)

我有一个测试设备,我可以从中读取数据使用 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,并且必须转换字节->字符并查找换行符,看起来这肯定会奏效,但也会是一个真正的难题。

qeeaahzv

qeeaahzv1#

使用时 BufferedReader ,你可以用 String#getBytes() 从文件中取出字节 String 线路。别忘了考虑字符编码。我建议使用 UTF-8 总是。
仅供参考:另一方面,如果您只有字节,并且希望构造字符,那么只需使用 new String(bytes) . 也不要忘了在这里考虑字符编码。
[编辑]毕竟,最好使用bufferedinputstream并为单行构造一个字节缓冲区(填充直到字节与换行符匹配),然后测试它的起始字符表示形式是否与预定义的字符串之一匹配。

jmp7cifd

jmp7cifd2#

请看linenumberinputstream的源代码。类本身已经被弃用了,但是看起来这正是您需要的。
这个类允许您读取字节行,然后使用正则表达式 InputStream 读取方法。
如果不想将不推荐使用的代码拖到系统中,只需从中借用一些实现细节。

x33g5p2x

x33g5p2x3#

对于一般情况,我没有一个很好的答案(因此欢迎其他答案),但是如果我假设输入是iso-8859-1(8位字符),那么下面的方法对我来说是可行的,尽管我猜将8位字节转换为 char 也不一定保证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 Package 在其周围时,inputstreamreader.read()仍然在某种程度上缓冲,通过“贪婪地”读取多个字符,即使您只想拉出一个字符。因此,我不能使用inputstreamreader Package inputstream,并尝试同时使用inputstream和inputstreamreader来根据当前需要的字节/字符来读取字节/字符。

b4lqfgs4

b4lqfgs44#

我想我将尝试使用java.nio.bytebuffer和bytebuffer.ascharbuffer,这看起来很有前景。仍然需要手动查找换行符,但至少看起来它可以正确处理字符转换。

jaql4c8m

jaql4c8m5#

而不是使用 Reader 以及 InputStream 尝试在两者之间来回切换,尝试使用回调接口,其中一个方法用于二进制数据,另一个方法用于字符数据。例如

interface MixedProcessor {
    void processBinaryData(byte[] bytes, int off, int len);
    void processText(String line);
}

然后有另一个“splitter”类:
决定输入的哪些部分是文本,哪些是二进制的,并将它们传递给相应的处理器方法
在需要时将字节转换为字符(借助 CharsetDecoder )
splitter类可能如下所示:

class Splitter {
    public Splitter(Charset charset) { /* ... */ }
    public void readFully(InputStream is, MixedProcessor processor) throws IOException  { /* ... */ }
}
i34xakig

i34xakig6#

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

相关问题