从任何数据读取

时间:2018-11-01 02:48:53

标签: c fopen fgets data-files

我正在尝试编写允许任何文件名(Makefile,1.txt,abc.txt等)读取屏幕上输出的程序。看来可行,但是只能打印任何文件中最多10行中的一行。

/**
 * Get a filename from the command line or print "Usage: p6 <filename>\n" if it
 * is not provided and exit.  Use fopen(3) to open the file for reading. Then 
 * use fgets(3) to read at most 10 lines from the file and print them out to the
 * console.  You may assume that a line of text will not exceed 4096 characters.
 * Example input/output:
 * ./p6 Makefile 
 * CC=gcc
 * 
 * PROGS=p1 p2 p3 p4 p5 p6 p7 p8 p9 p10
 * 
 * # Linux defaults:
 * CFLAGS=-ggdb -pedantic -Wall
 * #CFLAGS=-O4 -Wall
 * LDFLAGS=-s
 * 
 * all:    $(PROGS)
 */
#include <stdio.h>
int main (int argc, char *argv[])
{
  if (argc < 2)
    {
      printf ("Usage: p6 <filename>\n");
    }

    FILE *fp;
    char str[60];

    /* opening file for reading */
    fp = fopen ("Makefile", "r"); //In the instruction says Makefile
    // When I run check command, I must use       
    //"/u1/lecture/instructor/.check/text/1.txt" for ".check" file

    if (fgets (str, 10, fp) != NULL)
      {
  puts (str);
      }
    fclose (fp);

    return (0);
  }

输出:

> p6:
> -2.5 output of program (p6) is not correct for input      '/u1/lecture/instructor/.check/text/1.txt':
> ------ Yours: ------ 
> man(1) General Commands Manual man(1)
> 
> ---- Reference: ---- 
> man(1) General Commands Manual man(1)
> 
> NAME
>        man - format and display the on-line manual pages
> 
> SYNOPSIS
>        man [-acdfFhkKtwW] [--path] [-m system] [-p string] [-C config_file]
>        [-M pathlist] [-P pager] [-B browser] [-H htmlpager] [-S section_list]
>        [section] name ...
> 
> --------------------

对于操作系统,我使用KDE Linux System提供的CS Instructor

2 个答案:

答案 0 :(得分:0)

以下建议的代码:

  1. 干净地编译
  2. 正确检查并处理错误
  3. 执行所需的功能
  4. 通过赋予有意义的名称来避免使用“魔术”数字
  5. 发生错误时以适当的返回值退出程序

现在,建议的代码:

#include <stdio.h>    // fopen(), fclose(), fgets(), fprintf(), printf(), perror()
#include <stdlib.h>   // exit(), EXIT_FAILURE

#define MAX_LINE_LEN 4096
#define MAX_LINES    10

int main (int argc, char *argv[])
{
    if (argc != 2)
    {
        fprintf ( stderr, "Usage: %s <filename>\n", argv[0]);
        exit( EXIT_FAILURE );
    }

    char buffer[ MAX_LINE_LEN ];

    /* opening file for reading */
    FILE *fp = fopen ( argv[1], "r"); //In the instruction says Makefile
    if( !fp )
    {
        perror( "fopen failed" );
        exit( EXIT_FAILURE );
    }

    int i = 0; 
    while( (i<MAX_LINES) && (fgets ( buffer, sizeof( buffer ), fp)) )
    {
        printf( "%s", buffer );
        i++;
    }
    fclose (fp);

    return (0);
  }

没有给出命令行参数的代码运行:

./untitled
Usage: ./untitled <filename>

运行带有有效文件名的代码:

./untitled untitled.c
#include <stdio.h>
#include <stdlib.h>

#define MAX_LINE_LEN 4096
#define MAX_LINES    10

int main (int argc, char *argv[])
{
    if (argc != 2)
    {

运行的文件名不存在的代码:

./untitled nonexistent.txt
 fopen failed: No such file or directory

答案 1 :(得分:0)

通过关注单词Makefile,您使问题变得比所需的复杂。那是一条红鲱鱼。您刚刚得到的示例之一恰好是打印Makefile的前十行。它不影响编写代码以仅从您在命令行上提供的任何文件名中输出前十行来读取。您可以自由地做同样的事情,并使用Makefile作为程序的输入,但是除了选择输入文件之外,它与当前的问题无关。

查看您现有的代码,您几乎可以正确地使用基本方法,但是如果使用if (argc < 2),则会丢失错误。您不仅要做简单的打印语句,还必须通过将控制权交还给外壳程序(例如return 1;)来处理错误,以便您的程序不会继续处理试图从永远不会打开的文件中获取数据的尝试

否则,您逻辑上就可以打印行了。只需执行以下操作,即输出在显示行之前显示的行号,然后显示最后显示的行数的总计,例如

#include <stdio.h>

#define MAXC 4096   /* if you need a constant, #define one (or more) */
#define NLINES 10   /* number of lines to read */

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

    char line[MAXC];    /* buffer to hold each line */
    size_t ndx = 0;
    FILE *fp = NULL;

    if (argc < 2) { /* validate adequate number of arguments */
        fprintf (stderr, "error: insufficient input.\n"
                         "usage: %s <filename>\n", argv[0]);
        return 1;
    }
    /* open file / validate file open for reading */
    if ((fp = fopen (argv[1], "r")) == NULL) {
        perror ("fopen(argv[1],\"r\")");
        return 1;
    }

    /* read/output each line while ndx < NLINES */
    while (ndx < NLINES && fgets (line, MAXC, fp))
        printf ("line[%2zu]: %s", ndx++ + 1, line);

    printf ("\ntotal lines read: %zu\n", ndx); /* print total lines */

    fclose (fp);
}

编译代码

始终启用编译器警告,并让编译器帮助您修复代码。要启用警告,请在您的-Wall -Wextragcc编译字符串中添加clang。 (添加-pedantic以获得其他一些警告)。对于clang,您可以使用-Weverything。对于 VS (在windoze上为cl.exe),添加/W3(或使用/Wall,但您会收到很多无关的与代码无关的警告)。阅读并理解每个警告。他们将确定任何问题以及发生问题的确切路线。 不要接受代码,直到代码干净地编译而没有警告。您只需听编译器试图告诉您的内容,就可以学到很多C语言。

示例输入文件

$ cat dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.

使用/输出示例

$ ./bin/tenlines dat/captnjack.txt
line[ 1]: This is a tale
line[ 2]: Of Captain Jack Sparrow
line[ 3]: A Pirate So Brave
line[ 4]: On the Seven Seas.

total lines read: 4

文件超过10行:

$ ./bin/tenlines dat/structaddrout.txt
line[ 1]:  K1, K2      720 Eucalyptus Ave 105    Inglewood, CA           89030
line[ 2]:  O1, O2      7659 Mckinley Ave         Los Angeles, CA         90001
line[ 3]:  G1, G2      20253 Lorenzana Dr        Los Angeles, CA         90005
line[ 4]:  N1, N2      20044 Wells Dr            Beverly Hills, CA       90210
line[ 5]:  H1, H2      5241 Del Moreno Dr        Los Angeles, CA         91110
line[ 6]:  F1, F2      20225 Lorenzana Dr        Los Angeles, CA         91111
line[ 7]:  C1, C2      5142 Dumont Pl            Azusa, CA               91112
line[ 8]:  J1, J2      5135 Quakertown Ave       Thousand Oaks, CA       91362
line[ 9]:  M1, M2      4819 Quedo Pl             Westlake Village, CA    91362
line[10]:  E1, E2      4851 Poe Ave              Woodland Hills, CA      91364

total lines read: 10

您可以轻松地将Makefile包含为要读取的文件(只是文本),以了解其价值。

仔细检查一下,如果还有其他问题,请告诉我。