如何阅读文本文件

时间:2018-06-01 21:03:28

标签: c file io

我正在尝试从文本文件中提取键值,但我无法确定如何找到值的结尾。这是文本文件的简短片段。

GIRRAFE: A tall spotted animal
LION: A short carnivore.
Prince: The son of a king.
Princess: The daughter of a king.

这是我的代码:

FILE *fp;
char line[20], word[20];
int i = 0, endind;

  fp = fopen(file, "r");
  if (fp==NULL){
    printf("Error parsing the file\n");
    exit(1);
  }
while (!feof(fp)){
  fgets(line, 100, fp);
      for (i;i<strlen(line);i++){
        if (line[i]=='.'){
          endind = i;
        }
      }
      for (i;i<endind;i++){
        word[i] = line[i];
          printf("%s\n",word);
      }


}

代码不是很好,因为我无法获得以完整空白换行符结尾的值。

2 个答案:

答案 0 :(得分:0)

从示例数据看,密钥在第一个'.'处结束 在字符串中。使用strchr(3)找到它。但它看起来像 值和整个项目以两个换行结束。对于 您需要编写代码以将段落读入字符串。 为此,malloc(3)和realloc(3)将是有用的。如果你有 如果已知最大尺寸,您当然可以使用固定大小的缓冲区。

将问题分解为多个部分。首先,阅读一个段落,然后找到 键结束的地方,然后找到值开始的位置。决定是否 两个换行符是值的一部分,以及句点是否为一部分 关键。

要阅读段落,请阅读一行。如果该行为空,您可以使用strcmp(line, "\n")确定该行,那么您已完成读取该值, 你可以继续前进否则,将该行附加到段落缓冲区。

一旦你将整个段落作为单个字符串,找到结束 密钥char *keyend = strchr(para, '.'),它将返回指向'.'字符的指针。您可以用null替换该字符(*keyend = 0) 现在para是一个带键的字符串。接下来推进keyend指针 到第一个非空白字符。有几种方法可以做到这一点。此时,keyend现在将指向该值。哪一个 给你para作为键的指针,keyend作为指针 值。有了这个,你可以更新你的哈希表。

我也会在整个过程中检查错误,并且可能会单独使用 更好地为段落,键和值命名的变量。修剪 关闭尾随换行符和其他数据验证是可选的。例如,如果段落根本不包含'.'字符会怎么样?

答案 1 :(得分:0)

你走在正确的轨道上。确定您是否有空行(在您的情况下)的简单方法是:

fgets(line, 100, fp);
if (*line == '\n')
    // the line is empty

注意: if (line[0] == '\n')是等效的。在每种情况下,您只需检查line中的第一个字符是否为'\n'。{{的索引表示法1}}等同于指针符号line[x],并且由于您正在检查第一个字符(例如*(line + x)),因此指针符号只是x=0

虽然您可以使用*line或任何其他方法来定位第一个strtok,但使用'.'或只是使用指针迭代(向下)缓冲区直到您找到第一个strchr()可能是一个更容易的方法。您的解析流程应该类似于:

'.'

关键是循环并处理输入的不同状态(空行 - 我们有一个单词+完整定义,readdef = 0; // flag telling us if we are reading word or definition offset = 0; // number of chars copied to definition buffer read line { if (empty line (e.g. '\n')) { // we have a full word + definition add definition to your list reset readdef flag = 0 reset offset = 0 } else if (readdef == 0) { // line with word + 1st part of definiton scan forward to 1st '.' check number of chars will fit in word buffer copy to word buffer (or add to your list, etc..) scan forward to start of definition (skip punct & whitespace) get length of remainder of line (so you can save offset to append) overwrite \n with ' ' to append subsequent parts of definition strcpy to defn (this is the 1st part of definition) update offset with length set readdef flag = 1 } else { // we are reading additional lines of definition get length of remainder of line (so you can save offset to append) check number of chars will fit in definition buffer snprintf to defn + offset (or you can use strcat) update offset with length } } add final defintion to list 我们需要开始一个新单词+定义,或{{1}我们正在为当前定义添加行)您可以将其视为状态循环。您只是处理输入文件提供的不同条件(或状态)。注意 - 您必须在读取循环后添加最终定义 (当readdef = 0返回readdef = 1时,您仍然在定义缓冲区中有最后一个定义)

以下是使用数据文件的简短示例。它只是输出单词/定义对 - 您可以将它们添加到列表中。您可以使用fgetsEOF的任意组合或按照下面的步骤操作,将数据文件解析为单词和定义。请记住,如果您发现无法使strtok适合您的数据的问题 - 您可以随时沿着缓冲区向下移动指针,比较每个字符并根据需要进行响应以解析数据。

您还可以使用strchrstrtok将多行定义添加到一起(或简单地添加指针和循环),但要避免使用snprintf,尤其是对于大缓冲区 - 它有一些性能损失,因为它每次都会将未使用的空间归零。

strcat

示例输入文件

strncpy

示例使用/输出

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

#define MAXW  128   /* max chars in word or phrase */
#define MAXC 1024   /* max char for read buffer and definition */

int main (int argc, char **argv) {

    int readdef = 0;        /* flag for reading definition */
    size_t offset = 0,      /* offset for each part of definition */
        len = 0;            /* length of each line */
    char buf[MAXC] = "",    /* read (line) buffer */
        word[MAXW] = "",    /* buffer storing word */
        defn[MAXC] = "";    /* buffer storing definition */
    /* open filename given as 1st argument, (or read stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    while (fgets (buf, MAXC, fp)) { /* read each line */

        char *p = buf;      /* pointer to parse word & 1st part of defn */

        if (*buf == '\n') {     /* empty-line, output definition */
            defn[offset-1] = 0; /* remove trailing ' ' left for append */
            printf ("defn: %s\n\n", defn);
            readdef = 0;        /* reset readdef flag - 0 */
            offset = 0;         /* reset offset - 0 */
        }
        else if (readdef == 0) {    /* line contais word + 1st part of defn */
            while (*p && *p != '.') /* find the first '.' */
                p++;
            if (p - buf + 1 > MAXW) {   /* make sure word fits in word */
                fprintf (stderr, "error: word exceeds %d chars.\n", MAXW - 1);
                return 1;
            }
            snprintf (word, p - buf + 1, "%s", buf);    /* copy to word */
            printf ("word: %s\n", word);                /* output word */
            while (ispunct (*p) || isspace (*p))   /* scan to start of defn */
                p++;
            len = strlen (p);               /* get length 1st part of defn */
            if (len && p[len - 1] == '\n')  /* chk \n, overwrite with ' ' */
                p[len - 1] = ' ';
            strcpy (defn, p);       /* copy rest of line to defn */
            offset += len;          /* update offset (no. of chars in defn) */
            readdef = 1;            /* set readdef flag - 1 */
        }
        else {                      /* line contains next part of defn */
            len = strlen (buf);                 /* get length */
            if (len && buf[len - 1] == '\n')    /* chk \n, overwite w/' ' */
                buf[len - 1] = ' ';
            if (offset + len + 1 > MAXC) {      /* make sure it fits */
                fprintf (stderr, "error: definition excees %d chars.\n",
                        MAXC - 1);
                return 1;
            }
            snprintf (defn + offset, len + 1, "%s", buf);   /* append defn */
            offset += len;  /* update offset */
        }
    }
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    defn[offset-1] = 0;     /* remove trailing ' ' left for append */
    printf ("defn: %s\n\n", defn);      /* output final definition */

    return 0;
}

仔细看看,如果您有其他问题,请告诉我。