Mus
Mus

Reputation: 19

Reading a file through STDIN in C

I am trying to run the following in cmd:

gcc my_mainFile

and then run the following:

a.exe 2 < file.ppm

Basically what it does is sees the value 2, calls a specific function based on that, and uses the contents inside the ppm file. However, I am unaware of how to access this file itself. I need to be using scanf() to read the file, but I don't have the format clear.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    if(*argv[1] - '0' == 2){
        //Open and read contents of the file
    }
}

Upvotes: 0

Views: 3731

Answers (1)

David C. Rankin
David C. Rankin

Reputation: 84642

Many Linux utilities allow you to pass the filename to read as the first argument or read from stdin by default. This allows you to read from a given filename, or to pipe or redirect output from another process to your code on stdin. To implement the alternative, you can take advantage that stdin has type FILE* and simply check whether a filename argument has been provided to read (and if so, open and read from that file), or read from stdin by default.

For example:

#include <stdio.h>

#define MAXC 1024   /* if you need a constant, #define one (or more) */

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

    char buf[MAXC]; /* buffer to hold entire line (adjust MAXC as needed) */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    while (fgets (buf, MAXC, fp)) {                 /* read each line of input */
        int a, b;                                   /* example variables */
        if (sscanf (buf, "%d %d", &a, &b) == 2) {   /* parse/validate values */
            /* do what you need with your values */
            printf ("a: %d    b: %d\n", a, b);
        }
    }

    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);

    return 0;
}

Above, fgets() is used to ensure a complete line on input is consumed with each read, preventing stray characters from be left unread in your input stream that will cause read failure (or infinite loop) on your next attempted read. Any values needed from the line are parsed with sscanf. This avoids a great number of pitfalls new C programmers fall into by attempting to read directly with scanf or fscanf before understanding how to detect and properly handle matching or input failures due to either a mismatch between the format specifier and input, or exhausting input before all specified conversions take place.

Examples

Piping input on stdin:

$ printf "1 2\n3 4\n" | ./bin/readfileorstdin
a: 1    b: 2
a: 3    b: 4

Example Input File

$ cat dat/2x2.txt
2 4
3 5

Handling File Directly or on stdin

Reading file directly:

$ ./bin/readfileorstdin dat/2x2.txt
a: 2    b: 4
a: 3    b: 5

Redirecting on stdin:

$ /bin/readfileorstdin < dat/2x2.txt
a: 2    b: 4
a: 3    b: 5

You don't have to do it this way, you can just read from stdin directly and avoid checking whether a filename was given -- but this method provides a lot of convenience and flexibility for input handling in just a few extra lines of code.

Upvotes: 2

Related Questions