1

C# の BinaryWriter を使用して、いくつかの int、char[] などをデータ ファイルに書き込みました。BinaryReader を使用して (C# で) ファイルを読み込むと、ファイルのすべての部分を完全に再作成できます。

ただし、C++ で読み戻そうとすると、恐ろしい結果が生じます。fstream を使用してデータを読み戻そうとしましたが、データが正しく読み込まれませんでした。C++ で fstream を設定し、ios::in|ios::binary|ios::ateseekg を使用して自分の場所をターゲットにしました。次に、整数 "16" として書き込まれた次の 4 バイトを読み取ります (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 の 8 ビットではなく、C# では 16 ビットであることがわかります。これは、C# の char が生データではなく Unicode テキストを処理するように設計されているためです。したがって、BinaryWriter を使用して char を書き込むと、生のバイトではなく Unicode が書き込まれます。

これにより、整数のオフセットが正しく計算されない可能性があります。16 進エディタでファイルを確認することをお勧めします。問題が解決しない場合は、ファイルとコードをここに投稿してください。

EDIT1
C++ コードに関しては、バイナリ ストリームから読み取るために >> 演算子を使用しないでください。読み取り先の int のアドレスで read() を使用します。

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

EDIT2
閉じたストリームから読み取ると、未定義の動作が発生します。fin.close() を呼び出しても、そこから読み取ることができると期待することはできません。

于 2009-10-06T13:46:23.843 に答える
3

これは問題に関連している場合とそうでない場合がありますが、...

BinaryWriter を作成すると、デフォルトでchars が UTF-8 で書き込まれます。これは、それらの一部が 1 バイトよりも長く、シークに失敗する可能性があることを意味します。

これは、2 引数のコンストラクターを使用してエンコーディングを指定することで回避できます。のインスタンスはSystem.Text.ASCIIEncoding、デフォルトで C/C++ が使用するものと同じです。

于 2009-10-06T13:52:18.900 に答える
1

それが助けになるなら、私はBinaryWriterがここにデータを書き込む方法を調べました。

しばらく経ちましたが、引用して正確であることを願っています。

  • Int16は2バイトとして書き込まれ、パディングされます。
  • Int32はリトルエンディアンとして記述され、ゼロが埋め込まれます
  • フロートはより複雑です。フロート値を取得して逆参照し、16進数のメモリアドレスの内容を取得します。
于 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 に答える