【问题标题】:C++ Binary Read Write FilesC++ 二进制读写文件
【发布时间】:2019-09-18 06:45:49
【问题描述】:

好的,所以我在大学的第二学期已经完成了 c 并且现在正在做 c++ 在 DevC 中做项目。

目前我正在制作一个程序,该程序将在拥有和编辑数据库的同时执行商店的收费过程。

尝试写入和读取一个完整的结构,但工作量不大,所以我写下 2 个 int 数字并读取它们,但这在读取时获得随机数时也能工作,即使我写 txt 数字看起来还可以。

//write and read are different fucntion only 1 is called .
//file creation code
int AccountNumber=0;
ofstream FileCreator("Database.dat",ios::binary);   
FileCreator<<AccountNumber;
AccountNumber=1;
FileCreator<<AccountNumber;

//reading code

int AccountNumber=0;
ifstream FileCreator("Database.dat",ios::binary);
FileCreator.seekg(0,ios::beg);

FileCreator.read(reinterpret_cast<char*>(&AccountNumber), sizeof(AccountNumber));
cout<<AccountNumber<<endl;
FileCreator.read(reinterpret_cast<char*>(&AccountNumber), sizeof(AccountNumber));
cout<<AccountNumber<<endl;

我希望输出为 0 和 1,但得到的是 12592 和 12592。

【问题讨论】:

  • 对于二进制写入,使用std::ostream::write,而不是operator&lt;&lt;。因此,FileCreator&lt;&lt;AccountNumber 应替换为 FileCreator.write((char *) &amp;AccountNumber, sizeof(AccountNumber))
  • 你的意思是你期望 0 和 1(不是 50)
  • 你好 EJLH。无关,但您可能会感兴趣:minimal reproducible example.
  • @ThomasMatthews ooof 修复了它,谢谢:D。但为什么重要?
  • 以二进制打开仅在 Windows 下有用,不会将 \n 即时转换为 \c\n

标签: c++ file binary


【解决方案1】:

完成@Thomas Matthews 的回答

但是为什么重要呢?

在 Windows 之外您不会看到差异,在 Windows 下,如果文件以二进制模式打开,则 \n 将被保存/读取不变,否则写入 \n 会产生 \r\n 并读取 \c\n 会返回 \n .它就像 fopen 的 "r"/"rb" 和 "w"/"wb" 之间的区别。

您可以混合使用运算符&lt;&lt;/&gt;&gt; 并以二进制模式读/写,但您必须注意分隔符,例如:

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
  int AccountNumber = 123;

  {
    ofstream bin("bin",ios::binary);   

    bin << AccountNumber << '\n'; // a \n to finish the number allowing to read it later
    bin.write((char *) &AccountNumber, sizeof(AccountNumber));
  }
  {
    ofstream txt("txt");   

    txt << AccountNumber << '\n';
    txt.write((char *) &AccountNumber, sizeof(AccountNumber));
  }
  {
    ifstream bin("bin",ios::binary);

    AccountNumber = 0;
    bin >> AccountNumber;
    cout << AccountNumber << endl;

    // I have to read the \n with read() because >> bypass it.
    // Supposing I written '@' rather than '\n' `bin >> c;` can be used
    char c;

    bin.read(&c, 1);
    cout << (int) c << endl;

    AccountNumber = 0;
    bin.read((char *) &AccountNumber, sizeof(AccountNumber));
    cout << AccountNumber << endl;
  }

  return 0;
}

编译和执行(Windows 外):

pi@raspberrypi:/tmp $ g++ -pedantic -Wextra -Wall f.cc
pi@raspberrypi:/tmp $ ./a.out
123
10
123
pi@raspberrypi:/tmp $ cmp txt bin
pi@raspberrypi:/tmp $ 

我不是在Windows下所以要使用二进制模式还是不改变什么,这两个文件是相同的

【讨论】:

  • 我不确定,但我怀疑bin.read(&amp;c, 1); 在 Windows 上无法正常工作。 bin.ignore(); 可能会更好。
  • 事实证明,bin.read(&amp;c, 1);bin.ignore(); 在 Windows 上都不能以二进制模式工作。必须手动读取 2 个 EOL 字符。所以在 Windows 上混合流操作符和read/write 似乎要复杂一些。
  • @TedLyngmo 是的,\n 和 \c\n 之间的自动转换仅在使用运算符 > 时才有效,因此在 Windows 下,\n 的混合运算符/函数是一个问题
【解决方案2】:

对于写入二进制文件,使用std::ostream::write()方法,而不是operator&lt;&lt;

FileCreator.write((char *) &AccountNumber, sizeof(AccountNumber));

强制转换是必要的,因为将整数写入流没有过载。

请记住,readwrite 是为二进制 I/O 配对的。

编辑 1:固定长度和可变长度记录
请注意,您在书写和阅读时需要项目的size。这适用于固定大小/长度的数据项和结构。但是,它不适用于可变长度数据,例如文本。

对于可变长度记录,您可能希望先写入长度,然后写入数据:

static const char hello[] = "Hello";
static const unsigned int data_size(sizeof(hello) - 1);
FileCreator.write((char *) &data_size, sizeof(data_size));
FileCreator.write(&hello[0], data_size);

在上面的示例中,“- 1”在那里,因此终止 NUL 字符不会写入文件。二进制文件不需要这个,但是 YMMV(我在写入控制台和其他人类可读的流时使用这个习惯用法)。

【讨论】:

    猜你喜欢
    • 2019-04-20
    • 2013-07-10
    • 2020-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-03
    • 2021-06-22
    • 2012-01-26
    相关资源
    最近更新 更多