2017-04-25 89 views
0

我想用二進制格式寫文件。我有我下面的代碼,但它以文本格式保存文件。用二進制格式寫文件

#include <iostream> 
#include <fstream> 

using namespace std; 

int main(){ 
    std::string ref = "Ecoli. 123"; 
    unsigned int size = 124; 

    std::ofstream supp_info_output("binary_file", std::ios::out | std::ios::binary); // saving file 
    supp_info_output << ref << std::endl; 
    supp_info_output << size << std::endl; 
    supp_info_output.close(); 

    std::ifstream supp_info_input("binary_file", std::ios::in | std::ios::binary); // loading file 
    std::string supp_info_line; 
    while(std::getline(supp_info_input, supp_info_line).good()){ 
     std::cout << supp_info_line << std::endl; 
    } 
    supp_info_input.close(); 
} 

在代碼中我寫了一些數據,然後再次讀取數據。閱讀和寫作沒有問題,但我需要二進制格式的文件。

+3

operator <<如果int給出,則寫入文本,簡單地說。如果你想有一個int的二進制數據,你必須寫出存儲在內存中的字節。 – Klaus

+0

@克勞斯哦!是不是每個數據元素都有大量的代碼呢 – AwaitedOne

回答

5

使用ofstream::write來寫入二進制數據和ifstream::read來讀取它們。請注意,您應該保存字符串的長度,因爲您應該知道要讀取多少個字節。

std::string ref = "Ecoli. 123"; 
unsigned int size = 124; 

std::ofstream supp_info_output("binary_file", std::ios::out | std::ios::binary); // saving file 
unsigned int stringLength = ref.length(); 
supp_info_output.write((char*)(&stringLength), sizeof(stringLength)); 
supp_info_output.write(ref.c_str(), ref.length()); 
supp_info_output.write((char*)(&size), sizeof(size)); 
supp_info_output.close(); 

這裏是如何閱讀:

std::string ref; 
unsigned int size; 

std::ifstream supp_info_input("binary_file", std::ios::in | std::ios::binary); // loading file 
unsigned int stringLength; 
supp_info_input.read((char*)(&stringLength), sizeof(stringLength)); 
ref.resize(stringLength); 
supp_info_input.read((char*)ref.c_str(), stringLength); 
supp_info_input.read((char*)(&size), sizeof(size)); 
supp_info_input.close(); 
+0

。而且很容易將對象及其大小劃分爲每個調用的單獨參數。如果有人需要編寫二進制數據,編寫自己的移位運算符就容易多了,這很容易。 – Klaus

+0

@Klaus然後它應該如何? – AwaitedOne

+0

@borisbn感謝您的回答,如何閱讀 – AwaitedOne

1

這是稍有難度比它看起來二進制寫入數據。我建議使用C FILE *接口,因爲很多C++程序員都會在文本模式下超載< <和>>來插入和提取更高級別的對象。當你去二進制時,你會失去它。

要插入一個整數,您需要知道它是16位還是32位,大端或小端。然後使用移位和掩碼並調用fputc()直接寫入字節。要插入一個asciiz字符串,請同樣調用fputc並確保您編寫了nul。

0

@Klaus是對的,如果你通過INT到< <在二進制文件中,它只是寫文本到文件。如果要將int binary寫入文件< <,則應將字節流傳遞給< <。例如,在您的代碼中,您需要每次使用< <寫入int的4個字節,然後將binary int寫入您的文件。您可以檢查下面的代碼:

#include "stdafx.h" 

#include <iostream> 
#include <fstream> 

using namespace std; 

union data { 
    int i; 
    char bytes[4]; 
}; 

int main(){ 
    data src; 
    src.i = 0xabcddcba; 

    std::ofstream supp_info_output("binary_file", ios::out | ios::binary); // saving file 
    supp_info_output << src.bytes[0]; 
    supp_info_output << src.bytes[1]; 
    supp_info_output << src.bytes[2]; 
    supp_info_output << src.bytes[3]; 
    supp_info_output.close(); 

    data dst; 
    dst.i = 0; 
    std::ifstream supp_info_input("binary_file", ios::in | ios::binary); // loading file 
    supp_info_input >> dst.bytes[0]; 
    supp_info_input >> dst.bytes[1]; 
    supp_info_input >> dst.bytes[2]; 
    supp_info_input >> dst.bytes[3]; 
    supp_info_input.close(); 

    std::cout << ((src.i == dst.i)?"Pass check.":"Failed check.") << std::endl; 

    getchar(); 
} 

我認爲< <二進制文件模式的行爲預期,因爲在二進制文件模式都應該被作爲一個字節流,無論其類型,如int,雙,短期治療int,...等。

2

從AwaitedOne回答我不喜歡爲每個輸出語句寫很多代碼。相反,我更喜歡讓shift運算符負載過重,以使用戶代碼更容易一些,並且不易出錯。

作爲一個起點,給出了下面的例子。沒有提供所有可能的重載,並且BinaryFile類也少於「準備生產」。它只是作爲一個可編譯的起點開始自己的調查。

請注意: 二進制文件不可移植,二進制表示可以從編譯器/ libc/other的版本更改爲版本。它也取決於操作系統和系統的永久性,以及體系結構(32對64位)和其他許多。

因此,除非您編寫具有定義的輸入/輸出格式的處理程序方法,否則通常不應將二進制數據用於使數據持久「稍後」使用。我的例子寫簡單的數據存儲的內存是非常愚蠢的,導致所有的問題被提及。隨意爲可交換二進制格式啓動自己的「完美」實現。

但不是重新發明輪子,有人應該使用隨時可用的實現。搜索「序列化程序」,你會發現一個很好的庫,如boost序列化和許多其他。

#include <fstream> 
#include <cstring> 

class BinaryOut: public std::ofstream 
{ 
    public: 
     BinaryOut(const char* fname): 
      std::ofstream(fname, std::ios::binary) 
    {} 

}; 

// use a generic func to use for everything which not handled in special way 
template < typename DataType > 
BinaryOut& operator << (BinaryOut& out, const DataType& data) 
{ 
    out.write((char*)&data, sizeof(DataType)); 
    return out; 
} 

// if pointer type, write not pointer but values which pointer points to: 
template < typename DataType > 
BinaryOut& operator << (BinaryOut& out, const DataType*& data) 
{ 
    out.write((char*)data, sizeof(DataType)); 
    return out; 
} 

// special case for char ptr (old style c string) which ends with '\0' 
// use old style c here (no std::string is involved) 
BinaryOut& operator << (BinaryOut& out, const char* ptr) 
{ 
    out.write(ptr, strlen(ptr)); 
    return out; 
} 

// may be some more overloads for << if needed... 

int main() 
{ 
    BinaryOut out("example.bin"); 

    int i=123; 
    double d=9.876; 
    double* ptrd=&d; 

    const char* dummy = "Ptr to Text"; 

    out << i << d << ptrd << "Hallo, this is a test" << dummy; 
}