c# - 使用 protobuf-net 为 c# 生成的文件与在 C++ 中生成的相同文件略有不同

标签 c# file binary protobuf-net winmerge

我遇到了有线问题,我正在使用 C# 的 protobuf-net 生成一个基于 Google Protocol Buffer 消息的文件,然后将其上传到我公司的一台服务器。

我在 C# 中创建了一个工具,它生成一个 .proto 文件到 .cs,然后我使用它的类(来自 .cs 文件)来填充消息中的所有必填字段,然后调用 Serializer.Serialze () 函数及其为我创建请求的文件。

但是,这就是问题所在,我有另一个文件(相同的文件)是在另一个用 C++ 编写的工具中创建的(使用与我使用的相同的 .proto 文件),但是当我尝试上传我的文件时到我们的服务器,我收到一条错误消息,表明出了点问题。

我将这 2 个文件与“Win Merge”软件进行了比较,我注意到与在 C++ 工具中生成的文件相比,3 个不同的行(每个文件中的 7000 多行)的差异很小。

这是从 Win Merge 工具(左边是 C++,右边是 C#)捕获的 2 行示例:

enter image description here

Another example:

我注意到不同之处在于矩形(我不明白这是什么意思)和它们里面的字节......

这是我正在使用的 .proto 文件:

message Package {

message ArchDepend {

    message Arch {
        required string version = 1;
        required string description = 2;
    }

    message Firmware {
        required string version = 1;
        required string description = 2;
        required bytes file = 3;

        repeated string from_version = 4;
    }

    message Rsu {
        required string version = 1;
        required string description = 2;
        required bytes file = 3;
    }

    required Arch arch = 1;

    optional Firmware firmware = 2;
    optional Rsu rsu = 3;
}

message DefaultEeprom {
    required string version = 1;
    required string description = 2;
    required bytes file = 3;

    message Migration {
        required string from_version = 1;
        required bytes file = 2;
    }

    repeated Migration migrations = 4;
}

required string name = 1;
optional ArchDepend archDepend = 2;
optional DefaultEeprom defaultEeprom = 3;

我在 .cs 文件中插入的字段是字符串和文件(*.bin),这里是字符串的示例:

“PowerMaster-30”

"JS702394 K17.A20"

等..

它们被插入到 .proto 文件中的大多数字符串字段中。

在文件字段 (.proto) 中,我正在加载我公司使用的二进制文件(与加载到 C++ 工具的文件相同)。

这是我正在从中读取数据的二进制文件的屏幕截图,在名为“Falsher.exe”的程序中打开,左侧是转换为十六进制 View ,右侧是 ASCII:

enter image description here

这是读取二进制文件的代码:

       private string[] FindPanelVersionInBinFile(string path)
    {
        string currentline;
        int flag = 0;
        string[] namesArray = new string[3]; // contains all the strings which I get from the BIN file.

        using (StreamReader sr = new StreamReader(path))
        {
            while ((currentline = sr.ReadLine()) != null && flag < 3)
            {
                if (currentline.Contains("PRODUCT_FAMILY"))
                {
                    int index = currentline.IndexOf("PRODUCT_FAMILY");
                    namesArray[0] = currentline.Substring(index + 16, 14); // index of product family"PowerMaster-xx"
                    flag++;
                }
                if (currentline.Contains("SW_VERSION"))
                {
                    int index = currentline.IndexOf("SW_VERSION");
                    namesArray[1] = currentline.Substring(index + 12, 17); // index of software version "JSxxxxx Kxx.yyy"
                    flag++;                       
                }
                if (currentline.Contains("compatibility"))
                {
                    int index = currentline.IndexOf("compatibility");
                    namesArray[2] = currentline.Substring(index + 21, 7); // index of compatibility number "xx.yyy"
                    flag++;
                }                  
            }
        }
        return namesArray;

毕竟,我正在使用此代码生成我的文件:

                        byte[] data;
                        using (var ms = new MemoryStream())
                        {
                            Serializer.Serialize(ms, package);
                            data = ms.ToArray();
                        }
                        string packageFilePath = Path.Combine(savePath, package.Name);
                        File.WriteAllBytes(packageFilePath, data);

有人可以帮我解释一下到底有什么区别以及它们发生的原因是什么?

谢谢!!

猎户座。

最佳答案

看起来的区别只是以零结尾的字符串。

我猜(请指正)左边的数据来自protobuf-net,右边的数据来自C++实现。在左边我们有 "[10],一些数据,然后是 [1A](我相信 [1A] 是下一个字段 header :字段 3,长度前缀)。支持这个假设,[10]/之前的“字符”(松散地说) [11]",即 ASCII 34 - 它(在 protobuf 中)表示“字段 2,长度前缀”。所以我很满意地说 "[10] 告诉我们“字段 2,长度为 16 的字符串”,而 "[11] 告诉我们“字段 2,长度为 17 的字符串。

因此,C# 中的字符串是 "JS702415 K17.020" 是合乎逻辑的,而 C++ 中的字符串是相同的,但带有一个空终止符 .有趣的是:我认为它不应该包含空终止符。所以:要么是 C++ API 出错(对此我表示怀疑),要么是在将数据传递给 C++ 时,你不小心告诉它(错误地)将 nul 终止符包含到字符串中。

我确定编码不包含空终止符,因为 protocol specification给出了字符串“testing”(作为字段 2)的示例,它被编码为:

12 07 74 65 73 74 69 6e 67

12是field-header(field 2, length-prefixed); 07 是长度,接下来的 7 个字节 (74...67) 是有效载荷,UTF-8 编码。注意:没有空终止符。

关于c# - 使用 protobuf-net 为 c# 生成的文件与在 C++ 中生成的相同文件略有不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16440286/

相关文章:

不能对多个文件指定 -c

java - 如何在 java 中缩短文件路径(获取规范路径)?

c - 将汇编翻译成 C 程序

r - 选择十进制数的所有二进制邻居

algorithm - 黑盒计数到 19 只有 2 位,并且只能切换?

c# - 如何在 LongListSelector 中显示/隐藏(如果可能,使用动画)复选框

c# - 如何加载依赖程序集?

ruby-on-rails - 如何在 Active Storage 测试中 stub 文件大小? (测试::单位)

c# - 如果 'Process.HasExited' 抛出异常,我是否可以认为进程已经消失了?

c# - 当 BufferBlock 为空时,Async StreamWriter Loop 停止写入