【问题标题】:How to get a user input to open a file in C?如何获取用户输入以在 C 中打开文件?
【发布时间】:2018-12-01 01:07:56
【问题描述】:

所以我试图根据用户输入打开一个文件,但我只是不断收到我输入的内容。

这就是我所拥有的。

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

int main(void) 
{
  FILE* data;
  char a[144];
  printf("Enter a filename:\n");
  fscanf(stdin, "%143[^\t]", a);
  data = fopen(a, "r");
  printf("%s", a);
  fclose(data);
  return 0;
}

这是我的文本文件。

larry snedden 123 mocking bird lane
sponge bob 321 bikini bottom beach
mary fleece 978 pasture road
hairy whodunit 456 get out of here now lane

【问题讨论】:

  • 在用户输入完文件名后,我需要向用户显示文件中的内容。
  • 您打开文件,但实际上忘记从中读取。您只需再次打印文件名。 (也就是说,如果文件已成功打开,您可能想添加一个测试。)
  • 好的。我该怎么做?
  • fscanf(stdin, "%143[^\n]", a); 如果您使用[^\t],您将阅读并包含尾随换行符——这不是您想要的。 (除了不阅读data
  • “从文件中读取”?最好从另一个来源学习。这是非常非常基本的 C。从您之前的问题中,我得到的印象是您试图通过同化来学习,而不是参加任何推荐的结构化课程。逐步学习一门语言并不是 Stack Overflow 的目的。

标签: c arrays string file stdin


【解决方案1】:

您面临三个主要问题:(1)您从用户那里获取一个带有fscanf(stdin, "%143[^\t]", a); 的文件名,它将读取所有字符而不是tab(包括按Enter生成的尾随'\n' >),(2)打开用户输入的文件并将fopen的返回分配给data后,您无法知道文件是否实际打开(考虑到文件名中包含的尾部'\n' ,我怀疑它失败了); (3) 您从未真正从文件流data 中读取数据(这可能是件好事,因为您未能验证它实际上是打开的。

关键是验证程序中的每个关键步骤尤其是用户输入的每一点。每个函数都提供一个返回值——使用它们来验证函数是成功还是失败。

一个添加验证的简短示例(并在需要的地方声明一个常量——除非绝对需要,否则不要在代码中使用幻数——比如scanf 字段——宽度修饰符),例如

#include <stdio.h>

#define MAXC 1024   /* if you need a constant, define one (or more)
                           ( don't SKIMP on buffer size ) */

int main (void) 
{
    FILE* data = NULL;  /* initialize all variables */
    size_t nlines = 0;
    char a[MAXC] = "";

    printf("Enter a filename: ");

    /* VALIDATE EVERY SINGLE BIT OF INPUT */
    if (fscanf (stdin, " %1023[^\n]", a) != 1) {
        fputs ("user canceled input.\n", stderr);
        return 1;
    }
    /* open/VALIDATE file open for reading */
    if ((data = fopen (a, "r")) == NULL) {
        perror ("fopen-a");
        return 1;
    }

    printf ("file opened: %s\n\n", a);

    /* reuse buffer to read each line */
    while (fgets (a, MAXC, data) != NULL)
        /* fgets include '\n' in buffer if buffer of sufficient size */
        printf ("line[%3zu]: %s", nlines++ + 1, a);
    fclose(data);

    return 0;
}

输入文件示例

$ cat dat/file.txt
larry snedden 123 mocking bird lane
sponge bob 321 bikini bottom beach
mary fleece 978 pasture road
hairy whodunit 456 get out of here now lane

使用/输出示例

$ ./bin/fopen_file_from_user
Enter a filename: dat/file.txt
file opened: dat/file.txt

line[  1]: larry snedden 123 mocking bird lane
line[  2]: sponge bob 321 bikini bottom beach
line[  3]: mary fleece 978 pasture road
line[  4]: hairy whodunit 456 get out of here now lane

【讨论】:

    【解决方案2】:

    使用fgets() 读取整行输入:

    #include <stddef.h>  // size_t
    #include <stdlib.h>  // EXIT_FAILURE
    #include <stdio.h>   // FILE, fprintf(), fputs(), fgets(), fopen(), fclose()
    #include <string.h>  // strlen()
    
    enum { MAX_FILENAME_LENGTH = 120 };
    
    int main(void)
    {
        char filename[MAX_FILENAME_LENGTH + 2]; // + '\n' + '\0'
        if (!fgets(filename, sizeof(filename), stdin)) {
            fputs("Input error :(\n\n", stderr);
            return EXIT_FAILURE;
        }
    
        size_t length = strlen(filename);  // get rid of the newline at the end:
        if (length && filename[length - 1] == '\n')
            filename[--length] = '\0';
    
        // When the length of the string is not needed, the above if-statement
        // can be replaced as suggested by Jonathan Leffler:
        filename[strcspn(filename, "\n")] = '\0'
    
        FILE *input = fopen(filename, "r");
        if(!input) {
            fprintf(stderr, "Couldn't open \"%s\" for reading :(\n\n", filename);
            return EXIT_FAILURE;
        }
    
        // do stuff with input
    
        fclose(input);
    }
    

    请参阅this answer,了解如何将整个文件逐行读入内存。

    【讨论】:

    • 通过写filename[strcspn(filename, "\n")] = '\0';而不是三行以及条件和减量等来换行通常更简单。只要filename中有一个字符串,使用strcspn()就可以工作,即使它是空的。当然,有时有长度是有用的——但你不会在这里使用它。
    • @JonathanLeffler 谢谢,我添加了它作为替代方案。
    【解决方案3】:

    fscanf(stdin, "%143[^\t]", a) 用制表符读取输入端。您可以尝试另一种方法。而且你没有从文件流data中读取。

    #include <stdio.h>
    #include <string.h>
    int main(void) 
    {
       FILE* data;
       char a[144];
       printf("Enter a filename:\n");
       fscanf(stdin, "%s", a);  //use %s not 143[^t]
       data = fopen(a, "r");
    
       //read from the file
       char read_from_file[100];
       while (!feof(data)) {
           fgets(read_from_file, 1024, data);
           printf("%s", read_from_file);
       }
       print("\n")
    
       printf("%s", a);
       fclose(data);
       return 0;
    }
    

    名为file.txt的文本文件:

    larry snedden 123 mocking bird lane
    sponge bob 321 bikini bottom beach
    mary fleece 978 pasture road
    hairy whodunit 456 get out of here now lane
    

    输入

    file.txt
    

    输出

    larry snedden 123 mocking bird lane
    sponge bob 321 bikini bottom beach
    mary fleece 978 pasture road
    hairy whodunit 456 get out of here now lane
    file.txt
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-11
      • 2013-12-16
      • 2016-08-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多