2008-09-04 19 views
44

Tôi có một tiện ích xuất ra một danh sách các tệp được yêu cầu bởi trò chơi. Làm thế nào tôi có thể chạy tiện ích đó trong một chương trình C và lấy đầu ra của nó để tôi có thể hành động trên nó trong cùng một chương trình?Làm thế nào tôi có thể chạy một chương trình bên ngoài từ C và phân tích đầu ra của nó?

CẬP NHẬT: Cuộc gọi tốt về việc thiếu thông tin. Tiện ích này phun ra một chuỗi các chuỗi và điều này được cho là hoàn toàn di động trên Mac/Windows/Linux. Xin lưu ý, tôi đang tìm một cách có lập trình để thực hiện tiện ích và giữ lại đầu ra của nó (mà đi đến stdout).

+0

cũng thấy http://stackoverflow.com/questions/125828/capturing-stdout-from-a-system-command-optimally – rogerdpack

+0

Nếu bạn muốn stderr cũng như bạn có thể chuyển hướng, ví dụ gọi ls nonexistant-name 2> & 1 – Vic

+5

Đây không phải là một bản sao; câu hỏi được liên kết là ** C++ cụ thể **, trong khi câu hỏi này là khoảng ** C **. –

Trả lời

45

Đối với các sự cố đơn giản trong môi trường Unix-ish, hãy thử popen().

Từ trang người đàn ông:

Các popen() chức năng sẽ mở ra một quá trình bằng cách tạo ra một đường ống, forking và gọi vỏ.

Nếu bạn sử dụng chế độ đọc, đây chính xác là những gì bạn đã yêu cầu. Tôi không biết nếu nó được thực hiện trong Windows.

Đối với các vấn đề phức tạp hơn, bạn muốn tìm kiếm liên lạc giữa các quá trình.

+20

một số ví dụ về cách sử dụng đúng 'popen()' sẽ tốt đẹp. –

+1

Tôi đã thêm một liên kết đến trang người dùng Open Group cho hàm này, bao gồm một ví dụ. Về cơ bản 'popen' geves bạn một con trỏ tập tin rất giống như' fopen'. Nó chỉ cho phép bạn ghi vào đầu vào tiêu chuẩn hoặc đọc từ đầu ra tiêu chuẩn của một chương trình thay vì tương tác với một tệp đĩa. Đó là unix * "mọi thứ là một tập tin" * triết lý tại nơi làm việc. Một số triển khai mở rộng tiêu chuẩn bằng cách cho phép truyền thông hai hướng. – dmckee

+0

[Thi s trả lời] (http://stackoverflow.com/a/53372/119527) chỉ ra rằng 'popen' có sẵn trên Windows. –

7

Vâng, giả sử bạn đang ở trên một dòng lệnh trong môi trường cửa sổ, bạn có thể sử dụng đường ống hoặc chuyển hướng dòng lệnh. Ví dụ,

commandThatOutputs.exe > someFileToStoreResults.txt 

hoặc

commandThatOutputs.exe | yourProgramToProcessInput.exe 

Trong chương trình của bạn, bạn có thể sử dụng các chức năng đầu vào tiêu chuẩn C để đọc các chương trình sản xuất khác (scanf, vv): http://irc.essex.ac.uk/www.iota-six.co.uk/c/c1_standard_input_and_output.asp. Bạn cũng có thể sử dụng ví dụ về tệp và sử dụng fscanf. Điều này cũng sẽ hoạt động trong Unix/Linux.

Đây là một câu hỏi rất chung chung, bạn có thể muốn bao gồm thêm chi tiết, như loại đầu ra (chỉ văn bản hoặc tệp nhị phân?) Và cách bạn muốn xử lý.

Chỉnh sửa: Hooray clarification!

Chuyển hướng STDOUT có vẻ phiền toái, tôi phải làm điều đó trong .NET, và nó đã cho tôi tất cả các loại nhức đầu. Có vẻ như cách C thích hợp là để sinh ra một tiến trình con, nhận được một con trỏ tập tin, và tất cả của một đột ngột đầu tôi đau.

Vì vậy, heres một hack sử dụng tệp tạm thời. Nó đơn giản, nhưng nó sẽ hoạt động. Điều này sẽ làm việc tốt nếu tốc độ không phải là một vấn đề (nhấn đĩa chậm), hoặc nếu nó ném đi. Nếu bạn đang xây dựng một chương trình doanh nghiệp, việc xem xét chuyển hướng STDOUT có lẽ là tốt nhất, sử dụng những gì người khác đề xuất.

#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. 
} 

Đảm bảo kiểm tra quyền đối với tệp của bạn: ngay bây giờ điều này sẽ chỉ đơn giản là ném tệp vào cùng thư mục với tệp exe. Bạn có thể muốn xem xét sử dụng /tmp trong nix hoặc C:\Users\username\Local Settings\Temp trong Vista hoặc C:\Documents and Settings\username\Local Settings\Temp in 2K/XP. Tôi nghĩ rằng /tmp sẽ hoạt động trong OSX, nhưng tôi chưa từng sử dụng nó.

+0

awesome .. :) điều này đã giúp tôi .. –

+0

'c' phải là' int' vì 'fgetc' trả về' int', không phải là 'char'. –

2

Tài liệu MSDN nói Nếu được sử dụng trong chương trình Windows, hàm _popen trả về một con trỏ tệp không hợp lệ khiến chương trình ngừng phản hồi vô thời hạn. _popen hoạt động đúng trong một ứng dụng giao diện điều khiển. Để tạo một ứng dụng Windows chuyển hướng đầu vào và đầu ra, hãy xem Tạo một tiến trình con với đầu vào và đầu ra được chuyển hướng trong Windows SDK.

0
//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; 
} 
+2

Ngôn ngữ là gì? Chắc chắn không phải C ('string.resize'?) – ugoren

+0

trông giống như C++ :( – gideon

1

Bạn có thể sử dụng system() như trong:

system("ls song > song.txt"); 

nơi ls là tên lệnh niêm yết các nội dung của bài hát và thư mục song là một thư mục trong thư mục hiện hành. Tập tin kết quả song.txt sẽ được tạo trong thư mục hiện tại.

+0

nếu tôi muốn chuyển hướng các chương trình khác xuất ra một tệp thì không phải là lệnh os –

29

Như những người khác đã chỉ ra, popen() là cách tiêu chuẩn nhất. Và vì không có câu trả lời cung cấp một ví dụ sử dụng phương pháp này, ở đây nó đi:

#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; 
} 
+0

Không nên' if (pclose (fp)) 'be' nếu (pclose (fp) == -1) '? –

+2

@CoolGuy: phụ thuộc vào những gì bạn muốn' '' '' '' '' '' '' '' '' 'nếu có lỗi xảy ra trạng thái thoát của lệnh, ngược lại nó trả về trạng thái thoát. Như các lệnh truyền thống đặt trạng thái thoát '0' để chỉ ra thành công, bằng cách kiểm tra' if (pclose (fp)) ', chúng ta đang thử nghiệm các lỗi trong' itlose() 'hoặc lệnh. – MestreLion