QGChi2
QGChi2

Reputation: 3

How to read data from all files in a directory using C Language?

I am trying to 1) Find all files in a directory and display them, 2) Open all found files and read data from them (characters) 3) Output the read data to the screen or a new file.

This is done in C Language and you will see below my current code. The problem that I am running into is that: I can find all the files in my directory and print them to the screen just fine (point 1 above), but when I try to open the found files and read data (characters) from them (point 2 above), I get a segmentation fault.

If I comment out the fscanf(entry_file, "%s", files); line below, but leave the entry_file = fopen(in_file->d_name, "r"); line, it compiles okay and writes the files to the screen. I also tried indexing the fscanf line with the int i (not shown below) and produced the same segmentation fault.

So, how can I read data from these found files? Thanks!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>

int main()
{
    DIR* dir;
    FILE *entry_file;
    struct dirent *in_file;
    char files[1000];
    int i;

    dir = opendir("/Users/tcn/data");

    if(dir==NULL){
        printf("Error! Unable to read directory");
        exit(1);
    }

    while( (in_file=readdir(dir)) != NULL) {
        if (!strcmp (in_file->d_name, "."))
            continue;
        if (!strcmp (in_file->d_name, ".."))
            continue;
        printf("%s\n", in_file->d_name);
        entry_file = fopen(in_file->d_name, "r");

        fscanf(entry_file, "%s", files); 
    }

    closedir(dir);
    fclose(entry_file);
    return 0;
}

Upvotes: 0

Views: 3876

Answers (3)

Arkku
Arkku

Reputation: 42129

The two most likely causes of the crash are not checking the return value of fopen – then either the fscanf or the fclose may crash when attempting to use entry_file when it's NULL – and the potential overflow of files.

Another problem which does not cause a crash is that the in_file->d_name does not contain the full path, but only the name of the file. So if you are testing the code inside /Users/tcn/data then it will appear to work, but it will fail elsewhere. Either prefix the filename with /Users/tcn/data/ or operate only on the current directory (.).

Fixes:

if ((entry_file = fopen(in_file->d_name, "r"))) {
    (void) printf("%s\n", in_file->d_name);
    if (fgets(files, sizeof files, entry_file)) { // or `while`?
        // do something with `files`, it will be overwritten for next file
    }
    (void) fclose(entry_file);
}

And remove the other fclose(entry_file) from the end of the code.

Also note that if you use this code with an arbitrary directory, it might contain pipes and/or device nodes that will hang forever when you attempt to read them.

Upvotes: 0

Weather Vane
Weather Vane

Reputation: 34585

You will need a function with a loop using fread() to replace the fscanf line, and do a hex dump. For one thing, you don't know if the files are text files or binary files. For another, the segfault could be coming from reading a binary file that contains no newline into char files[1000]; And even if the files are all text files, you cannot predict that your "generous" 1000 length is enough to hold the first line of text.

Upvotes: 0

Jashaszun
Jashaszun

Reputation: 9270

Seeing as you are correctly checking for NULL against dir and in_file before using them, the only other thing that could possibly be causing this is entry_file being null. Check it before using it:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>

int main()
{
    DIR* dir;
    FILE *entry_file;
    struct dirent *in_file;
    char files[1000];
    int i;

    dir = opendir("/Users/tcn/data");

    if(dir==NULL) {
        printf("Error! Unable to read directory");
        exit(1);
    }

    while((in_file=readdir(dir)) != NULL) {
        if (!strcmp (in_file->d_name, "."))
            continue;
        if (!strcmp (in_file->d_name, ".."))
            continue;
        printf("%s\n", in_file->d_name);
        entry_file = fopen(in_file->d_name, "r");
        if (entry_file != NULL) {
            fscanf(entry_file, "%s", files);
            /* whatever you want to do with files */
            fclose(entry_file);
        }
    }

    closedir(dir);
    return 0;
}

Note also that, as multiple other users have commented, you should close entry_file within the loop.

Upvotes: 2

Related Questions