0

我是 C 新手,我正在尝试构建一个 C 程序,它扫描文件直到 EOF,挑选出包含某个关键字的行,然后在搜索最后一行后设置偏移量。当再次执行扫描时,它会扫描文件,这次从保存的偏移量开始并继续向下直到 EOF。

我正试图围绕文件 I/O 的不同功能展开我的头脑,但我无法将调用 fopen()、fseek()、fgets()、ftell() 等的过程拼凑起来做我想做的事它要做。谁能指出我正确的方向或引导我完成完成这项工作所需的内容?

谢谢!

4

3 回答 3

1

在您的情况下,我建议您使用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);
// ...
于 2015-07-17T12:10:21.830 回答
0

听起来您想要做的是以“标题”开始文件,该标题定义了找到最后一个结果的位置。这样,该信息被写入并存储在文件本身中。一个 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 上,文本行以字符(分别为 0x0D 和 0x0A)终止<cr><lf>如果是 Unix,它将是<lf>唯一的。如果是 Mac,它可能是<cr>唯一的,也可能是其他任何一个。我在这个例子中计算了它们。这是假设 ANSI 样式的字符串,这意味着 8 位编码(一个字符 = 一个数据字节。)使用 Unicode 或其他字符串格式可以实现相同的功能,只需注意它们可能不再是每个字节特点。(在 Unicode 中,每个字符两个字节。因此,如果混合 Unicode 和 ANSI 字符串操作,可能会遇到麻烦。)

这里,“header”值是 0x22 或十进制 34,如果从文件开头开始计算所有字符,则在第 34 个计数处达到“~”。因此,“标题”指向找到最后一个搜索结果的位置。

它的工作原理是这样的:最初这个头值是零,所以你的代码会读到它并且知道它还没有被搜索过。假设代码扫描文件,每个字符加一,直到找到“~”字符。然后它回到开头,将此计数值转换为 8 个文本字符(itoasprintf),并用它覆盖文件的这一部分。一个人再次找到、完成或处理整个事情以搜索更多。现在下一次处理该文件时,您的代码读取此标头值,并将其从文本转换为uint( atoi),将文件查找到此偏移量加一(因为我们不想再次捕获此偏移量),然后开始再次扫描。

这里的其他人有一些很好的实际代码示例可以开始试验。请注意,如果您要查找的不仅仅是一个字符,例如一个单词或一系列数字,则扫描部分会变得更慢且更复杂。对“标记”而不是简单的字符或单词的复杂扫描称为字典分析,这是一个完全不同的主题。谷歌Flex and BisonYACC等。

于 2015-07-17T12:33:28.697 回答
0

你可以这样做(只是伪代码):

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。你必须处理那个案子。

于 2015-07-17T12:06:42.320 回答