2011-10-09 87 views
1

我想在C中使用wget,我正在使用popen來做到這一點。ftell函數在C中給出-1作爲標準輸出

FILE *stdoutPtr = popen(command,"r"); 
fseek(stdoutPtr, 0L, SEEK_END); 
long pos = ftell(stdoutPtr); 

這裏我想獲得stdout的大小,以便我可以初始化緩衝區。但pos變量總是-1。 pos應該告訴我讀指針的當前位置。

請幫助....

+0

ftell是用於確定流中當前位置的I/O函數。 -1表示錯誤。你可以使用perror和全局errno來讀取確切的錯誤。 – 2011-10-09 17:51:59

+0

請嘗試使用libcurl。 –

回答

6

FILE返回的popen不是一個普通的文件,而是一個叫做pipe的東西。 (這就是p代表的意思。)數據流從您調用的命令的標準輸出到您的程序的管道。因爲它是通信通道而不是磁盤上的文件,所以管道沒有確定的大小,並且您無法在數據流中尋找不同的位置。因此,fseek and ftell在應用於此FILE時都會失敗,這就是-1返回值的含義。如果您在撥打ftell後立即檢查errno,您會發現它的值爲ESPIPE,這意味着「您無法對管道執行此操作」。

如果您嘗試將命令的所有輸出讀取到單個char*緩衝區中,唯一的方法是重複調用其中一個讀取功能,直到它指示文件結束並放大必要時使用緩衝區,使用realloc。如果輸出可能很大,如果有任何方法可以更改程序以更好地處理數據,那將會更好。

+0

「fseek和ftell在應用到這個FILE時都會失敗,這就是-1返回值意味着」 - 對此的任何權威性引用(如C或其他標準)? – pfalcon

+1

@pfalcon ** http://pubs.opengroup.org/onlinepubs/9699919799/functions/fseek.html中**錯誤**的內容是什麼? (請注意它在「[ESPIPE]」上所說的內容。) – zwol

+0

正是,感謝您的快速回復! – pfalcon

1

不能使用管道的方式。首先,信息在你得到它的瞬間就會過時,因爲到那時可以將更多的數據寫入管道。你必須使用不同的分配策略。

最常見的策略是分配一個固定大小的緩衝區,並保持讀取,直到到達文件結尾。如果你喜歡,你可以在閱讀時處理數據。

如果您需要在一個塊中處理所有數據,您可以分配一個大緩衝區並開始讀入。如果它已滿,則使用realloc放大緩衝區並繼續前進,直到完成所有操作。

一個常見的模式是保持緩衝區指針,緩衝區計數和分配大小。最初,將分配大小設置爲64K。將計數設置爲零。分配一個64K緩衝區。最多可將size-count字節讀入緩衝區。如果您擊中EOF,請停止。如果緩衝區已滿,請將緩衝區的分配大小提高50%和realloc