我正在用 C++ 编写一个程序,它对 Linux 操作系统上当前目录中的所有文件进行一些特殊处理。
所以我正在考虑使用诸如
system("ls")
之类的系统调用来获取所有文件的列表。
但是如何将它存储在我的程序中? (如何将 ls 的输出重定向到我在程序中声明的字符串)
谢谢
共识似乎是不使用“ls”。 但是,对于任何对某个功能感兴趣的人来说:
/**
* Execute a command and get the result.
*
* @param cmd - The system command to run.
* @return The string command line output of the command.
*/
string GetStdoutFromCommand(string cmd) {
string data;
FILE * stream;
const int max_buffer = 256;
char buffer[max_buffer];
cmd.append(" 2>&1"); // Do we want STDERR?
stream = popen(cmd.c_str(), "r");
if (stream) {
while (!feof(stream))
if (fgets(buffer, max_buffer, stream) != NULL) data.append(buffer);
pclose(stream);
}
return data;
}
我认为你不能使用系统来读取输出。
尝试使用
popen
。
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
但是,您可能不想这样做
ls
。 两个原因:
readdir
),而不是使用shell命令并解析它。ls
输出是一个坏主意。我建议你不要喊
ls
- 正确完成工作,使用opendir/readdir/closedir
直接读取目录。
代码示例,打印目录条目:
// $ gcc *.c && ./a.out
#include <stdlib.h> // NULL
#include <stdio.h>
#include <dirent.h>
int main(int argc, char* argv[]) {
const char* path = argc <= 1 ? "." : argv[1];
DIR* d = opendir(path);
if (d == NULL) return EXIT_FAILURE;
for(struct dirent *de = NULL; (de = readdir(d)) != NULL; )
printf("%s/%s\n", path, de->d_name);
closedir(d);
return 0;
}
执行此操作的一个简单方法是使用 boost filesystem 目录迭代器。 或者像其他人建议的那样使用 opendir/readdir/closedir 。 你的前进方向没有真正的好处。
代码示例,指定目录中常规文件的打印大小:
// $ g++ listdir.cc -o listdir -lboost_filesystem && ./listdir
#include <iostream>
#include <boost/filesystem.hpp>
int main(int argc, char* argv[]) {
using std::cout;
using namespace boost::filesystem;
std::string path(argc <= 1 ? "." : argv[1]);
if (is_directory(path)) {
for (directory_iterator itr(path); itr!=directory_iterator(); ++itr) {
cout << itr->path().filename() << ' '; // display filename only
if (is_regular_file(itr->status())) // display size for regular files
cout << " [" << file_size(itr->path()) << ']';
cout << '\n';
}
}
else cout << (exists(path) ? "Found: " : "Not found: ") << path << '\n';
}
您使用的是 UNIX 还是 Windows? 在 UNIX 上,您可以使用 fork() 调用创建一个子进程,然后创建一些管道并将子进程的 STDOUT 分配给父进程的 STDIN。 在 Windows 上,Win32 API 中肯定会有类似的东西。
选项 4. 使用 popen();
使用适当的 c 调用来读取目录中的文件,或者概括您的程序,以便它采用文件列表作为输入,并从 ls 将该列表通过管道传输到您的程序
> ls | yoursoftware
我看到 3 个选项:
system("ls > tempfile")
,然后从临时文件中读取ls
的输出pipe()
打开管道,然后使用 fork()
生成新进程。在子进程中关闭文件描述符 2 并通过调用 dup()
来替换它的写入管道末端。接下来,在子进程中调用exec("ls",...)
。最后从父进程的管道中读取ls
的输出ls
来枚举当前目录中的文件。您的程序中有一些函数可以正确执行此操作,即 opendir(),readdir(),closedir
。我强烈推荐选项3。
我认为 pajton 的#2 是这个问题最合适的答案。
“ls”可能不是您想要使用它的命令的最佳示例,因为还有其他本机 C 库函数可用于执行此操作,但还有其他程序可以生成您可能想要处理的输出立即无需执行写入/读取文件。
#1 在 UNIX/Linux 类型系统上也很好,它实现了一个高效的 RAM 文件系统,可用于读取/写入系统全局数据。 在几乎所有系统上,这都是一种非常好的“快速而肮脏”的完成工作的方法。
同样,大多数响应都提供了使用本机 C 库获取目录内容的更好方法,但在某些情况下,诸如 pipeline()、fork()、dup()、exec()、system() 和popen() 适合与系统进程通信。
使用fork()/exec()和pipe()系统调用似乎是Unix上最好的通用方法。这允许最简单地分离被调用程序的标准输出和标准错误流。人们还可以等待生成的进程并获取它,收集其退出状态。最后,如果需要的话,可以使用非阻塞 I/O 来读取被调用程序的输出/错误。
最大的问题是,要在 Windows 上实现类似的功能,您可能需要编写数百行代码。我没有找到更好的方法,也没有研究过 Windows 环境下的问题。
如果您不想创建太多代码,另一种方法是在 shell 命令中使用 > 将其转储到文件中。例如。 LS>