【问题标题】:C opendir() not opening a directory?C opendir() 没有打开目录?
【发布时间】:2018-10-08 18:18:13
【问题描述】:

我在 C 方面的经验并不丰富,但在我的一门课程中有一个作业,我在打开目录时遇到了一些问题。

该计划的目的是(意译):

  1. 如果没有提供标志或目录,则列出当前目录中的文件名。
  2. 如果提供了标志 (-l),请列出有关每个文件的更多信息。
  3. 如果提供了标志和目录,请转到该目录并列出有关该目录中每个文件(或目录)的信息。不必通过子目录进行递归。

它不需要处理只得到一个目录但没有标志,或者一个无效的目录。这是更多的概念验证。

我已经设法满足第 1 部分和第 2 部分,但第 3 部分不断中断,出现分段错误。

我的代码如下:

void recursedirect(char* flag, char* directory)
{
    DIR* dir;
    struct dirent *entry;

    printf("Flag: %s\nDirectory: %s\n\n", flag, directory);

    if (flag == NULL)
    // No flag provided, therefore only do file names.
    {
        dir = opendir(".");
        entry = readdir(dir);

        while (entry != NULL) 
        {
            printf ("%s\n", entry->d_name);
            entry = readdir(dir);
        }
    }
    else if (strcmp(flag, "-l") == 0 && directory == NULL)
    // No directory provided, but flag provided
    {
        dir = opendir(".");
        entry = readdir(dir);

        while (entry != NULL) 
        {
            fileinfo(directory);
            entry = readdir(dir);
        }   
    }
    else if (strcmp(flag, "-l") != 0)
    {
        printf("Invalid flag.\n");
    }
    else
    // A directory is provided
    {
        dir = opendir(directory);

        if (dir != NULL)
        {
            entry = readdir(dir);

            while (entry != NULL) 
            {
                fileinfo(directory);
                entry = readdir(dir);
            }   
        }
        else
            printf("Something went wrong. It might be an invalid filename.\n");
    }
}

具体来说,最后的 else 语句给我带来了麻烦。我试过给它我能想到的任何文件路径,硬编码和其他,它仍然给我带来问题。我猜这很简单,但我没有足够的经验知道它是什么。

fileinfo 是一个函数,它打印出以DIRdirent 作为参数的文件信息。但是,我能说的最好的错误绝对不是该代码中的错误。

编辑:我犯了不分享所有内容的错误。我的主要方法很简单。

int main (int argc, char** argv)
{
    char* flag = argv[1];
    char* directory = argv[2];

    recursedirect(flag, directory);
}//main

它包括以下内容:

#include <dirent.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <fcntl.h>

fileinfo 函数如下(稍作编辑,因为我意识到我不再需要给它一个 DIR *dir 的参数):

void fileinfo(struct dirent *entry)
{
    struct stat fileStats;
    stat(entry->d_name, &fileStats);

    printf("File Name: %s\n", entry->d_name);
    printf("File Size: %d bytes\n", (int) fileStats.st_size);
    printf("Number of Blocks: %d\n", (int) fileStats.st_blocks);
    printf("Number of Links/References: %d\n", (int) fileStats.st_nlink);
    printf("I-Node: %d\n", (int) fileStats.st_ino);
    printf("Device ID: %d\n", (int) fileStats.st_dev);
    printf("User ID: %d\n", (int) fileStats.st_uid);
    printf("Group ID: %d\n", (int) fileStats.st_gid);

    stat("alphabet",&fileStats);
    printf("Time of Last Access: %s", ctime(&fileStats.st_atime));
    printf("Time of Last Modification: %s", ctime(&fileStats.st_mtime));
    printf("Time of Last Status Change: %s", ctime(&fileStats.st_ctime));

    stat(entry->d_name, &fileStats);
    printf("File Permissions: ");
    printf((int) (S_ISDIR(fileStats.st_mode)) ? "d" : "-");
    printf((int) (fileStats.st_mode & S_IRUSR) ? "r" : "-");
    printf((int) (fileStats.st_mode & S_IWUSR) ? "w" : "-");
    printf((int) (fileStats.st_mode & S_IXUSR) ? "x" : "-");
    printf((int) (fileStats.st_mode & S_IRGRP) ? "r" : "-");
    printf((int) (fileStats.st_mode & S_IWGRP) ? "w" : "-");
    printf((int) (fileStats.st_mode & S_IXGRP) ? "x" : "-");
    printf((int) (fileStats.st_mode & S_IROTH) ? "r" : "-");
    printf((int) (fileStats.st_mode & S_IWOTH) ? "w" : "-");
    printf((int) (fileStats.st_mode & S_IXOTH) ? "x\n\n" : "-\n\n");
}

关于失败输入的更多说明,./files./files -l 都可以。带有任何无效标志的./files 按预期捕获。但是,./files -l *any valid filepath* 始终失败。

一切都是在 c9.io IDE 的 Ubuntu 14.04.5 中使用 gcc 编译的。

谢谢!

编辑 2:我尝试删除并放回文件,但现在奇怪的是我没有收到错误。但是,现在它不会打印任何内容的完整文件信息。我会再排查一些问题。

编辑 3:我已修复它,但有一个例外。问题是检查标志的 if 语句不正确。显然 IDE 出了点问题。我现在收到此错误:Couldn't open MANPATH=/home/ubuntu/.nvm/versions/node/v6.11.2/share/man:/usr/local/rvm/rubies/ruby-2.4.0/share/man:/usr/local/man:/usr/local/share/man:/usr/share/man:/usr/local/rvm/man

看起来这不是代码,并且在某种程度上是 c9 服务器的问题。我尝试为源代码和编译代码文件提供完全权限,重新启动工作区,并重新启动 Apache2。谢谢大家的一切!

【问题讨论】:

  • (将代码缩进四个空格。如帮助弹出窗口中所示,有一个按钮。)
  • @usr2564301:不,你明白了——不用担心! :)
  • 旁白:我希望每个成功的opendir() 都有一个closedir()。我没有看到。
  • “它仍然给我带来问题。” --> 有什么问题? fileinfo(directory); 代码是可疑的。为什么会循环呢?应该是fileinfo(dir);fileinfo(entry) 还是fileinfo(entry-&gt;d_name)
  • "fileinfo 是一个函数,它打印出给定 DIR 和 dirent 作为参数的文件信息。" 是对人的描述。发布它的函数签名会更好。

标签: c file opendir


【解决方案1】:

除了chux 留下的 cmets,您还可以从重构代码以重用类似的块中受益。您提到您已经解决了第 1 部分和第 2 部分(由 if 语句中的前两个分支表示)。因此,理论上,以下 if 块会产生正确的输出。如果您简化它以减少代码重写,您可能会受益。

if (flag == NULL)
// No flag provided, therefore only do file names.
{
    dir = opendir(".");
    entry = readdir(dir);

    while (entry != NULL) 
    {
        printf ("%s\n", entry->d_name);
        entry = readdir(dir);
    }
}
else if (strcmp(flag, "-l") == 0 && directory == NULL)
// No directory provided, but flag provided
{
    dir = opendir(".");
    entry = readdir(dir);

    while (entry != NULL) 
    {
        fileinfo(directory);
        entry = readdir(dir);
    }   
}

您可以事先检查标志,然后设置一个变量,而不是这样写(在这种情况下,more_file_info != 0 告诉我们打印,如果标志无效,我们return)。

int more_file_info = 0;
if (flag != NULL) {
    if(strcmp(flag, "-l") == 0) {
        more_file_info = 1;
    } else {
        printf("Invalid flag.\n");
        return;
    }
}

然后,您可以按如下方式简化/重构上述(可能工作的)代码:

void recursedirect(char* flag, char* directory)
{
    DIR* dir;
    struct dirent *entry;
    int more_file_info = 0;

    printf("Flag: %s\nDirectory: %s\n\n", flag, directory);
    // Validate argument up front
    if (flag != NULL) {
        if(strcmp(flag, "-l") == 0) {
            more_file_info = 1;
        } else {
            printf("Invalid flag.\n");
            return;
        }
    }

    // The 'directory' parameter only changes opendir, so we reflect that here
    if(directory != NULL) {
        dir = opendir(directory);
    } else {
        dir = opendir(".");
    }
    // Adding some error checking, per comment
    if(dir == NULL) {
        printf("Couldn't open %s\n", directory);
        return;
    }
    // The readdir() loop is basically the same
    entry = readdir(dir);
    while (entry != NULL)
    {
        // Although we check a flag every time this loop runs,
        // it makes the code easier to follow
        if(more_file_info != 0) {
            printf ("%s\n", entry->d_name);
        } else {
            fileinfo(directory);
            // Or should this be:
            // fileinfo(entry);
        }
        entry = readdir(dir); 
    }
}

这消除了许多重复的代码,并有望使故障排除更容易。另请注意,这会处理指定目录但未指定标志的情况,您可以明确检查是否需要不同的行为。希望通过更多信息,我们可以提供更合适的答案。

【讨论】:

  • 在调用opendir 之后,您应该在调用readdir (dir) 之前检查dir 不是NULL。虽然如果dir 无效,readdir 将返回EBADF,但也不会对其进行检查。否则,请努力回答。
  • 我绝对同意,并将您的建议添加到我的回答中。我会注意到可以进行更多改进,但我的回答的目的不是编写一个完美的解决方案,而只是以一种可能使提问者更容易排除故障的方式重组给定的代码。肯定有更多的改进(例如使用strncmp 而不是strcmp,以防flag 不是\0 终止),我认为这些绝对是值得学习的宝贵经验,但这可能会影响解决最初的问题(发生在良好的输入上)。
  • 谢谢你!代码现在明显更干净了。我做了更多的故障排除,但我仍然遇到同样的错误。我尝试在读取文件而不是调用 fileinfo 时仅在 else 块中打印文件名,但仍然出现分段错误。我最好的猜测是它不想正确打开目录,这对我来说似乎很奇怪......我什至尝试将. 作为目录传递。硬编码时也会发生这种情况。
猜你喜欢
  • 1970-01-01
  • 2015-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多