C# の BinaryWriter から書き込まれたデータを読み取るための C++ の BinaryReader はありますか?
-
20-09-2019 - |
質問
C#のBinaryWriterを使用して、いくつかのint、char[]などをデータファイルに書き込みました。BinaryReader を使用してファイルを (C# で) 読み取ると、ファイルのすべての部分を完全に再作成できます。
ただし、C++ でそれらを読み戻そうとすると、いくつかの恐ろしい結果が得られます。fstream を使用してデータを読み戻そうとしましたが、データが正しく読み込まれませんでした。C++ では、次のように fstream を設定します。 ios::in|ios::binary|ios::ate
そしてseekkgを使って私の位置をターゲットにしました。次に、整数「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」を使用しても、まったく同じ値を受け取るようです。
解決
char は、C では通常 8 ビットですが、C# では 16 ビットであることがわかります。これは、C# の char が生データではなく Unicode テキストを処理するように設計されているためです。したがって、BinaryWriter を使用して文字を書き込むと、生のバイトではなく Unicode が書き込まれることになります。
これにより、整数のオフセットが間違って計算される可能性があります。16 進エディタでファイルを確認し、問題を解決できない場合は、ファイルとコードをここに投稿することをお勧めします。
編集1
C++ コードに関しては、バイナリ ストリームから読み取るために >> 演算子を使用しないでください。読み取り先の int のアドレスを指定して read() を使用します。
int i;
fin.read((char*)&i, sizeof(int));
編集2
閉じられたストリームから読み取ると、未定義の動作が発生します。fin.close() を呼び出しても、そこから読み取ることができると期待することはできません。
他のヒント
この月または問題に関連することはできませんが...。
あなたはBinaryWriterを作成すると、UTF-8での書き込みchar
sデフォルト。これは、それらのいくつかは、あなたの求めてオフに投げ、1バイトより長くてもよいことを意味します。
あなたはエンコーディングを指定するには2引数のコンストラクタを使用することによって、これを回避することができます。 System.Text.ASCIIEncoding
のは、何と同じになりますデフォルトではC / C ++を使用ます。
あなたの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;
何かの助けになれば、BinaryWriterがデータを書き込む方法を調べました ここ.
かなり時間が経ちましたが、正確であることを願って引用します。
- Int16 は 2 バイトとして書き込まれ、埋め込まれます。
- Int32 はリトル エンディアンとして書かれ、ゼロ埋めされます。
- フロートはさらに複雑です。float 値を取得して逆参照し、16 進数のメモリ アドレスの内容を取得します。