【问题标题】:How to write CSV fields on a binary file?如何在二进制文件上写入 CSV 字段?
【发布时间】:2019-09-06 05:47:06
【问题描述】:

我有以下代码:

typedef struct RegDados{

    char removido; //  deve ser inicializado com '-'
    int encadeamento; // deve ser inicializado com -1
    int nroInscricao; // nao aceita valores repetidos nem nulos
    double nota;
    char data[10]; // checar tipo
    char *cidade;
    int sizecid;
    char tagCampo4;
    char *nomeEscola;
    int sizesch;
    char tagCampo5;
}RegDados;

char * strtokEvenEmpty(char * s, const char * seps){

  static char * p = NULL;

  if (s != NULL)
    p = s;
  else if (p == NULL)
    return NULL;
  else
    s = p;

  while (*p) {
    if (strchr(seps, *p)) {
      *p++ = 0;
      return s;
    }
    p += 1;
  }
  return (*s) ? s : NULL;
}

const char * getfield(char* line, int num){

  const char * tok;

  for (tok = strtokEvenEmpty(line, ","); tok; tok = strtokEvenEmpty(NULL, ",\n")){
    if (!--num)
      return tok;
  }
  return NULL;
}

int main(){

  FILE * stream = fopen("trabalho1.csv.csv", "r+");
  FILE * ArqBin = fopen("test.bin","wb");
  RegDados regdados[5000];
  RegCab regcab;
  int i = 0;

  if(ArqBin == NULL) printf("Error");

  if (stream != NULL) {
    char line[1024];
    while (fgets(line, 1024, stream)) {  

      regdados[i].nroInscricao = atoi(getfield(line, 1));
      fwrite(&regdados[i].nroInscricao, sizeof(int), 1, ArqBin);

      regdados[i].nota =  atof(getfield(line, 2));
      fwrite(&regdados[i].nota, sizeof(double), 1, ArqBin); 

      strcpy(regdados[i].data, getfield(line, 3));                             
      fwrite(regdados[i].data, sizeof(char), 100, ArqBin);  

      regdados[i].cidade = getfield(line, 4);
      fwrite(regdados[i].cidade, sizeof(char), 100, ArqBin);

      regdados[i].nomeEscola = getfield(line, 5);
      fwrite(regdados[i].nomeEscola, sizeof(char), 100, ArqBin);  

      i++;
    }
    fclose(stream);
    fclose(ArqBin);
  }
  else{
    printf("Error");
  }
}

它已经解析了我文件的字段,但是我无法将它们写入二进制文件,因为当我尝试写入时,我会得到很多空字段,当我不写入时不会发生这种情况.

我的 CSV 文件如下所示:

nroInscricao,nota,data,cidade,nomeEscola

13893,353.9,26/11/2016,,FRANCISCO RIBEIRO CARRIL

13595,472.2,,Salgueiro,ALFREDO GUEDES

13894,614.4,28/11/2016,累西腓,JOAO DE MOURA GUIMARAES

13880,403.2,29/11/2016,Fortaleza,ANTONIO DIAS PASCHOAL PR

13881,373.7,,Sao Jose da Tapera,DONIZETTI TAVARES DE LIM

13882,394.8,01/12/2016,Sao Bernardo do Cam,JUSTINO GOMES DE CASTRO

如何将每个字段写入二进制文件?

【问题讨论】:

  • 除非我能理解 “因为它变得非常奇怪。” 的意思,否则我建议查看这个可能重复的 Read/Write to binary files in C
  • “get 真的很奇怪”不是描述。而且我没有看到您尝试在代码中的任何位置写入文件。
  • 你的#includes在哪里?
  • 解释你想要什么,'二进制'文件与csv文件相比有什么区别?
  • 我不知道,但在尝试您的代码时我也会收到此错误:error: unknown type name ‘RegCab’; did you mean ‘RegDados’?

标签: c file csv binary fwrite


【解决方案1】:

当我尝试写时,我得到很多空字段,而我不写时不会发生这种情况。

这是正常的,数字的内部表示可以包含几个0,例如:

fwrite(&regdados[i].nroInscricao, sizeof(int), 1, ArqBin);

如果regdados[i].nroInscricao 的值为 7 并且您的 int 是 32 位,则将写入 3 次 0 和 1 次 7(顺序取决于您使用的是小端/大端)。

当然和你写的固定大小的字符串一样,所以填充字符可以是任何值,包括0(没有初始化)


您使用 getfield 提取字段的方法很昂贵,因为您提取第一个令牌,然后要获得第二个令牌,您必须绕过第一个令牌,然后要获得第三个令牌,您必须绕过2个第一个令牌等。

更好的方法是先做getfield(line, 1) 然后getfield(NULL, 1) 得到第二个令牌,然后做getfield(NULL, 1) 得到第三个等等,所以实际上第二个参数总是1,你可以删除它的管理


你尝试打开trabalho1.csv.csv,可能你想打开trabalho1.csv


if(ArqBin == NULL) printf("Error");

if (stream != NULL) {

打印错误还不够,千万不要继续,可以

if(ArqBin == NULL) 
  printf("Error");
else if (stream != NULL) {

或者更好的替换

FILE * stream = fopen("trabalho1.csv.csv", "r+");
FILE * ArqBin = fopen("test.bin","wb");
...
if(ArqBin == NULL) printf("Error");

if (stream != NULL) {
  ...
}
else{
  printf("Error");
}

类似

FILE * stream = fopen("trabalho1.csv.csv", "r+");

if (stream == NULL) {
  fprintf(stderr, "cannot open input file rabalho1.csv.csv");
  return -1;
}

FILE * ArqBin = fopen("test.bin","wb");

if (ArqBin == NULL) {
  fprintf(stderr, "cannot open output file test.bin");
  fclose(stream); /* really useful if you do not stop execution */
  return -1;
}
...

【讨论】:

  • "您必须始终调用 getfield,将 1 作为第二个参数,所以实际上该参数是无用的,并且每次您必须返回下一个令牌"我真的不明白这部分,如果我一直传递 1 作为第二个参数,我只是用第一个字段的内容填充我的结构......
  • @RafaelaSouza 啊,是的,对不起,我想你在第二次通话中没有给出 line 而是 NULL。我编辑我的答案
  • @RafaelaSouza 为什么把读取的csv文件写成二进制文件,有什么兴趣?
  • 其实我还有很多事情要做,但是我真的卡在了那部分,谢谢!
猜你喜欢
  • 2014-03-14
  • 2021-05-13
  • 1970-01-01
  • 2010-10-15
  • 2013-08-24
  • 1970-01-01
  • 1970-01-01
  • 2015-07-02
  • 1970-01-01
相关资源
最近更新 更多