【问题标题】:Get bytes from the Int returned from socket intputStream read()从套接字 intputStream read() 返回的 Int 中获取字节
【发布时间】:2013-08-17 22:18:18
【问题描述】:

我有一个 InputStream,我想读取每个字符,直到我从套接字中找到一个逗号“,”。

这是我的代码

private static Packet readPacket(InputStream is) throws Exception
{
    int ch;
    Packet p = new Packet();

    String type = "";
    while((ch = is.read()) != 44) //44 is the "," in ISO-8859-1 codification
    {
        if(ch == -1)
            throw new IOException("EOF");
        type += new String(ch, "ISO-8859-1"); //<----DOES NOT COMPILE
    }
    ...
}

String 构造函数不接收 int,只接收字节数组。我阅读了文档,上面写着

读取(): 从输入流中读取数据的下一个字节。

那我怎样才能把这个 int 转换成 byte 呢?它是否仅使用 int 的所有 32 位中的较低有效位(8 位)?

由于我使用 Java,我想保持它与全平台兼容(小端与大端等...)这里最好的方法是什么?为什么?

PS:我不想使用任何现成的类,如 DataInputStream 等......

【问题讨论】:

    标签: java sockets byte


    【解决方案1】:

    为此可以使用InputStreamReader,它可以从原始字节流中读取编码的字符数据:

    InputStreamReader reader = new InputStreamReader(is, "ISO-8859-1");
    

    您现在可以使用reader.read(),它将使用来自is 的正确字节数,解码为ISO-8859-1,并返回一个可以正确转换的Unicode 代码点到char

    编辑:回应关于不使用任何“即用型”类的评论:

    我不知道InputStreamReader 算不算。如果是这样,请查看 Durandal 的答案,这对于某些单字节编码(如 US-ASCII、arguable 或 ISO-8859-1)来说已经足够了。

    对于多字节编码,如果您不想使用任何其他类,您可以先将所有数据缓冲到一个byte[] 数组中,然后从中构造一个String

    编辑:回复 cmets 中关于 Abhishek 答案的相关问题。

    问:

    Abhishek 写道:你能多指教一下吗?我尝试将整数 ASCII 转换为字符..它成功了..你能告诉我哪里出错了吗?

    答:

    您本身并没有“错”。 ASCII 起作用的原因与 Brian 指出 ISO-8859-1 起作用的原因相同。 US-ASCII 是单字节编码,字节 0x00-0x7f 的值与其对应的 Unicode 代码点相同。因此,转换为 char 在概念上是不正确的,但在实践中,由于值相同,它可以工作。与 ISO-8859-1 相同;字节 0x00-0xff 与该编码中的相应代码点具有相同的值。对 char 的强制转换在例如 char 中不起作用。 IBM01141(单字节编码,但值不同)。

    当然,单个字节到字符转换对于 UTF-16 等多字节编码不起作用,因为必须读取多个输入字节(实际上是一个可变数字)才能确定对应的正确值字符。

    【讨论】:

    • @Abhishek 那么他应该接受 Durandal 的回答。
    • @Abhishek 不想为工作使用正确的工具...通常不是一个好主意。这确实是正确答案。在谈论尝试编写网络代码时,不了解字符集以及 Java 如何处理它们是非常糟糕。 (+1)
    • @JasonC 我知道我很挑剔,但是……只要您只使用 US-ASCII(7 位)字符,它就可以与 UTF-8 一起使用。 UTF-8 直接将 U+0000 映射到 U+007F 作为单个字节(基本上是为了向后兼容 7 位 ASCII)。这实际上是会让许多新手开发者感到困扰的原因,因为它似乎可以工作......直到有人向你扔å:-D
    • 当然......一旦你超过了两个字节的序列,如果你尝试使用char,你就会被Java淹没。 (真的,我没有在 Java 和字符编码方面有个人恩怨:-D)
    • 我赢不了。无论如何,正确处理字符数据确实需要选择nits。我已将我的示例编辑为 UTF-16(尽管它实际上对 single UTF-16LE 字符
    【解决方案2】:

    String 构造函数接受一个 char[](一个数组)

    type += new String(new byte[] { (byte) ch }, "ISO-8859-1");
    

    顺便说一句。使用 StringBuilder 作为类型并利用其附加方法会更优雅。它更快,也更好地显示了意图:

    private static Packet readPacket(InputStream is) throws Exception {
        int ch;
        Packet p = new Packet();
    
        StringBuilder type = new StringBuilder();
        while((ch = is.read()) != 44) {
            if(ch == -1)
                throw new IOException("EOF");
            // NOTE: conversion from byte to char here is iffy, this works for ISO8859-1/US-ASCII
            // but fails horribly for UTF etc.
            type.append((char) ch);
        }
        String data = type.toString();
        ...
    }
    

    此外,为了使其更灵活(例如,使用其他字符编码),您的方法最好采用 InputStreamReader 来为您处理从字节到字符的转换(查看 InputStreamReader(InputStream, Charset) 构造函数的 javadoc)。

    【讨论】:

    • 你不能这样做。没有采用 char 数组和字符集的 String 构造函数。 char 数组已经包含未编码的 unicode 值。用编码类型指定是无稽之谈。
    • 你说得对,正在考虑 String(byte[])... 已修复,感谢您的关注。
    • +1,第一位现在是一个可行的解决方案。值得注意的是,这只适用于单字节编码(包括 ISO-8859-1)。 StringBuilder 的第二个示例问题更大,我永远不会将字节直接转换为char。第二个示例需要单字节编码,具有与代码点直接一致的字节值。
    【解决方案3】:

    部分答案:尝试替换:

      type += new String(ch, "ISO-8859-1");
    

    通过

      type+=(char)ch;
    

    如果您收到 char 的 ASCII 值,则可以这样做。代码通过强制转换将 ASCII 转换为 char。

    最好避免冗长的代码,这样就可以了。 read() 函数有多种工作方式:

    一种方式是:int= inpstr.read();

    第二个inpstr.read(byte) 所以这取决于你想使用哪种方法..两者都有不同的目的..

    【讨论】:

    • @JasonC 在这种情况下会很好。 ISO-8859-1 是 Unicode 的第一个块,相等的。
    • @BrianRoach 完全正确,但我认为写此答案的人不知道,我肯定不想要 OP了解转换为 char 的想法通常是可以接受的(并且在其他情况下遇到其他编码方案的问题)。
    • 您能多指教一下吗?我尝试将整数 ASCII 转换为字符..它有效..你能告诉我哪里出错了吗?
    • @Abhishek 就其本身而言,您并没有“错”。 ASCII 起作用的原因与 Brian 指出 ISO-8859-1 起作用的原因相同。 US-ASCII 是单字节编码,字节 0x00-0x7f 的值与其对应的 Unicode 代码点相同。所以转换为char 在概念上是不正确的,但在实践中,由于值相同,它可以工作。与 ISO-8859-1 相同;字节 0x00-0xff 与该编码中的相应代码点具有相同的值。转换为char工作在例如IBM01141(单字节编码,但值不同)。
    • 当然,char 转换的单个字节不适用于 UTF-8 等多字节编码,因为必须读取多个输入字节(实际上是一个可变数字)确定对应char的正确值。
    【解决方案4】:
    type += new String(String.valueOf(ch).getBytes("ISO-8859-1"));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-25
      • 1970-01-01
      • 2011-12-07
      • 2021-06-22
      • 2016-04-26
      • 1970-01-01
      • 1970-01-01
      • 2010-10-18
      相关资源
      最近更新 更多