Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从C列出Linux中的目录_C_Linux - Fatal编程技术网

从C列出Linux中的目录

从C列出Linux中的目录,c,linux,C,Linux,我正在尝试使用c中的LinuxAPI模拟linux命令ls。看看代码,它确实有道理,但当我运行它时,我得到了stat错误:没有这样的文件或目录。我已经检查了opendir是否正常工作。我认为问题在于stat,它返回-1,尽管我认为它应该返回0 我错过了什么 谢谢你的帮助 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <dirent.h> #include &l

我正在尝试使用c中的LinuxAPI模拟linux命令ls。看看代码,它确实有道理,但当我运行它时,我得到了stat错误:没有这样的文件或目录。我已经检查了opendir是否正常工作。我认为问题在于stat,它返回-1,尽管我认为它应该返回0

我错过了什么

谢谢你的帮助

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

int main(int argc, char *argv[])
{
 DIR *dirp;
 struct dirent *direntp;
 struct stat stat_buf;
 char *str;

 if (argc != 2)
 {
  fprintf( stderr, "Usage: %s dir_name\n", argv[0]);
  exit(1);
 }

 if ((dirp = opendir( argv[1])) == NULL)
 {
  perror(argv[1]);
  exit(2);
 }

 while ((direntp = readdir( dirp)) != NULL)
 {
  if (stat(direntp->d_name, &stat_buf)==-1)
  {
   perror("stat ERROR");
   exit(3);
  }
  if (S_ISREG(stat_buf.st_mode)) str = "regular";
  else if (S_ISDIR(stat_buf.st_mode)) str = "directory";
  else str = "other";
  printf("%-25s - %s\n", direntp->d_name, str);
 }

 closedir(dirp);
 exit(0);
}


这是因为您没有说明实际的文件。它在另一个目录中。如果需要真实的文件名,请将argv[1]和direntp->d_名称与“/”组合在一起

此外,匈牙利人的名字也很讨厌,甚至连结尾的小调都有点像“p”。如果你有这么多的变量,你需要用它们的名字来记录它们的类型,那你就做错了

以下是您计划的修订版本:

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#include <sys/param.h>

int main(int argc, char *argv[])
{
 DIR *dirp;
 struct dirent *direntp;
 struct stat stat_buf;
 char *str;
 char fullpath[MAXPATHLEN + 1];
 size_t dirnamelen;

 if (argc != 2)
 {
  fprintf( stderr, "Usage: %s dir_name\n", argv[0]);
  exit(1);
 }
 strncpy(fullpath, argv[1], MAXPATHLEN - 1); /* account for trailing '/' */
 fullpath[MAXPATHLEN - 1] = '\0';
 dirnamelen = strlen(fullpath);
 if (strlen(argv[1]) > dirnamelen) {
  fprintf( stderr, "Directory name is too long: %s", argv[1] );
  exit(2);
 }

 fullpath[dirnamelen++] = '/';
 fullpath[dirnamelen] = '\0';

 if ((dirp = opendir( argv[1])) == NULL)
 {
  perror(argv[1]);
  exit(2);
 }

 while ((direntp = readdir( dirp)) != NULL)
 {
  fullpath[dirnamelen] = '\0';
  if ((dirnamelen + strlen(direntp->d_name)) > MAXPATHLEN) {
   fprintf(stderr, "File %s + directory %s is too long.", direntp->d_name, fullpath);
   continue;
  } else {
   /* strncpy is mild overkill because the if statement has verified that
      there's enough space.  */
   strncpy(fullpath + dirnamelen, direntp->d_name, MAXPATHLEN - dirnamelen);
   fullpath[MAXPATHLEN] = '\0';
  }
  if (stat(fullpath, &stat_buf)==-1)
  {
   perror("stat ERROR");
   exit(3);
  }
  if (S_ISREG(stat_buf.st_mode)) str = "regular";
  else if (S_ISDIR(stat_buf.st_mode)) str = "directory";
  else str = "other";
  printf("%-25s - %s\n", direntp->d_name, str);
 }

 closedir(dirp);
 exit(0);
}
注意,我从中使用MAXPATHLEN并仔细检查以确保没有任何缓冲区溢出。在代码中也应该这样做


编辑:更改代码以使用strn系列函数以增加安全性。

这是因为您没有说明实际的文件。它在另一个目录中。如果需要真实的文件名,请将argv[1]和direntp->d_名称与“/”组合在一起

此外,匈牙利人的名字也很讨厌,甚至连结尾的小调都有点像“p”。如果你有这么多的变量,你需要用它们的名字来记录它们的类型,那你就做错了

以下是您计划的修订版本:

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#include <sys/param.h>

int main(int argc, char *argv[])
{
 DIR *dirp;
 struct dirent *direntp;
 struct stat stat_buf;
 char *str;
 char fullpath[MAXPATHLEN + 1];
 size_t dirnamelen;

 if (argc != 2)
 {
  fprintf( stderr, "Usage: %s dir_name\n", argv[0]);
  exit(1);
 }
 strncpy(fullpath, argv[1], MAXPATHLEN - 1); /* account for trailing '/' */
 fullpath[MAXPATHLEN - 1] = '\0';
 dirnamelen = strlen(fullpath);
 if (strlen(argv[1]) > dirnamelen) {
  fprintf( stderr, "Directory name is too long: %s", argv[1] );
  exit(2);
 }

 fullpath[dirnamelen++] = '/';
 fullpath[dirnamelen] = '\0';

 if ((dirp = opendir( argv[1])) == NULL)
 {
  perror(argv[1]);
  exit(2);
 }

 while ((direntp = readdir( dirp)) != NULL)
 {
  fullpath[dirnamelen] = '\0';
  if ((dirnamelen + strlen(direntp->d_name)) > MAXPATHLEN) {
   fprintf(stderr, "File %s + directory %s is too long.", direntp->d_name, fullpath);
   continue;
  } else {
   /* strncpy is mild overkill because the if statement has verified that
      there's enough space.  */
   strncpy(fullpath + dirnamelen, direntp->d_name, MAXPATHLEN - dirnamelen);
   fullpath[MAXPATHLEN] = '\0';
  }
  if (stat(fullpath, &stat_buf)==-1)
  {
   perror("stat ERROR");
   exit(3);
  }
  if (S_ISREG(stat_buf.st_mode)) str = "regular";
  else if (S_ISDIR(stat_buf.st_mode)) str = "directory";
  else str = "other";
  printf("%-25s - %s\n", direntp->d_name, str);
 }

 closedir(dirp);
 exit(0);
}
注意,我从中使用MAXPATHLEN并仔细检查以确保没有任何缓冲区溢出。在代码中也应该这样做


编辑:更改代码以使用strn系列函数以增加安全性。

如果在unix上使用,则可以使用system命令

system("ls -ltr | grep -d");

如果在unix上使用,则可以使用system命令

system("ls -ltr | grep -d");

其他人建议为stat构建完整路径,或者使用chdir。这两种方法都会起作用,尽管它们是受竞争条件影响的,如果目录在读的时候被重命名。

另一种选择是使用fstatat,它不受竞争条件的约束,因此可以说更为正确。只需将现有的stat调用替换为:

fstatat(dirfd(dirp), direntp->d_name, &stat_buf, 0)

chdir方法也可以不受竞争条件的限制:使用fchdirfddirp代替chdir,或者将目录更改为argv[1],然后打开。使用opendir。路径名构造方法不能成为无竞争条件的。

其他人建议为stat构建完整路径,或者使用chdir。这两种方法都会起作用,尽管它们是受竞争条件影响的,如果目录在读的时候被重命名。

另一种选择是使用fstatat,它不受竞争条件的约束,因此可以说更为正确。只需将现有的stat调用替换为:

fstatat(dirfd(dirp), direntp->d_name, &stat_buf, 0)

chdir方法也可以不受竞争条件的限制:使用fchdirfddirp代替chdir,或者将目录更改为argv[1],然后打开。使用opendir。路径名构造方法不能成为无竞争条件。

为什么不试试这个?只需像下面这样给出argv[1]的路径/home/sabri/Desktop/Test


}你为什么不试试这个?只需像下面这样给出argv[1]的路径/home/sabri/Desktop/Test


}

为什么不使用snprintf而不是strcpy?@Thomas,原因有二。首先,我可以更准确地报告错误,其次我的方法效率更高。我理解你的观点,但我不认为效率上的微小提高比代码可读性更重要。除了手动处理字符串之外,总是会增加引入错误的风险;更多代码行>更多bug……托马斯,我多年来一直是C++程序员,而且还没有习惯使用STRN函数,因为C++不需要这样的东西::STD::string类型。@ Tuomas,笑错了,这就是我是一个可怕的拷贝编辑器的原因。很抱歉。为什么不使用snprintf而不是strcpy呢?@Thomas,原因有二。首先,我可以更准确地报告错误,其次我的方法效率更高。我理解你的观点,但我不认为效率上的微小提高比代码可读性更重要。除了手动处理字符串之外,总是会增加引入错误的风险;更多代码行>更多bug……托马斯,我多年来一直是C++程序员,而且还没有习惯使用STRN函数,因为C++不需要这样的东西::STD::string类型。@ Tuomas,笑错了,这就是我是一个可怕的拷贝编辑器的原因。很抱歉。可能strn系列功能更适合使用。更少的错误检查。当然,这也使得正确报告一个公认罕见的错误情况变得困难。使用chdir似乎要简单得多。使用它是一种坏习惯吗?@nunos,我不喜欢使用它。这是一种全局变量,我避免使用