国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 系統(tǒng) > Unix > 正文

UNIX高級(jí)環(huán)境編程(7)標(biāo)準(zhǔn)IO函數(shù)庫(kù)

2024-06-28 13:21:44
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
UNIX高級(jí)環(huán)境編程(7)標(biāo)準(zhǔn)IO函數(shù)庫(kù) - 二進(jìn)制文件IO,流定位,創(chuàng)建臨時(shí)文件和內(nèi)存流

1 二進(jìn)制IO(Binary IO)

在前一篇我們了解了逐字符讀寫和逐行讀寫函數(shù)。

如果我們?cè)谧x寫二進(jìn)制文件,希望以此讀寫整個(gè)文件內(nèi)容,這兩個(gè)函數(shù)雖然可以實(shí)現(xiàn),但是明顯會(huì)很麻煩且多次循環(huán)明顯效率很低。

為了應(yīng)對(duì)這種場(chǎng)景,標(biāo)準(zhǔn)IO庫(kù)提供了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) 讀寫一個(gè)數(shù)組。

float data[10];

if (write(&data[2], sizeof(float), 4, fp) != 4)

? ? err_sys(“fwrite error");

本例中,從流fp中讀取4個(gè)float型數(shù)據(jù)填入到數(shù)組下表從2到5得位置中。

b) 讀寫一個(gè)結(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ù)填入到一個(gè)結(jié)構(gòu)體中。

?

上面兩例都可以認(rèn)為是讀寫一個(gè)結(jié)構(gòu)體的數(shù)組,參數(shù)size是結(jié)構(gòu)體的長(zhǎng)度,參數(shù)nobj是數(shù)組中要讀寫的元素的個(gè)數(shù)。

?

函數(shù)返回值:

兩個(gè)函數(shù)的返回值都是讀寫的元素個(gè)數(shù)。

對(duì)于讀函數(shù),返回值可能會(huì)比nobj小,如果有異常拋出或者讀到了文件結(jié)尾。這時(shí)需要調(diào)用函數(shù)ferror或feof來(lái)判斷。

對(duì)于寫函數(shù),返回值比nobj小,則一定是有異常拋出。

?

函數(shù)細(xì)節(jié):

在上面的例子中,我們通過(guò)fwrite函數(shù)填充了一個(gè)結(jié)構(gòu)體,那么如果讀寫不在一個(gè)系統(tǒng)中,那么結(jié)構(gòu)體的內(nèi)存布局可能并不相同,這對(duì)于現(xiàn)在的多系統(tǒng)互聯(lián)工作的場(chǎng)景下很常見(jiàn)。我們會(huì)在討論socket時(shí)回來(lái)繼續(xù)看這個(gè)問(wèn)題,實(shí)際的解決方案就是在不同系統(tǒng)間讀寫二進(jìn)制數(shù)據(jù)時(shí)使用相同的協(xié)議。

?

2 定位流(Positioning a Stream)

我們有三種方法對(duì)流進(jìn)行定位:

  • 函數(shù)ftell和fseek。將文件的當(dāng)前偏移位置存儲(chǔ)在long integer型變量中;
  • 函數(shù)ftello和fseeko。將文件的當(dāng)前偏移量存儲(chǔ)在off_t型變量中;
  • 函數(shù)fgetpos和fsetpos。使用數(shù)據(jù)類型fpos_t記錄文件的當(dāng)前偏移量。

?

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ù)細(xì)節(jié):

  • 二進(jìn)制文件的偏移量是從文件開(kāi)始到當(dāng)前位置的字節(jié)數(shù);
  • ftell函數(shù)返回當(dāng)前文件的偏移位置;
  • fseek函數(shù)用來(lái)定位文件到指定偏移位置;
  • fseek函數(shù)的參數(shù)whence,用來(lái)設(shè)置計(jì)算偏移量的方法:SEEK_SET表示從文件開(kāi)頭開(kāi)始計(jì)算,SEEK_CUR表示從文件當(dāng)前偏移位置開(kāi)始計(jì)算,SEEK_END表示從文件結(jié)尾開(kāi)始計(jì)算。
  • 對(duì)于一些非Unix操作系統(tǒng),存儲(chǔ)文本文件的存儲(chǔ)格式會(huì)有所不同,當(dāng)前文件偏移量無(wú)法通過(guò)字節(jié)數(shù)來(lái)表示,這種情況下,參數(shù)whence需要設(shè)置為SEEK_SET,并且offset只有兩個(gè)值可以使用:0,表示倒回文本開(kāi)頭;另一個(gè)可用值為函數(shù)ftell的返回值。

?

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ù)細(xì)節(jié):

  • 這兩個(gè)函數(shù)和上面的ftell和fseek功能相同,只是返回值類型不是long,而改成了off_t,實(shí)現(xiàn)上可以讓off_t的表示范圍更大。

?

fgetpos和fsetpos函數(shù)聲明:

#include <stdio.h>

int fgetpos(FILE* restrict fp, fpos_t *restrict pos);

int fsetpos(FILE* fp, const fpos_t pos);

函數(shù)細(xì)節(jié):

  • fgetpos函數(shù)保存當(dāng)前文件偏移量到參數(shù)pos中
  • fgetpos得到的pos可以用來(lái)使用fsetpos設(shè)置當(dāng)前文件偏移量到之前的位置。

?

3 格式化輸入輸出格式化輸出函數(shù)

有五個(gè)PRintf函數(shù)負(fù)責(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ù)細(xì)節(jié):

  • printf輸出到標(biāo)準(zhǔn)輸出;
  • fprintf輸出到指定的流中;
  • dprintf輸出到指定的文件描述符中;
  • sprintf將格式化字符串寫入到指定的buffer數(shù)組中,自動(dòng)在結(jié)尾處加上一個(gè)null結(jié)尾符,但是不計(jì)入返回值中,并且,sprintf在buffer不夠大時(shí)可能發(fā)生越界,因此需要使用者保證buffer足夠大;
  • snprintf防止越界,在springf的參數(shù)中增加了buffer的大小參數(shù),所有越界寫入的字符都被忽略,如果返回值比buffer得長(zhǎng)度要小,則說(shuō)明輸出沒(méi)有被截?cái)唷?/li>

?

格式化輸入函數(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ù)細(xì)節(jié):

  • format參數(shù)后面接得參數(shù),包含存放讀入字符串的變量地址。

更多關(guān)于格式化輸入輸出的細(xì)節(jié)可以自己查詢Unix操作系統(tǒng)手冊(cè)。

?

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 臨時(shí)文件(Temporary Files)

標(biāo)準(zhǔn)IO庫(kù)提供了兩個(gè)函數(shù)用于創(chuàng)建臨時(shí)文件。

函數(shù)聲明:

#include <stdio.h>

char* tempnam(char *ptr);

FILE* tmpfile(void);

函數(shù)細(xì)節(jié):

  • 函數(shù)tmpnam生成一個(gè)字符串,該字符串為一個(gè)合法的路徑名,并且不和任何已存在的文件重復(fù)。
  • 函數(shù)tmpnam每次調(diào)用都生成不同的字符串,知道TMP_MAX次數(shù)。
  • 如果函數(shù)tempnam的參數(shù)ptr為NULL,則生成的路徑字符串存在內(nèi)存靜態(tài)區(qū),函數(shù)返回值為指向該路徑字符串的指針。如果隨后再次使用null參數(shù)調(diào)用tempnam,會(huì)覆蓋之前生成的字符串。
  • 如果函數(shù)tempnam的參數(shù)ptr不是NULL,那么生成的路徑字符串存在ptr指向的數(shù)組內(nèi),所以需要保證ptr指向的數(shù)組的長(zhǎng)度至少為L(zhǎng)_tmpnam。
  • 函數(shù)tmpfile函數(shù)創(chuàng)建一個(gè)臨時(shí)二進(jìn)制文件(type wb+),程序終止或者該文件被關(guān)閉,則該文件自動(dòng)被刪除。對(duì)于UNIX操作系統(tǒng)而言,生成一個(gè)二進(jìn)制文件并沒(méi)有什么影響,因?yàn)閮?nèi)核并不區(qū)分文本文件還是二進(jìn)制文件。

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定義了另外兩個(gè)函數(shù)處理臨時(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ù)細(xì)節(jié):

  • mkdtemp函數(shù)創(chuàng)建一個(gè)名字唯一的文件夾
  • mkstemp函數(shù)創(chuàng)建一個(gè)名字唯一的常規(guī)文件(regular file)
  • 命名規(guī)則為 template + 六位隨機(jī)字符

?

6 內(nèi)存流(Memory Streams)

有的標(biāo)準(zhǔn)輸入輸出流并沒(méi)有對(duì)應(yīng)打開(kāi)的硬盤文件,所有操作都是與內(nèi)存中buffer進(jìn)行數(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ù)細(xì)節(jié):

  • 參數(shù)buf指定使用的buffer,size為該buffer的大小,如果只指定size,而buf為null,那么fmemopen根據(jù)size的大小分配內(nèi)存,由fmemopen分配的內(nèi)存在流關(guān)閉時(shí)自動(dòng)被釋放;
  • 參數(shù)type控制該流的功能.

?

7 總結(jié)

標(biāo)準(zhǔn)IO函數(shù)庫(kù)被大多數(shù)UNIX應(yīng)用使用。

在使用的時(shí)候,注意哪里使用了buffer來(lái)處理,因?yàn)檫@是容易引起迷惑的地方。

?

?

參考資料:

《Advanced Programming in the UNIX Envinronment 3rd》

?


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 丹江口市| 台东市| 炎陵县| 普兰县| 库尔勒市| 景洪市| 沭阳县| 丰镇市| 廊坊市| 陆良县| 河间市| 卢氏县| 广西| 乐亭县| 凤台县| 福贡县| 定南县| 社会| 申扎县| 繁昌县| 武城县| 涡阳县| 肇州县| 化州市| 贡嘎县| 江陵县| 新乐市| 隆尧县| 青州市| 江永县| 聂拉木县| 淮滨县| 高雄市| 湖南省| 周口市| 上蔡县| 新沂市| 百色市| 兴海县| 安仁县| 新邵县|