Использование C — Как открыть каждый файл в каталоге по отдельности, предполагая, что ваша программа не находится в указанном каталоге

#c #directory #filestream

#c #каталог #filestream

Вопрос:

Итак, я некоторое время осматривался и не могу найти ответ на свой вопрос…

Я пытаюсь создать программу, которая, когда каталог вводится в аргумент командной строки, будет обращаться к каждому отдельному файлу в каталоге и сохранять имя файла в связанном списке. Затем программа будет маркировать содержимое файла и сохранять каждый токен в связанном списке, возглавляемом соответствующим именем файла. Список будет построен следующим образом:

 [ListHeader][file1.txt][file2.txt][file3.txt]...[filen.txt]
            [token 1  ][token 1  ][token 1  ]...[token 1  ]
            [token 2  ][token 2  ][token 2  ]...[token 2  ]
            [token n  ][token n  ][token n  ]...[token n  ]
  

Теперь я завершил функцию tokenizer / linked list . В текущем рабочем каталоге у меня нет проблем с открытием файлов с помощью команды filestream fopen() . Однако у меня возникли проблемы с открытием файла в новом каталоге.

Например, допустим, я ввожу:

 user@usermachine:~/Cprograms$ gcc -o d directorytokenizer.c
user@usermachine:~/Cprograms$ ./d test.txt
  

Где test.txt находится в том же каталоге (в приведенном выше случае Cprograms), что и сама программа.
Этот пример работает нормально.

Однако, если входные данные

 user@usermachine:~/Cprograms$ gcc -o d directorytokenizer.c
user@usermachine:~/Cprograms$ ./d testdirectory
  

где «testdirectory» — это каталог, содержащийся в каталоге Cprograms (testdirectory — это папка в Cprograms).

Моя программа отлично открывает каталог и может выводить имена файлов внутри каталога (я сделал это для отладки, и это сработало). Однако, когда я пытаюсь передать отдельные имена файлов в функцию, которая передает их в filestreams (fopen()), команда filestream не может найти файл.

Вот соответствующие части моего кода:

 //Sortedlist.h-

#ifndef SORTED_LIST_H
#define SORTED_LIST_H

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <ctype.h>

struct SLNodes
{
    char *word;
    struct SLNodes * next;
    int occurencecounter;
};
typedef struct SLNodes* SLNode;

struct SortedList_
{
    char * filename;
    SLNode Listhead;
    struct SortedList_ * nextfile;
};
typedef struct SortedList_* SortedList;

SortedList SLCreate();

void tokenstore(char *inputstr, SortedList NewList);


#endif

//indexer.c (truncated)-
//this is the mainfile

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <dirent.h>
#include "listheader.h"
#include "tokenstore.c"
#include "diropen.c"

int main(int argc, char *argv[])
{   
DIR *dip;
if (argc < 2)
    usage(argc, argv[0]);

if ((dip = opendir(argv[1])) == NULL)
{   
    printf("Not a directory, now attempting to open file...n");

    SortedList NewList = CreateNewList(argv[1]);

    NewList = tokenize(NewList, argv[1]);

    SLNode curr = NewList->Listhead;

    if (curr != NULL)
    {
        SLNode curr = NewList->Listhead;
        printf("The following alphabetized and tokenized list of words is in the file: %sn", NewList->filename);
        while(curr != NULL)
        {
            printf("<listbegin>n");
            printf("The word <%s> appears <%d> timesn", curr->word, curr->occurencecounter);
            printf("<endlist>nn");
            curr = curr->next;
        }
    }
    else
        printf("File did not contain any words. Please make sure to input a         file with words in it. Remember, words consist of upper case and lower case letters, and numbers... Nothing else.n");
}
else
{
    SortedList NewList = CreateNewList(argv[1]);
    printf("You have input a directory. Now attempting to open and sort...n");
    openadir(argv[1], NewList);
}
}

//diropen.c (truncated)-

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

SortedList openadir(char *dirname, SortedList NewList)
{
    DIR *inputdir;
    struct dirent *dirstruct;

    SortedList placeholder;

    int i = 0;

    /* DIR *opendir(const char *name);
     *
     * Open a directory stream to argv[1] and make sure
     * it's a readable and valid (directory) */
    if ((inputdir = opendir(dirname)) == NULL)
    {
            perror("opendir");
            return;
    }

    printf("Directory stream is now openn");

    /*  struct dirent *readdir(DIR *dir);
     *
     * Read in the files from argv[1] and print */
    while ((dit = readdir(dip)) != NULL)
    {
            i  ;
            printf("n%sn", dit->d_name);

            NewList->filename = dirstruct->d_name;
            NewList = tokenize(NewList, dirstruct->d_name);
            NewList->nextfile = malloc(sizeof(SortedList));
            placeholder = NewList->nextfile;
            placeholder->filename = NULL;
            placeholder->Listhead = NULL;
            placeholder->nextfile = NULL;  
            NewList = placeholder;                           
    }
}

//tokenstore.c (truncated) - 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <ctype.h>
#include "listheader.h"


SortedList tokenize(SortedList NewList, char *filename) //tokenize the input file
{
printf("filename is : %sn", filename);
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * 
 * The following function simply steps through the input file and records the total
 * character count, in order to allocate a buffer of the correct size
 * to contain the eventual tokenized string.
 * 
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
FILE *fc = fopen(filename, "r");                            
if(fc == NULL)                                              
    fatal(": Input file does not exist");                   

int hold;                                                   
int count=0;                                                

do                                                          
{                                                           
    hold = fgetc(fc);                                       
    count  ;                                                
}                                                           
while( hold != EOF );                                       
fclose(fc); 
}
  

Теперь, как я уже говорил ранее, ввод имени файла, который находится в том же каталоге, что и программа, работает нормально, когда я пытаюсь передать имена файлов в fopen из другого каталога, программа выдает фатальный: file not found . (функция фатальной ошибки не включена в исходный код, который я опубликовал, но он работает нормально).

Мой вопрос в том, как мне передать имена файлов из другого каталога в fopen() таким образом, чтобы программа открывала файлы?

Спасибо, что нашли время, чтобы прочитать все это.

Ответ №1:

d_name Член struct dirent содержит, как вы заметили, только имя файла. Он не содержит имени каталога.

Все, что вам нужно сделать, это объединить имя каталога, разделитель каталогов и эту d_name строку, чтобы получить относительный путь, с которым вы можете использовать fopen .

Также обратите внимание:

 NewList->filename = dirstruct->d_name;
  

Это нехорошо. Вы должны скопировать эту строку, если хотите ее сохранить.

Ваша tokenize объявленная функция возвращает a SortedList , но она ничего не возвращает.

Пожалуйста, убедитесь, что вы включили предупреждения вашего компилятора.

Комментарии:

1. Или вы можете chdir() сначала перейти в каталог.

2. Да, chdir работает, но я стараюсь избегать этого, особенно в том, что может оказаться в «библиотечном» коде. Вы должны быть осторожны, чтобы вернуться в начальный каталог, и чтобы все, что вы вызываете из обхода каталога, знало, что вы cd редактируете. Упрощает код (меньше манипуляций со строками / вероятность утечки), поэтому в этом случае это может быть хорошо.

Ответ №2:

Вы можете сначала открыть каталог с open помощью, а затем получить доступ к файлам внутри него с openat помощью .