одна функция C для записи данных в текстовом или двоичном виде - PullRequest
2 голосов
/ 02 октября 2010

У меня есть функция C, которая записывает некоторые данные в текстовый файл. Данные состоят из чисел с плавающей точкой, целых и строк. это выглядит примерно так:

writeAsTextFile(  mystruct_t* myStructWithIntsFloatsAndStrings , const char* fileName);

для этого я использую вызовы fprintf;

Теперь я хотел бы написать те же данные, но в двоичном виде. Я мог бы написать вторую функцию writeAsBinaryFile и использовать вместо нее вызовы fwrite. Но тогда каждый раз, когда я буду вносить изменения в конструкцию mystruct_t, мне придется изменять и writeAsTextFile, и writeAsBinaryFile. И, конечно, соответствующие readAsTextFile и readAsBinaryFile. Кроме того, это увеличит размер кода. Поэтому я хотел бы иметь одну единственную универсальную функцию с одним аргументом bin-or-text, который бы выглядел так:

writeToFile( mystruct_t* myStructWithIntsFloatsAndStrings , const char* fileName, myEnumType_t eOption)

где option будет enum eBin = 0 и eTxt = 1, например. В зависимости от eOption функция будет записывать двоичные или текстовые данные.

Я не уверен, что было бы лучшим способом добиться этого. Должен ли я использовать fwrite также для написания текста, следует ли мне использовать макросы? (Я где-то видел использование директивы ##, но никогда не использовал ее) или инструкции switch / ifs везде, где мне нужно записать файл? Или я должен написать обобщенную функцию, такую ​​как myWriteFunction( void *data, char const type, myEnumType_t eOption)

что будет вызвано writeToFile?

Я не очень хорошо знаком с использованием fread / fwrite и макросов, поэтому приветствуются любые рекомендации, идеи и т. Д.,

Спасибо

Баба

Ответы [ 3 ]

1 голос
/ 02 октября 2010

Вы можете создать несколько функций для записи различных типов данных в struct:

writeInt(File *f, myEnumType_t eOption, int data);
writeFloat(File *f, myEnumType_t eOption, float data);
writeFloatArray(File *f, myEnumType_t eOption, float *data, size_t n_data);

.. тогда бинарный или текстовый тест скрыт в каждом из них.Ваша основная функция написания структуры будет выглядеть (без проверки ошибок):

writeToFile(mystruct_t *myStruct, const char *fileName, myEnumType_t eOption)
{
    const char *fmode = eOption == EOPT_BIN ? "wb" : "w";
    FILE *f = fopen(filename, fmode);

    writeInt(f, eOption, myStruct->a);
    writeInt(f, eOption, myStruct->b);
    writeFloatArray(f, eOption, myStruct->values, myStruct->n_values);
    /* ... */
 }

Таким образом, изменение структуры структуры может изменить только одно место.

Вы также можете реализовать разныефункции записи для различных «типов» уровня приложения - например, writeTemperature() может отличаться от универсального writeFloat().

1 голос
/ 02 октября 2010

Для вашей ситуации просто создайте функцию обтекания:

writeToFile(...,bool isBinary) {
  if (isBinary) {
    // write as binary file
  } else {
    // write as text file
  }
}

Что касается MACROS, они полезны, только если вы хотите, чтобы ВСЕ операции были либо двоичными, либо текстовыми:

#ifdef __BINARY
#define WriteToFile(a,b,c,d,e) WriteToBinary(a,b,c,d,e)
#else
#define WriteToFile(a,b,c,d,e) WriteToText(a,b,c,d,e)
#endif

Используется в winAPI для переключения между функциями ascii и функциями широких символов.

Кстати: если ваша структура содержит char * или std :: string, то содержимое строки не будет скопировано, только ее адрес. Это относится и к любым другим указателям, таким как int * или std :: vector.

0 голосов
/ 02 октября 2010

Во-первых, не объединяйте функции, практической экономии нет.

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

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

Таким образом, ваша функция чтения будет считывать размер структуры (когда она была записана) и узнает, сколько байтов нужно прочитать.Если ваша структура изменится, ваша программа сможет читать части из старой версии структуры, и новые члены в конце структуры будут неинициализированы.

EDIT

Написание структуры с указателями запишет значение указателя.Вы должны быть очень осторожны, когда читаете структуру, потому что указатель будет указывать на практически случайный мир памяти. B

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

...