У меня есть утилита, которая выводит список файлов, необходимых для игры. Как я могу запустить эту утилиту в программе на C и получить ее вывод, чтобы я мог действовать с ней в той же программе?
ОБНОВЛЕНИЕ: Хороший звонок из-за отсутствия информации. Утилита выводит серию строк, и предполагается, что она будет переносимой на Mac / Windows / Linux. Обратите внимание, я ищу программный способ запустить утилиту и сохранить ее вывод (который поступает на стандартный вывод).
Если вам нужен stderr, вы также можете перенаправить, например, call is nonexistent-name 2> & 1
Это не дубликат; связанный вопрос - Специфичный для C++, а этот вопрос - о C.
Я голосую за то, чтобы снова открыть этот вопрос, поскольку это не дубликат, он касается C, а не C++
см. также stackoverflow.com/questions/9405985/…





Для простых проблем в Unix-подобных средах попробуйте popen().
На странице руководства:
The popen() function opens a process by creating a pipe, forking and invoking the shell.
Если вы используете режим чтения, это именно то, о чем вы просили. Не знаю, реализовано ли это в Windows.
Для более сложных проблем вы хотите найти межпроцессное взаимодействие.
Было бы неплохо привести несколько примеров того, как правильно использовать popen().
Я добавил ссылку на страницу руководства Open Group для функции, которая включает пример. По сути, popen дает вам указатель на файл, очень похожий на fopen. Просто он позволяет вам писать в стандартный ввод или читать из стандартного вывода программы вместо взаимодействия с файлом на диске. Это философия UNIX "все - файл" в действии. Некоторые реализации расширяют стандарт, разрешая двунаправленную связь.
Для решения, использующего дескрипторы необработанных файлов (например, если вам нужен асинхронный ввод-вывод), см. stackoverflow.com/questions/9405985/…
Что ж, если вы находитесь в командной строке в среде Windows, вы можете использовать каналы или перенаправления командной строки. Например,
commandThatOutputs.exe > someFileToStoreResults.txt
или же
commandThatOutputs.exe | yourProgramToProcessInput.exe
В вашей программе вы можете использовать стандартные функции ввода C для чтения вывода других программ (scanf и т. д.): http://irc.essex.ac.uk/www.iota-six.co.uk/c/c1_standard_input_and_output.asp. Вы также можете использовать пример файла и использовать fscanf. Это также должно работать в Unix / Linux.
Это очень общий вопрос, вы можете включить более подробную информацию, например, какой это тип вывода (просто текст или двоичный файл?) И как вы хотите его обработать.
Обновлено: Ура разъяснения!
Перенаправление STDOUT выглядит хлопотным, мне приходилось делать это в .NET, и это доставляло мне множество головных болей. Похоже, что правильный способ C - создать дочерний процесс, получить указатель на файл, и внезапно у меня заболела голова.
Итак, вот хак, который использует временные файлы. Это просто, но должно работать. Это будет хорошо работать, если скорость не является проблемой (удар по диску происходит медленно) или если он выброшен. Если вы создаете корпоративную программу, возможно, лучше всего будет изучить перенаправление STDOUT, используя то, что рекомендуют другие люди.
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
FILE * fptr; // file holder
char c; // char buffer
system("dir >> temp.txt"); // call dir and put it's contents in a temp using redirects.
fptr = fopen("temp.txt", "r"); // open said file for reading.
// oh, and check for fptr being NULL.
while(1){
c = fgetc(fptr);
if (c!= EOF)
printf("%c", c); // do what you need to.
else
break; // exit when you hit the end of the file.
}
fclose(fptr); // don't call this is fptr is NULL.
remove("temp.txt"); // clean up
getchar(); // stop so I can see if it worked.
}
Обязательно проверьте права доступа к файлу: прямо сейчас это просто поместит файл в тот же каталог, что и exe. Возможно, вы захотите изучить использование /tmp в nix, C:\Users\username\Local Settings\Temp в Vista или C:\Documents and Settings\username\Local Settings\Temp in 2K/XP. Я думаю, что /tmp будет работать в OSX, но я никогда его не использовал.
c должен быть int, потому что fgetc возвращает int, а не char.
В Linux и OS X popen() действительно ваш лучший выбор, как указал dmckee, поскольку обе ОС поддерживают этот вызов. В Windows это должно помочь: http://msdn.microsoft.com/en-us/library/ms682499.aspx
popen поддерживается в Windows, см. здесь:
http://msdn.microsoft.com/en-us/library/96ayss4b.aspx
Если вы хотите, чтобы он был кроссплатформенным, используйте popen.
В документации MSDN говорится При использовании в программе Windows функция _popen возвращает неверный указатель файла, из-за которого программа перестает отвечать на неопределенное время. _popen правильно работает в консольном приложении. Чтобы создать приложение Windows, которое перенаправляет ввод и вывод, см. Создание дочернего процесса с перенаправленным вводом и выводом в Windows SDK.
//execute external process and read exactly binary or text output
//can read image from Zip file for example
string run(const char* cmd){
FILE* pipe = popen(cmd, "r");
if (!pipe) return "ERROR";
char buffer[262144];
string data;
string result;
int dist=0;
int size;
//TIME_START
while(!feof(pipe)) {
size=(int)fread(buffer,1,262144, pipe); //cout<<buffer<<" size = "<<size<<endl;
data.resize(data.size()+size);
memcpy(&data[dist],buffer,size);
dist+=size;
}
//TIME_PRINT_
pclose(pipe);
return data;
}
На каком это языке? Конечно, не C (string.resize?)
похоже на C++ :(
Вы можете использовать system() как в:
system("ls song > song.txt");
где ls - это имя команды для вывода содержимого папки song, а song - это папка в текущем каталоге. Полученный файл song.txt будет создан в текущем каталоге.
что, если я хочу перенаправить вывод других программ в файл? не команда ОС
Нет, это очень плохой способ. Делайте это правильно, используя каналы, не оставляя временные файлы по всей файловой системе.
Как отмечали другие, popen() - самый стандартный способ. И поскольку в ответе нет примера использования этого метода, вот оно:
#include <stdio.h>
#define BUFSIZE 128
int parse_output(void) {
char *cmd = "ls -l";
char buf[BUFSIZE];
FILE *fp;
if ((fp = popen(cmd, "r")) == NULL) {
printf("Error opening pipe!\n");
return -1;
}
while (fgets(buf, BUFSIZE, fp) != NULL) {
// Do whatever you want here...
printf("OUTPUT: %s", buf);
}
if (pclose(fp)) {
printf("Command not found or exited with error status\n");
return -1;
}
return 0;
}
Пример вывода:
OUTPUT: total 16
OUTPUT: -rwxr-xr-x 1 14077 14077 8832 Oct 19 04:32 a.out
OUTPUT: -rw-r--r-- 1 14077 14077 1549 Oct 19 04:32 main.c
Разве if (pclose(fp)) не должен быть if (pclose(fp) == -1)?
@CoolGuy: зависит от того, что вы хотите. pclose() возвращает -1, если произошла ошибка при получении статуса выхода команды, в противном случае он возвращает сам статус выхода. Поскольку команды традиционно устанавливают статус выхода 0 для индикации успеха, проверяя if (pclose(fp)), мы проверяем наличие ошибок либо в pclose(), либо в команде.
Большое спасибо за этот пример, он передает вывод другой программы на вывод текущей программы. Спасибо!
см. также stackoverflow.com/questions/125828/…