C++中方便的stream提供了流式IO,如cin、cout、getline等
C中也有同樣功能的函式,透過fprintf、fscanf、fgets、fgetc達成
當流式IO不僅用於檔案或stdio,而可能用於pipe、socket時
POSIX Standard (200809L) 提供了一組方法將一塊記憶體視為檔案來使用
以下是一個簡單的範例
#include <stdio.h>
#include <inttypes.h>
int main()
{
char buf[256] = {};
FILE *buffer = fmemopen(buf, sizeof(buf), "w");
fprintf(buffer, "123");
fprintf(buffer, "456");
fprintf(buffer, "789");
fflush(buffer);
int len = ftell(buffer);
fclose(buffer);
printf("len = %d\n", len);
buffer = fmemopen(buf, len, "r");
// atoll
int64_t n = 0;
int ch = 0;
while( EOF != (ch = fgetc(buffer)) )
{
n = n*10 + ch - '0';
}
printf("%lld\n", n);
fclose(buffer);
return 0;
}
與一般檔案有差別的是,開啟模式使用讀+寫
會產生令人困惑的行為
原因是stream內部會維護一個目前位置,而讀寫共用同一個位置
假設今天先寫入10個字元,位置被移動到11,下次使用一個讀取函式,會從11開始讀取
因此混合讀寫必須使用fseek
ftell
rewind
來重設位置
當傳入的buf為NULL時,fmemopen
內部會取得一塊buffer來操作,在fclose
時關閉
使用者不能存取這塊空間,需要存取則改用open_memstream
另外一點重要差異是,判斷檔案的EOF是根據傳入的__size__,而非內容的null byte
使用fflush也不能手動設定EOF位置,fflush的效用只有加上null byte
下面這段code演示了EOF的行為影響,
int main()
{
FILE* buffer = fmemopen(NULL, 1<<9, "w+");
fprintf(buffer, "GET / ");
fprintf(buffer, "HTTP/1.1\n");
fprintf(buffer, "Host: www.google.com.tw\n");
fprintf(buffer, "Agent: ");
fprintf(buffer, "Curl\n");
fflush(buffer);
rewind(buffer);
char line[64] = {};
while( fgets(line, 64, buffer) )
printf("Get: %s\n", line);
fclose(buffer);
return 0;
}
以下是輸出
Get: GET / HTTP/1.1
Get: Host: www.google.com.tw
Get: Agent: Curl
Get:
Get:
Get:
Get:
Get:
Get:
Get:
Get:
直觀的看法可能會認為只讀到前3行資料
但實際上還多印了8行,內容都是64個\0
(w+將其truncated)
欲限制這種行為只能在open時的len長度指定為寫入的資料長度