Чтение и запись в двоичный файл на C ++ - PullRequest
1 голос
/ 01 мая 2010

Мне нужно создать файл, содержащий «имя», которое является строкой-массивом char-, и «data», который является массивом байтов-массивом char в C ++, - но первая проблема, с которой я столкнулся, состоит в том, как отделить "имя" из "данных"? символ новой строки может работать в этом случае (при условии, что у меня нет «\ n» в имени), но у меня могут быть специальные символы в части «данные», поэтому нет никакого способа узнать, когда это заканчивается, поэтому я помещаю Значение int в файле перед данными, которые имеют размер «data»! Я пытался сделать это с помощью кода следующим образом:

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;
};

но в С ++ это было нелегко !!

Я также попробовал следующее:

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()) ??

Спасибо за помощь

Ответы [ 2 ]

3 голосов
/ 01 мая 2010

Во-первых, ваша запись / чтение в двоичном формате должно работать следующим образом (здесь 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;
}
0 голосов
/ 01 мая 2010

Ну, несколько проблем с вашим кодом:

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

Функция определяется следующим образом:

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

Итак, вы отправляете информацию в буфере, говоря, что она имеет размер 1 и число sizeof (буфер). Это может сработать для некоторых вещей, но, как правило, в обратном направлении. Попробуйте использовать:

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

Он не зависит от ширины символа и не имеет постоянных значений, о которых вам нужно беспокоиться (он будет работать практически для любой строки).

Еще одна незначительная вещь в этом:

 int number[1];

У вас есть одно целое число, поэтому вам нужно только использовать:

 int number;

Если вы встретите ошибки с fwrite после его изменения, используйте этот вызов:

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

Это запишет в файл значение одного целого числа.

После того, как вы это исправите, посмотрите, работает ли ваш код. Конечно, будет легче устранить неполадки с исправленными вызовами. :)

Кроме того, если вы планируете использовать длины полей (записанные в виде целых чисел в файле), вы захотите настроить какую-то систему для считывания длины, а затем данных, и у вас, вероятно, должно быть длина для каждого поля. Использование класса, безусловно, самый простой способ справиться с этим.

Edit: Вы можете захотеть использовать структуру и функцию вместо класса, или вы можете использовать класс с методами. Это не имеет значения, оба довольно просты. Struct / FUNC:

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);
}
...