如何从文本文件(C)中读取特定数据?

时间:2018-04-26 00:15:21

标签: c input file-io

我对C(以及本网站)有些新意,对我正在研究的项目有疑问。我坚持的部分是文件I / O的东西,因为我从来没有在我上一课中学到这一部分。因此,输入(.txt)文件如下所示:

REGISTERS
R5 11
R7 15
R21 4
MEMORY
4 12
12 92
[OTHER STUFF]

该文件为我们提供了任意的寄存器编号,然后是其内容(R0到31,省略了值为0的Regs)。下一节以类似的格式给出内存位置,然后再次显示内容。然后我可以处理更多的部分。

我的问题是:如何读取寄存器/存储器位置及其值?目前我有一个32位数组来存储内容,一个变量用于Reg数和值(例如:寄存器[regNumber] = regValue;),但我不知道如何在单词REGISTERS之后正确读取值。

我尝试了什么:

我做了一些环顾四周,我设法在一个只有一行的测试输入文件中读取:“R5 11”。为此我做了:

fscanf(file_ptr, "R%d %d", &regNumber, &regValue);

我打印了变量regNumber,regValue,它们正确地给了我5和11.但是如何在REGISTERS之后的任意行数处执行此操作并停在MEMORY一词?

无论解决方案是什么,我都可以在MEMORY位置和值中读取相同的内容。

2 个答案:

答案 0 :(得分:2)

您可以使用fgets()读取文本文件的整行,然后使用strcmp或strncmp读取" REGISTERS"和"记忆"字符串文字。

在" REGISTERS"之后,您的input.txt被格式化的方式具有相同的格式直到" MEMORY"以及" MEMORY"之后的所有内容。是相同的格式。也许以下类似的东西可行,尽管可能有更好的选择:

int main () {
   FILE *fp;
   char str[60];
   int input_type = 0; //you can enum this for the input types you have
   int line_num = 0;

   /* opening file for reading */
   fp = fopen("input.txt" , "r");
   if(fp == NULL) {
      perror("Error opening file");
      return(-1);
   }
   while( fgets (str, 60, fp)!=NULL ) { // dont really need the != NULL compare here.
      line_num++;
      /* Parse the next line in the file */
      if(strcmp(str,"MEMORY") == 0){
         //the next lines will be formatted like memory input lines
         input_type = 2; //This should be an enum or macro
         continue;
      }
      if(strcmp(str,"REGISTERS") == 0){
         //the next lines will be formatted like register input lines
         input_type = 1;//Also should be enum or macro
         continue;
      }
      switch(input_type){
         case 0:
            fprintf(stderr,"Failed to find REGISTER keyword%d\n",line_num);
            break;
         case 1:
            sscanf(str, "R%d %d", &regNumber, &regValue); //parse known string format
            do_something(&regNumber, &regValue);
            break;
         case 2:
            sscanf(str, "%d %d", &memNumber, &memValue); //parse known string format
            do_something_else(&memNumber, &memValue);
            break;
         default:
            fprintf(stderr,"Could not find input format at line %d\n",line_num);
            break;
      }
   }
   fclose(fp);

   return(0);
}

答案 1 :(得分:2)

我不会在这里使用fscanf,因为你不能向前看,看看下一个 行是REGISTERSMEMORY或其他。从理论上讲,你可以检查一下 返回值为fscanf但代码会很快变得非常混乱。

更好的解决方案是使用fgets来获取整行。如果线是相等的 到REGISTERS\n,然后你知道下一行是寄存器行等 解析本身可以使用sscanf完成,这类似于fscanf,而不是FILE*enum mode_t { REGISTERS = 0, MEMORY, ..., INVALID }; int parse_file(FILE *file_ptr, int *registers, int some_other_params) { if(file_ptr == NULL || registers == NULL) return 0; char line[1024]; enum mode_t mode = INVALID; while(fgets(line, sizeof line, file_ptr)) { if(strcmp(line, "REGISTERS\n") == 0) { mode = REGISTERS; continue; } else if(strcmp(line, "MEMORY\n") == 0) { mode = MEMORY; continue; } // keep adding if(strcmp.... as needed) if(mode == INVALID) { fprintf(stderr, "Invalid file format\n"); return 0; // or a better error handling } int ret; switch(mode) { case REGISTERS: ret = parse_registers(line, registers); break; case MEMORY: ret = parse_memory(line, some_other_args); break; ... } // evaluate ret and do error handling if necessary } return 1; } 缓冲区读取,它从字符串中读取。

所以,我做了:

mode

使用parse_registers作为解析状态,您可以确定您所在的部分 解析。然后你必须编写像parse_memory和...这样的函数 int parse_registers(const char *line, int *registers) { if(line == NULL || registers == NULL) return 0; int regNumber, regValue; if(sscanf("R%d %d", &regNumber, &regValue) != 2) { fprintf(stderr, "Invalid format for REGISTER section\n"); return 0; } if(regNumber < 0 || regNumber > 31) { fprintf(stderr, "Invalid register number %d\n", regNumber); return 0; } registers[regNumber] = regValue; return 1; } 用于对行进行真正的解析,例如:

parse_memory

现在,您可以实现parse_xxx和其他{{1}}函数 该文件的其他部分。