【问题标题】:Reading and writing to binary file in C++在 C++ 中读取和写入二进制文件
【发布时间】:2010-05-01 15:52:16
【问题描述】:

我需要创建一个包含“name”的文件,它是一个字符串-char数组-和“data”,它是字节数组-C++中的char数组-但我面临的第一个问题是如何将“名称”来自“数据”?换行符在这种情况下可以工作(假设我的名称中没有“\n”),但我可以在“数据”部分有特殊字符,所以无法知道它何时结束,所以我放了一个文件中具有“数据”大小的数据之前的 int 值! 我尝试使用以下代码执行此操作:

if((fp = fopen("file.bin","wb")) == NULL)
{
    return false;
}
char buffer[] = "first data\n";
fwrite( buffer ,1,sizeof(buffer),fp );
int number[1];
number[0]=10;
fwrite( number ,1,1, fp );
char data[] = "1234567890";
fwrite( data , 1, number[0], fp );
fclose(fp);

但我不知道“int”部分是否正确,所以我尝试了许多其他代码,包括这个:

char buffer[] = "first data\n";
fwrite( buffer ,1,sizeof(buffer),fp );
int size=10;
fwrite( &size ,sizeof size,1, fp );
char data[] = "1234567890";
fwrite( data , 1, number[0], fp );

当我打开文件时,我在文件中看到 4 个“NULL”字符,而不是看到一个整数。这正常吗? 我面临的另一个问题是再次从文件中读取!我尝试阅读的代码根本不起作用:(我用“fread”尝试过,但我不确定是否应该使用“fseek”或者它只是读取它后面的另一个字符。

我想过使用如下的类,然后写和读回来:

class Sign
{
public:
char* name;
int size;
char* data;
};

但这在 C++ 中可不是件容易的事!!

我还尝试了以下方法:

void saveData(char* filename) {

    fstream filestr;
    int n;
    n=10;
    char* data= "1234567890";

    filestr.open (filename, fstream::out | fstream::binary);
    for (int j = 0; j<5 ; j++)
    {
       filestr << n;

       for (int i = 0; i < n; i++) {
            filestr << data[i];
       }
    }
    filestr.close();
}

void readData(char* filename) {
    fstream filestr;
    int n =0;

    filestr.open (filename, fstream::in | fstream::binary);
    int m =0;
    //while(!filestr.eof())
    while(m<5)
    {
        filestr >> n;

        char *data = new char[n];
        for (int i = 0; i < n; i++) {
            filestr >> data[i];
        }
        printf("data is %s\n",data);
        m++;
    }
    filestr.close();
}

但是阅读也没有工作。

在阅读时,我得到了奇怪的字符。


到目前为止,对我有用的代码是这样的:

void saveData(char* filename) {
    fstream filestr;
    char * name = "first data\n";
    int n;
    n=10;
    char* data= "asdfghjkl;";

    filestr.open (filename, fstream::out | fstream::binary);
    for (int j = 0; j<5 ; j++)
    {
        filestr << name;
        filestr << strlen(data);
        filestr << data;
    }
    filestr.close();
}


void readData(char* filename) {
    fstream filestr;
    int n =0;

    filestr.open (filename, fstream::in | fstream::binary);
    while(!filestr.eof())
    {
        string name;
        getline(filestr,name,'\n');
        printf("name is %s\n",name.c_str());

        filestr >> n;

        char *data = new char[n];
        for (int i = 0; i < n; i++) {
            filestr >> data[i];
        }
        printf("n is%d\ndata is %s\n",n,data);
    }
    filestr.close();
}

但是阅读中的问题是:

1-(我认为这不是一个真正的问题)除了实际数据之外,它还会打印其他字符。 2- 在readData 函数上,我得到输出 6 次(最后一次我将每个字段都作为空字段),而我只写了 5 次!有谁知道这是为什么?和while(!filestr.eof())有关系吗??

感谢您的帮助

【问题讨论】:

  • 我尝试使用刚刚编写的 readData 函数读取数据,但是当数据为 char* data= “asdfghjkl;”,有谁知道这是为什么?

标签: c++ file binaryfiles


【解决方案1】:

首先,您的二进制格式的写入/读取应该像这样(这里read_num 将在此读取序列之后包含10)。

   FILE* fp = fopen("file.bin", "wb");
   int num = 10;
   fwrite(&num, sizeof(int), 1, fp);
   fclose(fp);

   FILE* fp2 = fopen("file.bin", "rb");
   int read_num;
   fread(&read_num, sizeof(int), 1, fp2);
   fclose(fp2);

还要提一下,这种写法不是C++的方式,而是C的方式。 C++的文件操作方式是指流,见下例:

#include <fstream>
#include <string>

struct data_structure {
   std::string name;
   std::string description;
   int number;

   void save(const std::string& filename) {
      std::ofstream file(filename.c_str());
      file << name.c_str() << std::endl
           << description.c_str() << std::endl
           << number;
   }
   void load(const std::string& filename) {
      std::ifstream file(filename.c_str());

      getline(file, name);
      getline(file, description);
      file >> number;
   }
};

int main() {
   data_structure d, loaded_d;
   d.name = "Name";
   d.description = "Description";
   d.number = 5;

   d.save("file.out");
   loaded_d.load("file.out");

   return 0;
}

【讨论】:

  • 感谢第一部分,它确实有效。但是对于第二部分,问题是描述可能不止一行,并且可能包含换行符!
【解决方案2】:

好吧,您的代码存在一些问题:

fwrite( buffer ,1,sizeof(buffer),fp );

函数定义如下:

size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

所以你在缓冲区中发送信息,说它的大小为 1,并且 sizeof(buffer) 的计数。这可能适用于某些事情,但通常只是倒退。尝试使用:

fwrite(buffer, sizeof(char), strlen(buffer), fp);

这既与字符宽度无关,也没有您需要担心的常量值(它基本上适用于任何字符串)。

还有一个小事:

 int number[1];

你只有一个整数,所以你只需要使用:

 int number;

如果您在更改 fwrite 后遇到错误,请使用此调用:

fwrite( &number, sizeof(int), 1, fp);

这会将一个整数的值写入文件。

修复该问题后,查看您的代码是否有效。纠正这些调用肯定会更容易进行故障排除。 :)

另外,如果您打算使用字段长度(以整数形式写入文件),您将需要设置某种系统来读取长度,然后读取数据,并且您可能应该有一个每个字段的长度。使用类绝对是处理这个问题的最简单方法。

编辑: 您可能想要使用结构和函数而不是类,或者您可以使用带有方法的类。没关系,两者都很简单。结构/函数:

struct Record
{
    std::string name, data;
};

void writeRecord(Record thisRecord, std::string filename, size_t offset)
{
    if ( ( fp = fopen(filename.c_str(), "wb") ) == NULL ) { return NULL; }

    fwrite( thisRecord.size(), sizeof(unsigned int), 1, fp); // assuming size() return uint
    fwrite( thisRecord.name.c_str(), sizeof(char), name.size(), fp);

    // repeat for data or other fields
    fclose(fp);
}

【讨论】:

  • strlen(buffer) 和 sizeof(buffer) 有什么区别?至于整数,我仍然看到 "NULL""NULL""NULL" !请你能告诉我在这种情况下如何使用一个类吗?我试过但没用,我觉得比我做的要复杂一点:(
  • Strlen(buffer) 将计算缓冲区中的字符数(例如,“aaa”将返回 3)。 Sizeof(buffer) 将返回缓冲区中的字节数。如果您使用 Unicode,一个字符可以是两个字节,因此差异变得很大。至于整数,除非你有一个巨大的数字,否则期望一两个空值。在您的文件中,数字 32 将写入 0x00 0x00 0x00 0x20。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多