【问题标题】:How can I move a file pointer to the next line in a file?如何将文件指针移动到文件中的下一行?
【发布时间】:2015-05-01 07:41:53
【问题描述】:

我正在尝试编写一个函数来读取一行,将每个字符保存到一个数组中,操作该字符数组,将结果打印到另一个文件,然后移动到文件中的下一行。

一些示例输入/输出如下(程序的目的是找到导数 - 但那部分代码工作正常。):

INPUT:
x
4x^4
91
sinx

OUTPUT:
1
16x^3
0
cosx

到目前为止我写的函数:

int main(){

    FILE *inptr = fopen("functions.txt", "r");
    FILE *outptr = fopen( "derive.txt", "w");

    if(inptr)
        derive(inptr,outptr);

    return 0;
}

void derive(FILE *inptr, FILE *outptr){
    int i;
    char in = '0';
    char array[MAX];

    while((in = fgetc(inptr)) != EOF){
        for(i = 0; in != '\n'; i++){
            fscanf(inptr, "%c", &in);
            array[i] = in;
        }
        manipulate(array, outptr); // Function that finds the derivative and prints to output file
    }
}

我的问题是:如何将文件指针 inptr 移动到下一行?

【问题讨论】:

  • fgets 有什么问题?
  • char line[12345]; while (fgets(inptr, line, sizeof line)) /* deal with line */;
  • char in = '0'; 应该是一个 int,否则 in != EOF 可能会失败。

标签: c file pointers c-strings


【解决方案1】:

如何将文件指针移动到文件中的下一行?

文件是字节的集合,其中字节的含义取决于文件格式。

“纯文本”是一组许多不同的文件格式;用不同的方式来编码字符(EBCDIC、ASCII、“扩展ASCII”的许多变体、UTF-8、UCS-2、UTF-16,...)和不同的方式来表示“行尾”(“\n” , "\r\n\", "\r")。

第一步是决定您的软件是否会采用一种特定风格的“纯文本”文件格式(并在其他所有情况下都被破坏 - 例如,当有人从不同的操作系统传输文件时),或者支持多种文件格式具有显式控制(使用命令行参数,以便用户可以告诉它哪种文件格式)和/或它是否会尝试自动检测(例如,假设 UTF-8,它也适用于 ASCII,然后自动检测检测“行尾”是什么,可能通过接受“\r”或“\n”,然后检查“\n”是否跟随“\r”或“\r”是否跟随“\n”)。

下一步是将字符从碰巧使用的任何文件格式转换为某种“标准”字符集(可能是编译器碰巧使用的任何字符集,也可能不是),同时丢弃垃圾(例如Unicode“字节顺序标记”之类的东西)和处理格式错误/损坏数据的可能性(例如,对于 UTF-8 非法的字节序列,对于 ASCII 非法的字节,......)和处理不需要的有效数据字符(NULL、BELL、DELETE、...)。

在“字符集验证、转换和过滤”之后,您可以立即进行“行尾检测”(可能使用状态机跟踪“前一个字符是'\r'”和“前一个字符是'\n' "; 并且可能计算空白字符并删除/删除行尾的所有尾随空白);并且可以将字符存储在数组中以备后用(如果它没有被丢弃或“行尾”)或调用“处理这一行”函数(如果它是“行尾”)。也不要忘记“文件结尾” - 当您仍在一行中间时,您可能会到达文件末尾(并且可以通过假装文件中的最后一行以“行尾”结尾来处理" 当它没有时)。

请注意,fscanf(inptr, "%c", &in); 非常糟糕(您可能将大部分 CPU 时间花在解析格式字符串 "%c" 的此函数上),您可以使用 fgetc() 作为“不那么糟糕”的替代方案;并且所有这些功能(fscanf()fgetc()fgets(),...)无论如何都几乎无法使用(除非您对“纯文本”文件格式实际上是哪种文件格式然后被破坏做出未知的编译器特定假设其他一切都是错误的),并且大多数功能都很慢。反而;你想考虑使用read()(这样你就可以处理一个充满字节的整个缓冲区,并避免每个字节的C库函数和/或内核API调用的开销),或者可能是mmap()

最后;您需要确保恶意攻击者不能(故意)提供单行中包含太多字符的文件。需要进行安全检查(例如if(i >= MAX) { // Array is full, can't add the next character to the array);然后可以输出错误消息(“Line too long at line number ...”)或使用动态调整大小的数组(例如,使用realloc() 函数来增加数组的大小)。

【讨论】:

    【解决方案2】:
    while((in = fgetc(inptr)) != EOF){
        for(i = 0; in != '\n'; i++){
            fscanf(inptr, "%c", &in);
            array[i] = in;
        }
        manipulate(array, outptr); // Function that finds the derivative and prints to output file
    }
    

    这里你不需要增加inptr,因为fscanf()在for循环中执行它的指针一直在增加,所以在下一个while循环中你将在下一行。


    在上面的代码中,您缺少任何行的第一个字符。,

    当您读取了一个字符但您没有使用该字符时,在下一个 for 循环中再次读取字符。

    【讨论】:

      【解决方案3】:
      int main(){
      
          FILE *inptr = fopen("functions.txt", "r");
          FILE *outptr = fopen( "derive.txt", "w");
      
          if(inptr)
              derive(inptr,outptr);
      
          return 0;
      }
      
      void derive(FILE *inptr, FILE *outptr){
          int i;
          char in = '0';
          char array[MAX],word[MAX];
          fseek(inptr,0,SEEK_SET);
          while((in = fgetc(inptr)) != EOF){
              for(i = 0; in != '\n'; i++){
                  fscanf(inptr, "%c", &in);
                  array[i] = in;
                  fgets(word,MAX,inptr); 
                  /* this should set the cursur of inptr to the next line :D */
              }
              manipulate(array, outptr); // Function that finds the derivative and               prints to output file
          }
      }
      

      【讨论】:

        【解决方案4】:

        使用函数fgets()逐行读取文件。

        【讨论】:

        • 欢迎来到 Stack Overflow!你应该更好地解释你的答案。即使它可以回答问题,您也应该提供更多信息,以便社区可以从中受益更多How to Answer
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-21
        • 1970-01-01
        • 1970-01-01
        • 2012-06-25
        • 2013-08-05
        相关资源
        最近更新 更多