1 二進制IO(Binary IO)
在前一篇我們了解了逐字符讀寫和逐行讀寫函數(shù)。
如果我們在讀寫二進制文件,希望以此讀寫整個文件內(nèi)容,這兩個函數(shù)雖然可以實現(xiàn),但是明顯會很麻煩且多次循環(huán)明顯效率很低。
為了應(yīng)對這種場景,標(biāo)準(zhǔn)IO庫提供了fread和fwrite函數(shù)。
函數(shù)聲明:
#include <stdio.h>
size_t fread(void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp);
size_t fwrite(const void *restrict ptr, size_t size size_t nobj, FILE *restrict fp);
函數(shù)用法;
a) 讀寫一個數(shù)組。
float data[10];
if (write(&data[2], sizeof(float), 4, fp) != 4)
? ? err_sys(“fwrite error");
本例中,從流fp中讀取4個float型數(shù)據(jù)填入到數(shù)組下表從2到5得位置中。
b) 讀寫一個結(jié)構(gòu)體
struct {
? ? short ?count;
? ? long ? total;
? ? char ? name[NAMESIZE];
} item;
if (fwrite(&item, sizeof(item), 1, fp) != 1)
? ? err_sys(“fwrite error");
本例中,從fp讀取數(shù)據(jù)填入到一個結(jié)構(gòu)體中。
?
上面兩例都可以認(rèn)為是讀寫一個結(jié)構(gòu)體的數(shù)組,參數(shù)size是結(jié)構(gòu)體的長度,參數(shù)nobj是數(shù)組中要讀寫的元素的個數(shù)。
?
函數(shù)返回值:
兩個函數(shù)的返回值都是讀寫的元素個數(shù)。
對于讀函數(shù),返回值可能會比nobj小,如果有異常拋出或者讀到了文件結(jié)尾。這時需要調(diào)用函數(shù)ferror或feof來判斷。
對于寫函數(shù),返回值比nobj小,則一定是有異常拋出。
?
函數(shù)細節(jié):
在上面的例子中,我們通過fwrite函數(shù)填充了一個結(jié)構(gòu)體,那么如果讀寫不在一個系統(tǒng)中,那么結(jié)構(gòu)體的內(nèi)存布局可能并不相同,這對于現(xiàn)在的多系統(tǒng)互聯(lián)工作的場景下很常見。我們會在討論socket時回來繼續(xù)看這個問題,實際的解決方案就是在不同系統(tǒng)間讀寫二進制數(shù)據(jù)時使用相同的協(xié)議。
?
2 定位流(Positioning a Stream)我們有三種方法對流進行定位:
?
ftell和fseek函數(shù)聲明:
#include <stdio.h>
long ftell(FILE* fp); ? ?// Returns:current file position indicator if OK, -1L on error
int fseek(FILE* fp, long offset, int whence); ? ? ? // Returns:0 if OK , -1 on error
void rewind(FILE* fp);
函數(shù)細節(jié):
?
ftello和fseeko函數(shù)聲明:
#include <stdio.h>
off_t ftello(FILE* fp); ? ? // Returns: current file position indicator if OK, (off_t) -1 on error
int fseeko(FILE* fp, off_t offset, int whence); ? ? /// Returns: 0 if OK, -1 on error
函數(shù)細節(jié):
?
fgetpos和fsetpos函數(shù)聲明:
#include <stdio.h>
int fgetpos(FILE* restrict fp, fpos_t *restrict pos);
int fsetpos(FILE* fp, const fpos_t pos);
函數(shù)細節(jié):
?
3 格式化輸入輸出格式化輸出函數(shù)有五個PRintf函數(shù)負責(zé)格式化輸出。
函數(shù)聲明:
#include <stdio.h>
int printf(const char *restrict format, ...);
int fprintf(FILE *restrict fp, const char *restrict format, ...);
int dprintf(int fd, const char *restrict format, ..);
? ? ? // All three return : number of characters output if OK , negative value if output error
int sprintf(char *resrict buf, const char *restrict format, ...);
? ? ? // Returns: number of characters stored in array if OK, negative value if encoding error
int snprintf(char *restrict buf, size_t n, const char *restrict format, ...);
? ? ? // Returns: number of characters,that would have been stored in array if buffer was large enough, negative value if encoding error
函數(shù)細節(jié):
?
格式化輸入函數(shù)函數(shù)聲明:
#include <stdio.h>
int scanf(const char *restrict format, ...);
int fscanf(FILE *restrict fp, const char *restrict format, ...);
int sscanf(const char *restrict buf, const char *restrict format, ...);
函數(shù)細節(jié):
更多關(guān)于格式化輸入輸出的細節(jié)可以自己查詢Unix操作系統(tǒng)手冊。
?
4 從流中獲取文件描述符函數(shù)聲明:
#include <stdio.h>
int fileno(FILE* fp); ? ? ? // Returns: the file descriptor associated with the stream
如果我們需要調(diào)用dup和fcntl,則需要調(diào)用該函數(shù)。
?
5 臨時文件(Temporary Files)標(biāo)準(zhǔn)IO庫提供了兩個函數(shù)用于創(chuàng)建臨時文件。
函數(shù)聲明:
#include <stdio.h>
char* tempnam(char *ptr);
FILE* tmpfile(void);
函數(shù)細節(jié):
Example:
Code:
#include?"apue.h"
?
int
main(void)
{
? ??char? ? name[L_tmpnam], line[MAXLINE];
? ??FILE? ? *fp;
?
? ? printf("%s/n", tmpnam(NULL)); ? ? ??/* first temp name */
?
? ? tmpnam(name); ? ? ? ? ? ? ? ? ? ? ??/* second temp name */
? ? printf("%s/n", name);
?
? ??if?((fp = tmpfile()) ==?NULL) ? ? ??/* create temp file */
? ? ? ? err_sys("tmpfile error");
? ? fputs("one line of output/n", fp);??/* write to temp file */
? ? rewind(fp); ? ? ? ? ? ? ? ? ? ? ? ??/* then read it back */
? ??if?(fgets(line,?sizeof(line), fp) ==?NULL)
? ? ? ? err_sys("fgets error");
? ? fputs(line,?stdout);? ? ? ? ? ? ? ??/* print the line we wrote */
?
? ? exit(0);
}
?
在系統(tǒng)The Single UNIX Specification定義了另外兩個函數(shù)處理臨時文件:
函數(shù)聲明:
char* mkdtemp(char* template); ? ?// Returns: pointer to directory name if OK, NULL on error
int mkstemp(char* template); ? ?// Returns: file descriptor if OK, -1 on error
函數(shù)細節(jié):
?
6 內(nèi)存流(Memory Streams)有的標(biāo)準(zhǔn)輸入輸出流并沒有對應(yīng)打開的硬盤文件,所有操作都是與內(nèi)存中buffer進行數(shù)據(jù)交換,這些流被叫做內(nèi)存流(memory streams)。
函數(shù)聲明:
#include <stdio.h>
FILE* fmemopen(void *restrict buf, size_t size, const char *restrict type);
// Returns: stream pointer if OK, NULL on error
函數(shù)細節(jié):
?
7 總結(jié)標(biāo)準(zhǔn)IO函數(shù)庫被大多數(shù)UNIX應(yīng)用使用。
在使用的時候,注意哪里使用了buffer來處理,因為這是容易引起迷惑的地方。
?
?
參考資料:
《Advanced Programming in the UNIX Envinronment 3rd》
?
|
新聞熱點
疑難解答