We help IT Professionals succeed at work.

How to read muliple files from command line with wildcard (in C)

apst
apst used Ask the Experts™
on
How can we read multiple files from a command line

eg.

file.exe  *.txt

where file.c is written in C.

I was able to read a single file input file using fopen(argv[1],"r")

But now need to read *.txt.

Appreciate your help.
thanks.
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
#include <stdio.h> void main(){      //Define the arrays for angle and sine      int a[25];      double s[25];     //Grab the filename      char* name = new char[];      printf("Load Sine Values\nFile Name: ");      gets(name);       //Create the file pointer and open it      FILE* in = fopen(name,"rt");       //Read from the file      int n = 0;      while(fscanf(in, "%i%lf", &a[n], &s[n]) == 2) n++;       //Display Proof      printf("\nLoaded %i entries from %s\n", n, name);      printf("---------------------------------------\n");      for(int k=0; k<n; k++)      {            printf("%5i%12.6f\n", a[k], s[k]);      }       //Close the file      fclose(in);       printf("Press Any Key to Continue...");      char temp[1];      gets(temp);}#include <stdio.h>

void main()
{
      //Define the arrays for angle and sine
      int a[25];
      double s[25];

    //Grab the filename
      char* name = new char[];
      printf("Load Sine Values\nFile Name: ");
      gets(name);

      //Create the file pointer and open it
      FILE* in = fopen(name,"rt");

      //Read from the file
      int n = 0;
      while(fscanf(in, "%i%lf", &a[n], &s[n]) == 2) n++;

      //Display Proof
      printf("\nLoaded %i entries from %s\n", n, name);
      printf("---------------------------------------\n");
      for(int k=0; k<n; k++)
      {
            printf("%5i%12.6f\n", a[k], s[k]);
      }

      //Close the file
      fclose(in);

      printf("Press Any Key to Continue...");
      char temp[1];
      gets(temp);
}

Author

Commented:
how does this help with reading the wildcard and multiple files in a directory?
In the folder where a.exe is are three files of interest:
=================
$ ls fil* *.txt
1.txt  2.txt  file.exe
=================

The code below shows how to get the file names.
#include <stdio.h>
#define PATH_MAX 256
int main() {

   FILE *fp;
   int status;
   char path[PATH_MAX];

   fp = popen("ls file.exe  *.txt", "r");
   if (fp == NULL) {
      /* Handle error */;
      perror("popen failed");
      return -99;
   }

   while (fgets(path, PATH_MAX, fp) != NULL) {
      printf("%s", path);
   }

   status = pclose(fp);
   if (status == -1) {
      /* Error reported by pclose() */
      perror("pclose error");
   } 
   else {
      /* Use macros described under wait() to inspect `status' in order
      to determine success/failure of command executed by popen() */
      printf("Goodbye\n");
   }
}

Open in new window

If you need to use argc, argv, then you can loop over the argv elements and concatenate these argv strings into one long string using strcat.
      http://www.cplusplus.com/reference/clibrary/cstring/strcat/

Keep in mind that in Unix, if you have a command like:
              $ ./a file.exe  *.txt
then your argv strings will not have *.txt - instead the *.txt gets expanded into the matched files.

However this will pass in the *.txt:
              $ ./a file.exe  "*.txt"
Top Expert 2009
Commented:
As in your other question (refer to http://www.experts-exchange.com/Programming/Languages/C/Q_26299135.html), I'd prefer not to use popen (it is a roundabout way of doing things). Rather use the existing functionality to read files, like opendir, readdir, closedir.

Or, since you're doing this on Windows, it's possible that you prefer the FindFirstFile/FindNextFile/FindClose approach :

        FindFirstFile : http://msdn.microsoft.com/en-us/library/aa364418%28VS.85%29.aspx
        FindNextFile : http://msdn.microsoft.com/en-us/library/aa364428%28v=VS.85%29.aspx
        FindClose : http://msdn.microsoft.com/en-us/library/aa364413%28v=VS.85%29.aspx

Some example code :

        http://msdn.microsoft.com/en-us/library/aa365200%28v=VS.85%29.aspx
>> since you're doing this on Windows
I didn't realize that - I don't see where this was mentioned. But, then just for completeness using my previous post, I'll show below code that works on Linux or Windows (using a WIN32 macro to make adjustments). Don't forget that after a fgets, you need to overwrite the '\n'.

>> Rather use the existing functionality to read files, like opendir, readdir, closedir.
I was considering that (hence the link in the related post that used opendir), but I didn't want to then have to apply a filter to match the specific and wildcard files. So, I ended up with popen. But, on reviewing this question one more time...

>> How can we read multiple files from a command line
Looking at your question again, if you want to open, process, close each file on the command line, one file at a time, then, as mentioned, any patterns on the command line will expand to the matched file list. In this case you can just loop over the filenames in the argv strings:

for( i=1; i<argc; i++ ) {
     file_handler = fopen(argv[i],"r");
     processFile( file_handler );
     fclose( file_handler );
}
Of course, add error handling to above.

If you need concurrency for all the open files, you could avoid popen and opendir, if you allow the wildcard or pattern matching to expand in the command line.

nFiles = argc-1; // assumed to be the number of files to open
FILE * fp[nFiles];  // one file pointer per file
If this last statement does not compile, then you can use malloc.

Then, in a loop: fp[i-1] = fopen(argv[i],"r"). But now you do not have to close a file to process more than one file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PATH_MAX 256

#ifdef WIN32
#define LIST_DIR "dir /B "
#define POPEN  _popen
#define PCLOSE _pclose
#else
#define LIST_DIR "ls"
#define POPEN  popen
#define PCLOSE pclose
#endif

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

   FILE *fp;
   FILE *fileHandler;
   int status;
   char path[PATH_MAX];
   int i;

   for(i=0; i< argc; i++ ) {
      printf("     %s\n", argv[i]);
   }
    printf("\n");

   fp = POPEN(LIST_DIR " file.exe  *.txt", "r");
   if (fp == NULL) {
      /* Handle error */;
      perror("popen failed");
      return -99;
   }

   while (fgets(path, PATH_MAX, fp) != NULL) {
      path[ strlen(path)-1 ] = 0; // overwrite \n
      printf("%s", path);
      fileHandler = fopen(path, "r");
      if( fileHandler == NULL ) {
         perror(path);
         printf(" got error opening file %s\n", path);
      }
      else {
         printf(" Success opening %s\n", path);
         fclose(fileHandler);
      }
   }

   status = PCLOSE(fp);
   if (status == -1) {
      /* Error reported by pclose() */
      perror("pclose error");
   } 
   else {
      /* Use macros described under wait() to inspect `status' in order
      to determine success/failure of command executed by popen() */
      printf("Goodbye\n");
   }
}

Open in new window

Top Expert 2009

Commented:
>> I didn't realize that - I don't see where this was mentioned.

Based on this :

>> file.exe  *.txt

.exe is the standard extension for executables on Windows.
Ah .. I didn't notice that since on Cygwin, the default executable is a.exe.