[英]How to read in specific data from a text file (C)?
我是C语言的新手(也是本网站的新手),并且对我正在从事的项目有疑问。 我卡住的部分是文件I / O东西,因为我在上一堂课中从未学过。 因此,输入(.txt)文件如下所示:
REGISTERS
R5 11
R7 15
R21 4
MEMORY
4 12
12 92
[OTHER STUFF]
该文件为我们提供了任意的寄存器编号,后跟其内容(R0至31,省略了值为0的Regs)。 下一节将以类似的格式给出存储位置,然后再次显示内容。 然后是我以后可以处理的更多部分。
我的问题是:如何读取寄存器/内存位置及其值? 目前,我有一个大小为32的数组来存储内容,还有一个用于Reg号和值的变量(例如:Registers [regNumber] = regValue;),但是我不知道如何在单词REGISTERS之后正确开始读取值。
我试过的
我环顾四周,设法读入只有一行的测试输入文件:“ R5 11”。 为此,我做到了:
fscanf(file_ptr, "R%d %d", ®Number, ®Value);
我打印了变量regNumber,regValue,它们正确地给了我5和11。但是,对于单词REGISTERS之后的任意数量的行,我如何在单词MEMORY处停下来呢?
我假定无论解决方案是什么,我都可以做同样的事情来读取MEMORY的位置和值。
您可以使用fgets()读取文本文件的整行,然后使用strcmp或strncmp替换“ REGISTERS”和“ MEMORY”字符串文字的行。
您的input.txt格式化“ REGISTERS”之后的所有内容的格式都相同,直到“ 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", ®Number, ®Value); //parse known string format
do_something(®Number, ®Value);
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);
}
我不会在这里使用fscanf
,因为您无法向前看,看看下一行是REGISTERS
还是MEMORY
或其他。 从理论上讲,您可以检查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
类的函数parse_registers
对行进行真正的解析,例如:
int parse_registers(const char *line, int *registers)
{
if(line == NULL || registers == NULL)
return 0;
int regNumber, regValue;
if(sscanf("R%d %d", ®Number, ®Value) != 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
函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.