2009-10-06 96 views
1

我已經用C#中的BinaryWriter寫了幾個int,char []和數據文件。用BinaryReader將文件讀回(在C#中),我可以完美地重新創建文件的所有部分。在C++中是否有BinaryReader讀取從C#中的BinaryWriter寫入的數據?

但是,試圖用C++讀取它們會產生一些可怕的結果。我正在使用fstream嘗試讀取數據,並且數據沒有正確讀取。在C++中,我用ios::in|ios::binary|ios::ate設置了fstream,並使用seekg來定位我的位置。然後我讀取下四個字節,它們被寫爲整數「16」(並正確讀入C#)。這讀取1244780在C + +(不是內存地址,我檢查)。爲什麼會這樣?在C++中是否有與BinaryReader相當的功能?我注意到它在msdn上提到,但這是Visual C++和intellisense甚至不像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」來,我收到完全相同的值。

+0

你能告訴我們一段代碼(或整個代碼)和一個二進制文件的例子嗎? – coelhudo

+0

我已經發布了一些代碼。不知道我可以在哪裏上傳二進制文件。 – Chris

+0

你閱讀你的C#閱讀器中的chris.dat和你的C++閱讀器中的datafile.dat ... – Pondidum

回答

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(),然後仍然期望能夠讀取它。

+1

c/C++ char可以以UTF-8字符串的形式處理unicode。 – anno

3

這可能會或可能不會進行相關的問題,但...

當您創建的BinaryWriter,它默認爲UTF-8書寫char秒。這意味着它們中的一些可能比一個字節長,從而拋棄了你的尋求。

您可以通過使用2參數構造函數來指定編碼來避免這種情況。 System.Text.ASCIIEncoding的實例將與C/C++默認使用的實例相同。

+0

'ASCIIEncoding'的問題是它會以無聲方式破壞非ASCII字符。 – CodesInChaos

+0

對於這樣的互操作,您絕對不能使用C#的字符串類型。除非你知道你在做什麼,現在不是這樣。使用byte []。即使像我這樣的高級程序員也害怕字符串類型。使用Ecoding變體將字符串轉換爲Byte Array,然後寫入其大小及其數據。使用Yacoby的方法在C++中讀取它,並使用一些Unicode庫,例如icu。 –

1

如果有任何幫助,我會瀏覽BinaryWriter如何寫入數據here

這已經有一段時間,但我會引用它,希望它是準確的:

  • 的Int16寫爲2個字節和填充。
  • 的Int32寫成小尾數和零填充
  • 花車更加複雜:它採用浮點值,並取消引用它,得到的內存地址的內容是一個十六進制
+0

int32是小端和0填充,這可能會導致一些問題?你能詳細闡述一下嗎? (對不起,還沒有檢查鏈接,它可能在那裏詳細說明) – Chris

+0

看起來像是C++ char相關,與整數無關,除了偏移量 –

+0

頁面未找到404。 –

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; 
+0

非常感謝。我很久沒有用過這類東西了,需要這些指出:) – Chris