Search code examples
cfilefreadfseekftell

fseek() and ftell() fail in a loop


I need to loop trough a directory, data and read each file, that meets certain conditions, in a string and do something with it. For some reason it fails after the fseek call (the output is only the name of the first file in the directory).

Any idea what am I doing wrong?

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

void doAlgorithm(char *input) {
    printf("%s\n", input);
}

int main(int argc, char** argv) {
    struct dirent *dir;
    DIR *d = opendir("data");
    FILE *file;
    while ((dir = readdir(d)) != NULL) {
        if (strlen(dir->d_name) > 6 && dir->d_name[6] == 'i') {
            printf("Filename: %s\n", dir->d_name);
            file = fopen(dir->d_name, "r");
            fseek(file, 0, SEEK_END);
            long length = ftell(file);
            fseek(file, 0, SEEK_SET);
            printf(", Filesize: %ld\n", length);

            char *buffer = malloc(length + 1);
            fread(buffer, 1, length, file);
            buffer[length] = '\0';

            fclose(file);
            doAlgorithm(buffer);
        }
    }
    closedir(d);
    return (EXIT_SUCCESS);
}

Solution

  • Your problem is that you file = fopen(dir->d_name, "r"); doesn't know where that file is in the directory. you need to give it the full path. You can do this;

        struct dirent *dir;
       // put the directory path here. on windows is \ instead of /
        char *path = "/Users/adnis/CLion/Stackoverflow/testdir";
        char *slash = "";
        DIR *d = opendir(path);
        FILE *file;
            while ((dir = readdir(d)) != NULL) {
           if (strlen(dir->d_name) > 6 && dir->d_name[6] == 'i') {
                    printf("Filename: %s\n", dir->d_name);
                    int length = strlen(path);
            /*check if the path already contains a '/' at 
              the end before joining the filename to the directory*/
    
                    if(path[strlen(path)-1] != '/'){ //on windows is '\'
                       slash = "/";
                    }
    
                    length += strlen(dir->d_name)+2;
         // allocate memory for the new path
         // and make sure we have enough memory.
                    char *newpath = malloc(length);
    
                    assert(newpath != NULL);
    
                    snprintf(newpath,length,"%s%s%s",path,slash,dir->d_name);
    
                    file = fopen(newpath, "r");
                    if(file == NULL){
                        fprintf(stderr, "fopen: %s\n", strerror(errno));
                        break;
                    }
                    fseek(file, 0, SEEK_END);
                    long len = ftell(file);
                    fseek(file, SEEK_SET, 0);
    
                    char *buffer = malloc(len + 1);
                    fread(buffer, 1, len, file);
                    buffer[strlen(buffer)] = '\0';
    
                    printf("%s \n",buffer);
                    fclose(file);
                }
            }
            closedir(d);
            return (EXIT_SUCCESS);
    

    I suggest that when reading directory you have to also try and avoid reading "." and ".." since they are just current directory and previous directory. something like this will help. In your while loop

    if(strcmp(dir->d_name,".") == 0 || strcmp(dir->d_name,"..") == 0)
                continue;