我是C的新手,我正在尝试构建一个C程序,通过扫描文件直到EOF,挑选出包含某个关键字的行,然后在最后一行搜索后设置偏移量。当再次执行扫描时,它扫描文件,这次从保存的偏移量开始,一直向下直到EOF。
我正试图围绕文件I/O的不同函数包装我的头,我有麻烦拼凑过程调用fopen(), fseek(), fgets(), ftell()等做我想做的事情。谁能给我指出正确的方向,或者告诉我该怎么做?
谢谢!
我建议在您的情况下使用getline
进行读取,ftell
和fseek
用于获取/设置偏移量(strstr
用于搜索单个行)。
我不确定我理解你保存偏移量是关于什么的,但它可能看起来像这样:
int pick_lines(const char *filename, const char *keyword, long *offset)
{
FILE *fp;
char *line = NULL;
size_t len = 0;
if (offset == NULL || (fp = fopen(filename, "r")) == NULL)
return 1;
if (*offset > 0 && fseek(fp, *offset, SEEK_SET) != 0) {
fclose(fp);
return 1;
}
while (getline(&line, &len, fp) != -1) {
if (strstr(line, keyword) != NULL)
printf("%s", line); // or do something else with chosen line
}
if ((*offset = ftell(fp)) < 0) {
free(line);
fclose(fp);
return 1;
}
free(line);
fclose(fp);
return 0;
}
这里的offset
是一个输入/输出参数。它的解引用值用于查找给定的偏移量(从*offset == 0
开始),然后重置为新的偏移量。
这个函数只打印包含keyword
的每一行。如果您想返回一个行数组,则需要做一些额外的工作。
用法的一个例子可能是:
long offset = 0;
pick_lines(filename, keyword, &offset);
// append lines to file
pick_lines(filename, keyword, &offset);
// ...
你可以这样做(只是伪代码):
fopen();
offset = loadOffset();
fseek(offset); // set offset from previous run
while(!feof())
{
fgets();
if(searchKeyword() == true)
{
offset = ftell(); // getting the offset (after the line you just read)
doSomething();
}
}
saveOffset(offset);
fclose();
提示:小心使用feof();只有当输入操作因为EOF而失败时,它才返回true。如果文件指针处于EOF,但之前没有任何失败,则返回false。你必须处理这种情况
听起来您想要做的是用一个"header"开始文件,该"header"定义在哪里找到最后一个结果。通过这种方式,信息被写入并存储在文件本身中。8位十六进制值足以表示大小为4GB的文件中的偏移量。比如:
00000022<cr><lf>
Text...<cr><lf>
More text...<cr><lf>
~ <cr><lf> <-- this '~' is whatever we're looking for
Other stuff...<cr><lf>
我在这里做了一些假设。首先,这是在Windows上,其中文本行以<cr>
和<lf>
字符结束(分别为0x0D和0x0A)。如果是Unix,则仅为<lf>
。如果是Mac,它可以是<cr>
,或者其他任何一个。我在这个例子中计算了它们。这是假设ansi风格的字符串,这意味着8位编码(一个字符=一个字节的数据)。使用Unicode或其他字符串格式也可以实现相同的功能,只是注意它们可能不再是每个字符一个字节。(在Unicode中,每个字符是两个字节。因此,如果混合使用Unicode和ANSI字符串操作,将会出现麻烦。)
这里,"header"值是0x22或34十进制,如果从文件开头开始计算所有字符,在第34次计数时到达'~'。因此,"header"指向最后一次搜索结果的位置。
的工作原理是这样的:最初这个头值是零,所以你的代码会读到这个,并且知道它还没有被搜索。假设代码扫描整个文件,对每个字符加1,直到找到'~'字符。然后它返回到开头,将该计数值转换为8个文本字符(itoa
或sprintf
),并用它覆盖文件的这一部分。一个人发现、完成或重新处理整个事情以寻找更多的东西。现在,下次处理该文件时,您的代码将读取该头值,并将其从文本转换为uint
(atoi
),查找该文件到此偏移量加上一个(因为我们不想再次捕获此偏移量),然后再次开始扫描。
这里的其他人有一些很好的实际代码示例,可以开始试验。注意,如果要查找的不仅仅是一个字符,比如一个单词或一串数字,那么扫描部分会变得更慢、更复杂。复杂的"标记"扫描而不是简单的字符或单词被称为词典分析,这是另一个话题。谷歌Flex and Bison
或YACC
等