【问题标题】:How write a byte array with integer to file encoded in utf8 format如何将带有整数的字节数组写入以 utf8 格式编码的文件
【发布时间】:2014-07-23 21:52:57
【问题描述】:

最近我偶然发现了一个关于 UTF8 的问题。我被要求以 UTF8 编码写入和读取文件。乍一看,我认为这很容易,但事实并非如此。 我的问题是我必须编写一个包含字符串和整数或短整数的二进制文件。 为此,我写了

            byte[] BOM  = new byte[] {0xEF, 0xBB, 0xBF};
            byte[] Head;
            byte head4[] = new byte[4];
            UTF8Encoding utf8 = new UTF8Encoding(false);
            using (FileStream stream = new FileStream(fileName, FileMode.Create))
            {

                    stream.Write( BOM,0, BOM.Length);
                    Byte[] title = utf8.GetBytes("Hello_Abra");
                    stream.Write(title, 0, title.Length);

                    string HeadString = new string('\0', INDEXLength);
                    Head = utf8.GetBytes(HeadString);
                    stream.Write( Head, 0, Head.Length);

                    WriteInt(1258, head4, 0 );  
                    stream.Write( head4, 0, head4.Length);

            }


        public static void WriteInt(int TheInt, byte[] ToArray, int atIndex) 
    {

        for (int i=0; i<limit; i++) 
        {
            byte thebyte = (byte) (TheInt & 0xff);
            ToArray[atIndex+i] = thebyte;
            TheInt = TheInt>>8;
        }
    }

当我调用 WriteInt 函数获取整数值并尝试将其写入文件时,结果文件的内容始终为 ANSI,所有字符均以 ANSI 格式写入。 另一方面,如果我只写字符串,则文件内容为 UTF8,字符串以 2 字节 UFT8 格式写入。

怎么了。这是实现目标的正确方法。 任何帮助表示感谢。

乔斯

【问题讨论】:

    标签: utf-8


    【解决方案1】:

    您从 int 中提取的原始字节不是 UTF-8 编码的,因此它们会破坏解码过程。

    您可以对字符串表示进行编码:

    Head = utf8.GetBytes("1258".ToString());
    stream.Write( Head, 0, Head.Length);
    

    当然 BASE-64 会为较大的数字生成较短的字符串:

    WriteInt(1258, head4, 0 );
    Head = utf8.GetBytes(Convert.ToBase64String(head4));
    stream.Write( Head, 0, Head.Length);
    

    【讨论】:

    • 感谢 Alireza 的回答。我注意到在我的头字节数组中我有错误的 UTF8 代码,但我试过了。另一方面,如果我将 Base64String 写入转换为 UTF8 如何从二进制文件中读取此字段并转换回整数 1258 ?再次感谢
    • 我真的没想到那么远 ;-) 你可以倒着做这个过程。假设您在流中的正确位置,并且由于 4 字节 int 始终转换为 8 字节 Base-64,它们都是 ASCII 字符,相当于 UTF-8 中的一个字节:stream.Read( Head, 0, 8); byte[] b = Convert.FromBase64String(utf8.GetString(head)); int n = 0; for (int i = 3; i &gt;= 0; i--) n = (n &lt;&lt; 8) + b[i];
    【解决方案2】:

    由于您在同一个文件中混合了字符串和非字符串数据,因此您根本不应该在文件的前面编写 BOM。您不能将二进制数写入 UTF-8 编码的文本文件。您需要将整个文件视为二进制文件,而不是文本,并根据需要简单地对各个字符串进行编码/解码。

    您还存在知道 UTF-8 编码字符串在哪里结束的问题。我怀疑你正试图在它之后写一个空终止符,但你没有这样做。你可以使用stream.WriteByte(0)

    另一方面,从FileStream 中读取以空字符结尾的字符串很困难。您必须一次将一个字节的流读入缓冲区,直到遇到空值,然后您可以使用UTF8Encoding 对缓冲区进行解码。效率不高。

    就我个人而言,我会将以 null 结尾的字符串改为以长度为前缀的字符串。然后你可以使用BinaryWriterBinaryReader 为你处理一切,例如:

    using (FileStream stream = new FileStream(fileName, FileMode.Create))
    {
        using (BinaryWriter writer = new BinaryWriter(stream, Encoding.UTF8))
        {
            writer.Write("Hello_Abra");
            writer.Write(new string('\0', INDEXLength));
            writer.Write(Int32(1258));
        }
    }
    

    string s;
    int i;
    using (FileStream stream = new FileStream(fileName, FileMode.Open))
    {
        using (BinaryReader reader = new BinaryReader(stream, Encoding.UTF8))
        {
            s = reader.ReadString();
            s = reader ReadString();
            i = reader.ReadInt32();
        }
    }
    

    【讨论】:

    • 谢谢你,雷米,我不知道 UTF8 限制/行为。看来你的建议是正确的......我的意思是......删除BOM并使用混合代码,就像你在你的例子中所做的那样......但如果我这样做,我怀疑我无法编写固定对元素...... . 我的意思是 [tex+value] [tex+value] [tex+value] 的一块??对吗??
    • 当然可以。在二进制文件中,你可以写任何你想写的东西,只要你按照你写它们的顺序来读它们。在我的示例中,该文件由 [length+text][length+text][int32] 组成,但您可以使用 [type+length+value][type+length+value][type+length+value] 代替(TLV 在许多文件格式和协议中都很常见)。
    猜你喜欢
    • 2015-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-04
    • 2014-04-10
    • 2010-12-18
    • 2012-04-10
    • 2016-07-05
    相关资源
    最近更新 更多