【问题标题】:C# BinaryReader ReadUTF from Java's DataOutputStream来自 Java 的 DataOutputStream 的 C# BinaryReader ReadUTF
【发布时间】:2014-10-17 02:02:19
【问题描述】:

我一直在努力将这些类转换为 C#(DataInputStreamDataOutputStream),并且我已经完成了 DataOutputStream 类,现在问题都在输入流类。

注意:我没有在 C# 中使用 Encoding 类的原因是因为 Java 中的 DataInput/DataOutputStream 使用了自定义的 UTF-8 编码。

基本上,我有这个代码: (C#) 它使用 BinaryReader

public String ReadUTF()
    {
        int utflen = this.ReadUnsignedShort ();
        byte[] bytearr = null;
        char[] chararr = null;

        if(bytearr.Length < utflen)
        {
            bytearr = new byte[utflen * 2];
            chararr = new char[utflen * 2];
        }

        int c, char2, char3;
        int count = 0;
        int chararr_count=0;

        this.ReadFully(bytearr, 0, utflen);

        while (count < utflen) {
            c = (int) bytearr[count] & 0xff;
            if (c > 127) break;
            count++;
            chararr[chararr_count++]=(char)c;
        }

        while (count < utflen) {
            c = (int) bytearr[count] & 0xff;
            switch (c >> 4) {
            case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
                /* 0xxxxxxx*/
                count++;
                chararr[chararr_count++]=(char)c;
                break;
            case 12: case 13:
                /* 110x xxxx   10xx xxxx*/
                count += 2;
                if (count > utflen)
                    throw new Exception(
                        "malformed input: partial character at end");
                char2 = (int) bytearr[count-1];
                if ((char2 & 0xC0) != 0x80)
                    throw new Exception(
                        "malformed input around byte " + count);
                chararr[chararr_count++]=(char)(((c & 0x1F) << 6) |
                                                (char2 & 0x3F));
                break;
            case 14:
                /* 1110 xxxx  10xx xxxx  10xx xxxx */
                count += 3;
                if (count > utflen)
                    throw new Exception(
                        "malformed input: partial character at end");
                char2 = (int) bytearr[count-2];
                char3 = (int) bytearr[count-1];
                if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
                    throw new Exception(
                        "malformed input around byte " + (count-1));
                chararr[chararr_count++]=(char)(((c     & 0x0F) << 12) |
                                                ((char2 & 0x3F) << 6)  |
                                                ((char3 & 0x3F) << 0));
                break;
            default:
                /* 10xx xxxx,  1111 xxxx */
                throw new Exception(
                    "malformed input around byte " + count);
            }
        }
        // The number of chars produced may be less than utflen
        return new String(chararr, 0, chararr_count);
    }

这是我的 ReadUnsignedShort 方法

public int ReadUnsignedShort()
    {
        int ch1 = BinaryReader.Read();
        int ch2 = BinaryReader.Read();
        if ((ch1 | ch2) < 0)
        {
            throw new EndOfStreamException(); // Temp- To be changed
        }
        return (ch1 << 8) + (ch2 << 0); 
    }

这也是使用的 Readfully 方法:

public void ReadFully(byte[] b, int off, int len)
    {
        if(len < 0)
        {
            throw new IndexOutOfRangeException();
        }

        int n = 0;
        while(n < len) 
        {
            int count = ClientInput.Read(b, off + n, len - n);
            if(count < 0)
            {
                throw new EndOfStreamException(); // Temp - to be changed
            }
            n += count;
        }
    }

对于 OutputStream,问题在于我使用的是 Write(int) 而不是 Write(byte) 函数,但我认为这里不是这种情况,或者我一定是盲目的。

如果您对如何发送 UTF 字符串感兴趣,这里是它的 C# 转换:

public int WriteUTF(string str)
    {
        int strlen = str.Length;
        int utflen = 0;
        int c, count = 0;

        for(int i = 0; i < strlen; i++) 
        {
            c = str.ToCharArray()[i];
            if((c >= 0x0001) && (c <= 0x007F)) 
            {
                utflen++;
            } 
            else if(c > 0x07FF)
            {
                utflen += 3;
            }
            else
            {
                utflen += 2;
            }
        }

        if(utflen > 65535)
        {
            throw new Exception("Encoded string is too long: " + utflen + " bytes");
        }

        byte[] bytearr = null;
        bytearr = new byte[(utflen*2) + 2];

        bytearr[count++] = (byte) (((uint)utflen >> 8) & 0xFF);
        bytearr[count++] = (byte) (((uint)utflen >> 0) & 0xFF);

        int x = 0;
        for(x = 0; x < strlen; x++) 
        {
            c = str.ToCharArray()[x];
            if (!((c >= 0x0001) && (c <= 0x007F))) break;
            bytearr[count++] = (byte)c;
        }

        for(;x < strlen; x++)
        {
            c = str.ToCharArray()[x];
            if ((c >= 0x0001) && (c <= 0x007F)) 
            {
                bytearr[count++] = (byte)c;
            }
            else if (c > 0x07FF)
            {
                bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
                bytearr[count++] = (byte) (0x80 | ((c >>  6) & 0x3F));
                bytearr[count++] = (byte) (0x80 | ((c >>  0) & 0x3F));
            }
            else
            {
                bytearr[count++] = (byte) (0xC0 | ((c >>  6) & 0x1F));
                bytearr[count++] = (byte) (0x80 | ((c >>  0) & 0x3F));
            }
        }
        ClientOutput.Write (bytearr, 0, utflen+2);
        return utflen + 2;
    }

希望我已经提供了足够的信息,以便在阅读 UTF 值方面获得一点帮助,这确实为我的项目进度设置了障碍。

【问题讨论】:

    标签: java c# input io output


    【解决方案1】:

    如果我正确理解了“问题”(例如,您说存在“障碍”,但您未能解释“障碍”到底是什么),那么您正在尝试在 C# 中实现代码以读取和从流中写入文本。如果是这样,那么(我知道如果您是 .NET 新手,这不是很明显)自己显式处理文本编码是疯狂的。

    BinaryReader 和 BinaryWriter 有处理这个问题的方法。创建对象时,您可以传递用于解释或创建文本二进制数据的 Encoding 实例(例如 System.Text.Encoding.UTF8、System.Text.Encoding.Unicode 等)。您可以使用 BinaryReader.ReadChars(int) 读取文本,使用 BinaryWriter.Write(char[]) 写入文本。

    如果由于某种原因不起作用,至少您可以直接使用 Encoding 实例来解释或创建某些文本的二进制数据。 Encoding.GetString(byte[]) 将二进制转换为文本,Encoding.GetBytes(string) 将文本转换为二进制。同样,为您正在处理的实际文本编码使用特定的 Encoding 实例。

    【讨论】:

    • 我这样做的原因是因为我在 Java 服务器中使用的 DataOutputStream 类使用自定义 UTF-8 加密,所以当我从服务器发送一个 UTF 字符串时,编码它使用它不同于标准的 UTF-8 编码。这里的问题是它没有正确读取数据,无论出于何种原因,它都没有返回字符串的值......甚至没有得到任何地方。 msdn.microsoft.com/en-us/library/aa286366%28v=vs.60%29.aspx
    • 为了详细说明我这样做的原因,我一直在编写的我的服务器结构使用 Java DataInputStreamDataOutputStream 类,我现在正在用 C# 编写一个需要为了能够毫无问题地与服务器通信,考虑到 Java 类对 UTF-8 使用自定义编码,这就是我自己处理所有编码的原因。
    • 如果我正确理解了 Java 实现,它与纯 UTF8 编码之间的唯一区别是表示剩余数据字节数的两字节前缀。所以只需将这两个字节作为 Int16 读取,然后使用该字节数来确定之后要读取的字节长度,然后将这些字节传递给 Encoding.UTF8.GetString()。显然你会做相反的事情来写字符串。
    【解决方案2】:

    写了Java的DataInputStreamDataOutputStream的C#转换,你可以在这里收集。

    https://bitbucket.org/CTucker1327/c-datastreams/src

    要构造这些类,您需要将 BinaryWriter 或 BinaryReader 传递给构造函数。

    构造DataOutputStream

    DataOutputStream out = new DataOutputStream(new BinaryWriter(Stream));
    

    构造DataInputStream

    DataInptuStream in = new DataInputStream(new BinaryReader(Stream));
    

    【讨论】:

    • 如果这里的回答没有帮助,但您能够自己解决问题,您最好用答案跟进您自己的问题,以防其他人发现自己未来类似的情况。如果此处的任何回复有用,您应该评论如何以及为什么,当然,标记/投票任何有用的答案以识别它们。谢谢! (很高兴你把源放到网上,但那是在别处,无论如何不会明确指出实际问题是什么)。
    • 链接失效了...你能把代码分享到别的地方吗?
    猜你喜欢
    • 1970-01-01
    • 2014-12-11
    • 1970-01-01
    • 1970-01-01
    • 2015-10-23
    • 2011-06-22
    • 1970-01-01
    • 2021-12-02
    • 1970-01-01
    相关资源
    最近更新 更多