1

我已经用 C# 中的 BinaryWriter 将几个整数、char[] 等写入数据文件。使用 BinaryReader(在 C# 中)读回文件,我可以完美地重新创建文件的所有部分。

然而,尝试用 C++ 将它们读回会产生一些可怕的结果。我正在使用 fstream 尝试读回数据,但数据未正确读入。在 C++ 中,我设置了一个 fstreamios::in|ios::binary|ios::ate并使用 seekg 来定位我的位置。然后我读取了接下来的四个字节,它们被写为整数“16”(并正确读取到 C# 中)。这在 C++ 中读取为 1244780 (不是内存地址,我检查了)。为什么会这样?C++ 中是否有与 BinaryReader 等价的东西?我注意到它在 msdn 上提到过,但那是 Visual C++,而智能感知在我看来甚至不像 C++。

编写文件的示例代码(C#):

    public static void OpenFile(string filename)
    {
        fs = new FileStream(filename, FileMode.Create);
        w = new BinaryWriter(fs);

    }

    public static void WriteHeader()
    {
        w.Write('A');
        w.Write('B');
    }

    public static byte[] RawSerialize(object structure)
    {
        Int32 size = Marshal.SizeOf(structure);
        IntPtr buffer = Marshal.AllocHGlobal(size);
        Marshal.StructureToPtr(structure, buffer, true);
        byte[] data = new byte[size];
        Marshal.Copy(buffer, data, 0, size);
        Marshal.FreeHGlobal(buffer);
        return data;
    }

    public static void WriteToFile(Structures.SomeData data)
    {
        byte[] buffer = Serializer.RawSerialize(data);
        w.Write(buffer);
    }

我不确定如何向您展示数据文件。

读回数据的示例(C#):

        BinaryReader reader = new BinaryReader(new FileStream("C://chris.dat", FileMode.Open));
        char[] a = new char[2];
        a = reader.ReadChars(2);
        Int32 numberoffiles;
        numberoffiles = reader.ReadInt32();
        Console.Write("Reading: ");
        Console.WriteLine(a);
        Console.Write("NumberOfFiles: ");
        Console.WriteLine(numberoffiles);

这是我想在 C++ 中执行的。初始尝试(在第一个整数处失败):

 fstream fin("C://datafile.dat", ios::in|ios::binary|ios::ate);
 char *memblock = 0;
 int size;
 size = 0;
 if (fin.is_open())
 {
  size = static_cast<int>(fin.tellg());
  memblock = new char[static_cast<int>(size+1)];
  memset(memblock, 0, static_cast<int>(size + 1));

  fin.seekg(0, ios::beg);
  fin.read(memblock, size);
  fin.close();
  if(!strncmp("AB", memblock, 2)){ 
   printf("test. This works."); 
  }
  fin.seekg(2); //read the stream starting from after the second byte.
  int i;
  fin >> i;

编辑:似乎无论我在哪个位置使用“seekg”,我都会收到完全相同的值。

4

4 回答 4

5

您意识到 char 在 C# 中是 16 位,而不是通常在 C 中的 8 位。这是因为 C# 中的 char 旨在处理 Unicode 文本而不是原始数据。因此,使用 BinaryWriter 写入字符将导致写入 Unicode 而不是原始字节。

这可能会导致您错误地计算整数的偏移量。我建议您在十六进制编辑器中查看该文件,如果您无法解决问题,请在此处发布文件和代码。

EDIT1
关于您的 C++ 代码,不要使用 >> 运算符从二进制流中读取。将 read() 与要读取的 int 的地址一起使用。

int i;
fin.read((char*)&i, sizeof(int));

EDIT2
从封闭的流中读取也会导致未定义的行为。您不能调用 fin.close() 然后仍然期望能够从中读取。

于 2009-10-06T13:46:23.843 回答
3

这可能与问题有关,也可能无关,但是...

创建 BinaryWriter 时,它默认以charUTF-8 编写 s。这意味着它们中的一些可能比一个字节长,从而使您无法搜索。

您可以通过使用 2 参数构造函数来指定编码来避免这种情况。的实例与System.Text.ASCIIEncodingC/C++ 默认使用的实例相同。

于 2009-10-06T13:52:18.900 回答
1

如果有任何帮助,我在这里介绍了 BinaryWriter 如何写入数据。

已经有一段时间了,但我会引用它并希望它是准确的:

  • Int16 被写入 2 个字节并被填充。
  • Int32 写为 Little Endian 和零填充
  • 浮点数更复杂:它获取浮点值并取消引用它,获取十六进制的内存地址内容
于 2009-10-06T13:55:51.367 回答
1

您的 C++ 代码段中有很多问题。您不应该将二进制阅读与格式化阅读混为一谈:

  // The file is closed after this line. It is WRONG to read from a closed file.
  fin.close();

  if(!strncmp("AB", memblock, 2)){ 
   printf("test. This works."); 
  }

  fin.seekg(2); // You are moving the "get pointer" of a closed file
  int i;

  // Even if the file is opened, you should not mix formatted reading
  // with binary reading. ">>" is just an operator for reading formatted data.
  // In other words, it is for reading "text" and converting it to a 
  // variable of a specific data type.
  fin >> i;
于 2009-10-06T14:07:29.710 回答