简体   繁体   English

从C中的文本文件读取数据?

[英]Reading data from a text file in C?

So I'm pretty new at reading data from a text file in C. I'm used to getting input using scanf or hard coding. 因此,我在使用C语言从文本文件读取数据方面还很陌生。我习惯于使用scanf或硬编码来获取输入。

I am trying to learn how to not only read data from a text file but manipulate that data. 我正在尝试学习如何不仅从文本文件读取数据,而且如何处理该数据。 For example, say a text file called bst.txt had the following information used to perform operations on a binary search tree: 例如,假设一个名为bst.txt的文本文件具有以下信息,该信息用于对二进制搜索树执行操作:

insert 10
insert 13
insert 5
insert 7
insert 20
delete 5
delete 10
....

With that example, I would have the following code: 对于该示例,我将具有以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{ 
  FILE *fptr;
  char *charptr;
  char temp[50];

  fptr = fopen("bst.txt", "r");

  while(fgets(temp, 50, fptr) != NULL)
  {
    charptr = strtok(temp, " ");

    while(charptr != NULL)
    {
      charptr = strtok(NULL, " ");
    }
  }

return 0;
}

I know that within the first while loop strtok() splits each line in the text file and within the second while loop strtok() splits off when the program recognizes a space, which in this case would separate the operations from the integers. 我知道在第一个while循环中strtok()会拆分文本文件中的每一行,而在第二个while循环中strtok()会在程序识别出空格时拆分,在这种情况下,这会将操作与整数分开。

So my main question is, after, for example, the word "insert" is separated from the integer "10", how do I get the program to continue like this: 所以我的主要问题是,例如,将单词“ insert”与整数“ 10”分开后,如何使程序像这样继续:

if(_____ == "insert")
{
  //read integer from input file and call insert function, i.e. insert(10);
}

I need to fill in the blank. 我需要填写空白。

Any help would be greatly appreciated! 任何帮助将不胜感激!

you can call as follows.For example i have put printf but you can replace your insert/delete function instead that. 您可以按如下方式调用。例如,我放置了printf但是您可以替换为insert/delete函数。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{ 
  FILE *fptr;
  char *charptr;
  char temp[50];

  fptr = fopen("bst.txt", "r");

  while(fgets(temp, 50, fptr) != NULL)
  {
    charptr = strtok(temp, " ");

    if(strcmp(charptr,"insert")==0)
    {
      charptr = strtok(NULL, " ");

      printf("insert num %d\n",atoi(charptr));
    }
    else if(strcmp(charptr,"delete")==0)
    {
      charptr = strtok(NULL, " ");

      printf("delete num %d\n",atoi(charptr));
    }
  }

return 0;
}

I think the best way to read formatted strings in file is using fscanf , the following example shows how to parse the file. 我认为读取文件中格式化字符串的最佳方法是使用fscanf ,以下示例显示了如何解析文件。 You could store the charptr and value for further operations: 您可以存储charptrvalue以进行进一步的操作:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{ 
  FILE *fptr;
  char charptr[50];
  int value;

  fptr = fopen("bst.txt", "r");

  while (fscanf(fptr, "%s%d", charptr, &value) > 0)
  {
      printf("%s: %d\n", charptr, value);
  }

  return 0;
}

try this code 试试这个代码

int main(){
FILE *fp;
char character[50];
int value;
fptr = fopen("input.txt", "r");

while (fscanf(fp, "%s%d", character, &value) > 0)
{
  if(strcmp(character,"insert")==0){
      insert(value);//call you function which you want value is 10 or change according to file
  }
}
return 0;
}

If I were doing what you're doing, I would be doing it that way :) 如果我正在做您正在做的事情,那么我会那样做:)

I see a lot of people getting upvoted (not here, I mean on SO generally) for recommending that people use functions like scanf() and strtok() despite the fact that these functions are uniformly considered evil , not just because they're not thread-safe, but because they modify their arguments in ways that are hard to predict, and are a giant pain in the ass to debug. 我看到很多人因推荐人们使用scanf()strtok()之类的功能而感到愤慨(不是在这里,我一般意思是说SO),尽管事实上这些功能被统一认为是邪恶的 ,不仅仅是因为它们不是线程安全的,但是因为它们以难以预测的方式修改了参数,并且调试起来非常痛苦。

If you're malloc()ing an input buffer for reading from a file, always make it at least 4kB — that's the smallest page the kernel can give you anyway , so unless you're doing a bazillion stupid little 100-byte malloc() s, you might as well — and don't be afraid to allocate 10x or 100x that if that makes life easy. 如果您要malloc()ing用于读取文件的输入缓冲区,请始终使其至少为4kB-这是内核仍然可以为您提供的最小页面,因此,除非您要进行不那么笨拙的100字节小分配malloc() ,您也可能会这样,并且不要害怕分配10倍或100倍的价格,如果这样可以使生活变得轻松。

So, for these kinds of problems where you're dealing with little text files of input data, here's what you do: 因此,对于您正在处理输入数据的少量文本文件的此类问题,您可以执行以下操作:

  • malloc() yourself a fine big buffer that's big enough to slurp in the whole file with buckets and buckets of headroom malloc()自己是一个很好的大缓冲区,足够大,足以容纳整个桶中的净空
  • open the file, slurp the whole damn thing in with read() , and close it 打开文件,使用read()将整个该死的东西吞噬掉,然后关闭它
  • record how many bytes you read in n_chars (or whatever) 记录您在n_chars读取了多少字节(或其他内容)
  • do one pass through the buffer and 1) replace all the newlines with NULs and 2) record the start of each line (occurs after a newline!) into successive positions in a lines array (eg char **lines; lines=malloc(n_chars*sizeof(char *)) : there can't be more lines than bytes!) 一次通过缓冲区,然后1)用NUL替换所有换行符,然后2)将每行的开始(在换行符之后!)记录到lines数组中的连续位置中(例如char **lines; lines=malloc(n_chars*sizeof(char *)) :行数不能超过字节!)
  • (optional) as you go, advance your start-of-line pointers to skip leading whitespace (可选)进行时,前进行开始指针以跳过前导空格
  • (optional) as you go, overwrite trailing whitespace with NULs (可选)使用时,使用NUL覆盖尾随空白
  • keep a count of the lines as you go and save it in n_lines 保持行数并保存在n_lines
  • remember to free() that buffer when you're done with it 完成操作后,请记住free()该缓冲区

Now, what do you have? 现在,你有什么? You have an array of strings that are the lines of your file (optionally with each line stripped of leading and trailing whitespace) and you can do what the hell you like with it. 您有一个字符串数组,它们是文件的行(可选,每行前导空格和尾随空格都被去除),并且您可以使用它来做自己喜欢的事情。

So what do you do? 所以你会怎么做?

Go through the array of lines one-by-one, like this: 像这样一步一步地遍历所有行:

for(i=0; i<n_lines; i++) {
    if( '\0'==*lines[i] || '#' == *lines[i] )
        continue;
    // More code

}

Already you have ignored empty lines and lines that start with a "#". 你也许忽略空行和一些由“#”开始。 Your config file now has comments! 您的配置文件现在有注释!

long n;
int  len;
for(i=0; i<n_lines; i++) {
    if( '\0'==*lines[i] || '#' == *lines[i] )
        continue;
    // More code

    len = strlen("insert");
    if( 0== strncmp(lines[i], "insert", len) ) {
        n = strtol(lines[i]+len+1, &endp, 10);
        // error checking
        tree_insert( (int)n );
        continue;
    }

    len = strlen("delete");
    if( 0== strncmp(lines[i], "delete", len) ) {
        n = strtol(lines[i]+len+1, &endp, 10);
        // error checking
        tree_delete( (int)n );
    }
}

Now, you can probably see 10 ways of making this code better. 现在,您可能会看到使此代码更好的10种方法。 Me too. 我也是。 How about a struct that contains a keywords and a function pointer to the appropriate tree function? 包含关键字和指向适当树函数的函数指针的结构如何?

Other ideas? 还有其他想法吗? Knock yourself out! 把自己打昏!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM