日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內(nèi)最全I(xiàn)T社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > php開源 > php教程 > 《Linux系統(tǒng)編程》筆記 第三章(二)

《Linux系統(tǒng)編程》筆記 第三章(二)

來源:程序員人生   發(fā)布時間:2016-08-06 09:13:49 閱讀次數(shù):2524次

3.6 定位流

標(biāo)準(zhǔn)庫提供了與系統(tǒng)調(diào)用lseek()類似的函數(shù)來定位流中的讀寫位置。

#include <stdio.h> int fseek (FILE *stream, long offset, int whence); long ftell(FILE *stream);

與lseek()用法類似,whence提供了以下選擇:
SEEK_CUR-將流的讀寫位置設(shè)置為當(dāng)前位置加上pos個字節(jié),pos可以是正數(shù)或負(fù)數(shù)。
SEEK_END-將流的讀寫位置設(shè)置為文件尾加上pos個字節(jié),pos可以是正數(shù)或負(fù)數(shù)。
SEEK_SET-將流的讀寫位置設(shè)置為pos對應(yīng)的位置,pos為0時期表設(shè)置為文件起始位置。
函數(shù)調(diào)用成功后返回0并取消之前的ungetc()操作,毛病時返回⑴。

上述的函數(shù)中偏移量類型是long,若處理的文件大小超過long變量的范圍時,可使用

#include <stdio.h> int fseeko(FILE *stream, off_t offset, int whence); off_t ftello(FILE *stream);

off_t在64位系統(tǒng)上被實現(xiàn)為64位大小,在32位系統(tǒng)上與long大小相同。

類似功能的函數(shù)有

#include <stdio.h> int fsetpos (FILE *stream, fpos_t *pos); int fgetpos(FILE *stream, fpos_t *pos);

除非為了源碼兼容性,1般不使用這個函數(shù)。

#include <stdio.h> void rewind (FILE *stream);

該調(diào)用將stream的讀寫位置設(shè)置為流初始,與fseek (stream, 0, SEEK_SET);功能1致。由于該函數(shù)沒有返回值,因此需要驗證是不是正確的話調(diào)用之前應(yīng)當(dāng)將errno置0,調(diào)用知乎檢查errno是不是為0。

格式化I/O

格式化I/O是指將內(nèi)容依照規(guī)定的格式整理后讀取或輸出。
格式化輸出主要通過printf()系列函數(shù):

#include <stdio.h> int printf(const char *format, ...);//格式化到標(biāo)準(zhǔn)輸出 int fprintf(FILE *stream, const char *format, ...);//格式化到流 int sprintf(char *str, const char *format, ...);//格式化到str中 int snprintf(char *str, size_t size, const char *format, ...);//與sprintf類似,更安全,其提供了可寫緩沖區(qū)的長度 int dprintf(int fd, const char *format, ...);//格式化到文件描寫符fd對應(yīng)的文件中

上述函數(shù)的返回值均是真正格式化的長度,不包括字符串結(jié)束符\0
我們1般見到的printf()調(diào)用是printf("%d", i);的情勢,其實printf()系列函數(shù)的完全格式是:

% [flags] [fldwidth] [precision] [lenmodifier] convtype

%-是格式化字符串的起始,必須要有
flags-是控制格式化樣式的標(biāo)志,有以下取值:

標(biāo)志 說明
將整數(shù)按千分位組字符
- 在字段內(nèi)左對齊輸出
+ 總是顯示帶符號轉(zhuǎn)換的正負(fù)號
(空格) 如果第1個字符不是正負(fù)號,則在其前面加上1個空格
# 指定另外一種轉(zhuǎn)換情勢(例如,對106進(jìn)制格式,加0x前綴)
0 添加前導(dǎo)0(默許是空格)進(jìn)行填充

fldwidth-控制被格式化內(nèi)容的寬度,若寬度不夠則用空格或0補(bǔ)齊。可以指定非負(fù)數(shù)也能夠指定*來默許處理
precision-數(shù)字的位數(shù)或字符串的字節(jié)數(shù),以.開頭,后面跟非負(fù)數(shù)或*
lenmodifier-用來修飾被格式化變量的長度:

取值 說明
hh 將相應(yīng)的參數(shù)按signed或unsigned char類型輸出
h 將相應(yīng)的參數(shù)按signed或unsigned short類型輸出
l 將相應(yīng)的參數(shù)按signed或unsigned long或?qū)捵址愋洼敵?/td>
ll 將相應(yīng)的參數(shù)按signed或unsigned long long類型輸出
j intmax_t或uintmax_t
z size_t
t ptrdiff_t
L long double

convtype-被格式化的變量類型:

取值 說明
d、i 有符號10進(jìn)制
o 無符號8進(jìn)制
u 無符號10進(jìn)制
x,X 無符號106進(jìn)制
f, F 雙精度浮點數(shù)
e, E 指數(shù)格式雙精度浮點數(shù)
g, G 根據(jù)轉(zhuǎn)換后的值解釋為f、F、e或E
a, A 106進(jìn)制指數(shù)格式雙進(jìn)度浮點數(shù)
c 字符
s 字符串
p 指向void的指針
n 到目前為止,此printf調(diào)用輸出的字符的數(shù)目將被寫入到指針?biāo)赶虻膸Х栒椭?/td>
% 1個%字符
C 寬字符
S 寬字符串

下面是各個參數(shù)的效果:

#include <stdio.h> int main(void) { printf("%+0.1lf\n", 1.23456); //+1.2 printf("%+0.1lf\n", -1.23456); //⑴.2 printf("%+8.2lf\n", -1.23456); // ⑴.23 printf("%8.6d\n", 123); // 000123 return 0; }

標(biāo)準(zhǔn)庫還提供了使用可變長參數(shù)的版本,功能與對應(yīng)版本類似:

#include <stdio.h> #include <stdarg.h> int vprintf(const char *format, va_list ap); int vfprintf(FILE *stream, const char *format, va_list ap); int vsprintf(char *str, const char *format, va_list ap); int vsnprintf(char *str, size_t size, const char *format, va_list ap); int vdprintf(int fd, const char *format, va_list ap);

格式化輸入用于分析字符串并轉(zhuǎn)換成對應(yīng)類型變量保存起來,主要通過scanf()系列函數(shù):

#include <stdio.h> int scanf(const char *format, ...); int fscanf(FILE *stream, const char *format, ...); int sscanf(const char *str, const char *format, ...);

完全的參數(shù)為:

%[*] [fldwidth] [m] [lenmodifier] convtype

fldwidth-最大字符寬度
m-當(dāng)要輸入的是字符串時,該參數(shù)指定提供的緩沖區(qū)的大小
lenmodifier-轉(zhuǎn)換后要賦值的參數(shù)大小
convtype-要轉(zhuǎn)化的參數(shù)類型,與printf()系列函數(shù)級別1致。當(dāng)該標(biāo)志代表無符號變量且輸入的數(shù)據(jù)是負(fù)數(shù)時,將轉(zhuǎn)換為2進(jìn)制相同的正數(shù),例如⑴轉(zhuǎn)為4294967295。
標(biāo)準(zhǔn)庫一樣提供了變長參數(shù)的版本,不再贅述。

3.7 清洗1個流

在向1個流寫入數(shù)據(jù)后數(shù)據(jù)并沒有真正交給內(nèi)核,而是在用戶空間的緩沖區(qū)內(nèi)保存,等待數(shù)據(jù)積累到適合大小后再要求內(nèi)核。標(biāo)準(zhǔn)庫提供了立行將緩沖區(qū)數(shù)據(jù)提交內(nèi)核的函數(shù)。

#include <stdio.h> int fflush (FILE *stream);

該函數(shù)調(diào)用后,stream中的數(shù)據(jù)會被flush到內(nèi)核緩沖區(qū),此時與直接調(diào)用write()的效果是1樣的。如果需要確保數(shù)據(jù)被提交給硬盤,需要使用fysnc()或相同功能的系統(tǒng)調(diào)用。1般fflush()后都要調(diào)用fsync()來確保數(shù)據(jù)從用戶緩沖區(qū)到內(nèi)核緩沖區(qū)再到硬盤。

3.8 毛病和文件結(jié)束

fread()函數(shù)的返回值不能辨別產(chǎn)生毛病還是遇到了EOF,標(biāo)準(zhǔn)庫提供了毛病檢查函數(shù):

#include <stdio.h> int ferror (FILE *stream);

用于檢測stream上是不是有毛病標(biāo)志。毛病標(biāo)志由標(biāo)準(zhǔn)I/O相干函數(shù)設(shè)置,如果存在毛病標(biāo)志,該函數(shù)返回非0值,否則返回0。

#include <stdio.h> int feof (FILE *stream);

用來檢測stream是不是到了文件結(jié)尾。若到文件結(jié)尾,返回非0,否則返回0。

#include <stdio.h> void clearerr (FILE *stream);

用于清算stream的errno和EOF標(biāo)志。

3.9 取得關(guān)聯(lián)的文件描寫符

與fdopen()相對,fileno()用于獲得與流關(guān)聯(lián)的文件描寫符。但是不建議讀寫文件時將文件描寫符和流混用。

#include <stdio.h> int fileno (FILE *stream);

失敗時返回⑴并設(shè)置errno。

3.10 控制緩沖

標(biāo)準(zhǔn)I/O庫提供了3種緩沖類型,分別為:
不緩沖
不履行用戶空間緩沖,數(shù)據(jù)直接提交給內(nèi)核。這類情況下使用標(biāo)準(zhǔn)I/O沒有甚么優(yōu)勢。標(biāo)準(zhǔn)毛病就是這類緩沖模式。
行緩沖
遇到換行符時將緩沖區(qū)提交到內(nèi)核。標(biāo)準(zhǔn)輸出是這類緩沖模式,也叫全緩沖。
塊緩沖
默許的緩沖模式,緩沖效果最好。

#include <stdio.h> int setvbuf (FILE *stream, char *buf, int mode, size_t size);

控制緩沖類型,mode多是:
_IONBF-不緩沖
_IOLBF-行緩沖
_IOFBF-塊緩沖

在_IONBF模式下,buf和size參數(shù)被疏忽。其他模式下標(biāo)準(zhǔn)I/O會使用buf作為緩沖區(qū),其大小是size。當(dāng)buf是NULL時,緩沖區(qū)被自動分配。默許的緩沖區(qū)大小為BUFSIZ宏定義的,是塊大小的整數(shù)倍。setbuf()必須在打開流后,做任何其他操作之前被調(diào)用,失敗時返回非0并設(shè)置errno。
還要注意緩沖區(qū)是局部變量時,1定要在局部變量失效前關(guān)閉流,毛病的使用例如

#include <stdio.h> int main(void) { char buf[BUFSIZ]; setbuf(stdin, buf); printf("Hello, world!\n"); return 0; }

內(nèi)存流

標(biāo)準(zhǔn)I/O庫提供了fmemopen()函數(shù)來打開位于內(nèi)存的流,而不與底層文件相干聯(lián),其用用戶指定的緩沖區(qū)單做文件讀寫的位置,返回1個FILE*。

#include <stdio.h> FILE *fmemopen(void *buf, size_t size, const char *mode);

buf-緩沖區(qū)的起始地址,若該參數(shù)是NULL,庫函數(shù)會幫助分配1個size大小的緩沖區(qū),在關(guān)閉流的時候被釋放。
size-緩沖區(qū)大小。
mode-讀寫模式,與fopen()參數(shù)類似。
注意事項:
1 當(dāng)以追加方式打開內(nèi)存流時,當(dāng)前的文件讀寫位置是緩沖區(qū)中的第1個字符串結(jié)束符位置(‘\0’)。緩沖區(qū)中無字符串結(jié)束符時,文件位置是緩沖區(qū)結(jié)尾的后1個字節(jié)。
2 當(dāng)內(nèi)存流不是以追加方式打開時,當(dāng)前文件位置是緩沖區(qū)開始的位置
3 buf是NULL,以只讀或只寫方式打開內(nèi)存流沒成心義。由于我們沒辦法知道分配的緩沖區(qū)的地址,因此只能讀取我們沒法寫入的數(shù)據(jù)或?qū)懭胛覀儧]法讀取的數(shù)據(jù)
4 增加內(nèi)存流中數(shù)據(jù)或調(diào)用fclose()、fflush()、fseek()、fseeko()和fsetpos()時都會在當(dāng)前位置增加1個字符串結(jié)束符
下面代碼測試上述內(nèi)容:

#include <stdio.h> #include <string.h> #include <iostream> using namespace std; int main(void) { //============ //追加模式下文件位置是第1個'\0'處,非追加模式下是緩沖區(qū)開始位置 FILE* fp =NULL; char buffer[256] = "this is a buffer."; fp = fmemopen(buffer, 256, "r+"); cout << ftell(fp) << endl;//0 fclose(fp); fp = fmemopen(buffer, 256, "a+"); cout << ftell(fp) << " " << strlen(buffer) << endl;//17 17 fclose(fp); //============ //============緩沖區(qū)內(nèi)容增加,會自動寫入'\0' fp = fmemopen(buffer, 256, "w+"); fputc('a', fp); fflush(fp); cout << buffer << endl;//a cout << &buffer[2] << endl;//is a buffer. 由于'th'變成了a'\0' fclose(fp); //============ return 0; }

由于內(nèi)存流依賴字符串結(jié)束符,因此以2進(jìn)制的情勢讀寫文件流其實不適合,由于2進(jìn)制數(shù)據(jù)中’\0’出現(xiàn)的位置有多是1條數(shù)據(jù)的中間而不是結(jié)尾,使用內(nèi)存流來讀寫2進(jìn)制數(shù)據(jù)極可能會破壞數(shù)據(jù)。
類似的函數(shù)還有

#include <stdio.h> FILE *open_memstream(char **ptr, size_t *sizeloc);//對char類型的字符串做操作 #include <wchar.h> FILE *open_wmemstream(wchar_t **ptr, size_t *sizeloc);//對寬字節(jié)的字符串做操作

與fmemopen()區(qū)分在于:
* 創(chuàng)建的流沒法指定讀寫模式,只能寫打開
* 不能自行指定緩沖區(qū),函數(shù)返回時指針指向標(biāo)準(zhǔn)庫分配的緩沖區(qū)。由于緩沖區(qū)可能會被重新分配(例如1開始分配的緩沖區(qū)不夠擴(kuò)大了),因此*ptr指向的地址可能會變
* 關(guān)閉流后需要自行釋放緩沖區(qū)
* 緩沖區(qū)會隨著流數(shù)據(jù)的增多而變大,每次fflush()或fclose()后sizeloc指向的值可能會被改變

內(nèi)存流的作用

最直觀的作用是其提供了1個處于內(nèi)存中的文件指針,使我們可以像讀寫文件1樣操作1塊內(nèi)存,方便的使用標(biāo)準(zhǔn)I/O提供的函數(shù)調(diào)用而沒有真正讀寫文件的性能損失。在1些特殊的第3方API中,可能需要1個FILE*類型的參數(shù),但是此時都在內(nèi)存中,這時候?qū)?nèi)存寫入文件再傳到第3方API中明顯是不劃算的,因此可以將對應(yīng)的內(nèi)存映照為打開的文件。另外對open_memstream()相干的函數(shù)來講,其內(nèi)部管理了緩沖區(qū),使我們不需要擔(dān)心緩沖區(qū)溢出的問題,此時可以方便的格式化或拼接字符串,例如格式化1段sql語句等。

3.11 線程安全

多線程程序中線程同享進(jìn)程的資源,因此需要對同享資源做線程同步操作,避免產(chǎn)生非預(yù)期的結(jié)構(gòu),標(biāo)準(zhǔn)I/O默許是線程安全的(即在多線程并發(fā)讀寫同1個文件時,讀寫操作在任意時刻只能運(yùn)行1個,且上1個要求結(jié)束前不會被其他讀寫要求搶占CPU)。
下面的代碼驗證線程安全:

//編譯時要-lpthread,鏈接pthread庫 #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> void *thrd_func(void *arg); FILE *stream; int main() { pthread_t tid; int *thread_ret = NULL; stream = fopen("1.txt", "a"); if (!stream) { perror("fopen"); return -1; } if (pthread_create(&tid,NULL,thrd_func,NULL)!=0)//創(chuàng)建1個線程,使其與主線程同時向1個流輸出內(nèi)容。 { printf("Create thread error!\n"); exit(1); } for(int i = 0; i<10000; ++i) { if (fputs("This is a test line,it should not be broken1\r\n", stream) == EOF) { printf("err!"); } } pthread_join(tid, (void**)&thread_ret ); return 0; } void *thrd_func(void *arg) { for(int i = 0; i<10000; ++i) { if (fputs("This is a test line,it should not be broken2\r\n", stream) == EOF) { printf("err!"); } } pthread_exit(NULL); }

在多核的主機(jī)上運(yùn)行上述代碼,可以看到”This is a test line,it should not be broken1”和”This is a test line,it should not be broken2”交替出現(xiàn),但是每行都是完全的。交替出現(xiàn)的緣由是不同的CPU核心會同時向文件寫入字符串。
上面的代碼也暴露了1些問題,假設(shè)現(xiàn)在有1個多線程的服務(wù)器,要在日志中打印出來內(nèi)部1個map中的數(shù)據(jù),那末在實際情況中極可能打印出的內(nèi)容被其他線程的日志輸出穿插,讀日志時帶來1些困難,這就需要線程同步來進(jìn)行,標(biāo)準(zhǔn)I/O庫提供了針對流的加鎖功能。

3.11.1 手動文件加鎖

用flockfile()給對應(yīng)流加鎖,用funlockfile()解鎖。

#include <stdio.h> void flockfile (FILE *stream); void funlockfile (FILE *stream);

標(biāo)準(zhǔn)I/O庫中的鎖是遞歸鎖(可重入鎖),即1個線程可以屢次取得該鎖而不被鎖死或斷言毛病。該鎖使用計數(shù),當(dāng)flockfile()時,計數(shù)器+1;funlockfile()時,計數(shù)器⑴,因此調(diào)用funlockfile()的次數(shù)1定要與flockfile()次數(shù)1致,特別是毛病處理提早返回時更要謹(jǐn)慎。當(dāng)計數(shù)器為0時,代表線程不再保持鎖,此時其他線程對同1個流加鎖的話能夠無阻塞的取得鎖。
當(dāng)?shù)?次加鎖成功時flockfile()返回0,當(dāng)前線程取得鎖;已取得鎖時本線程再次調(diào)用flockfile(),返回非0。
在輸出map元素之前加鎖,輸出完成后釋放鎖,這樣就能夠保證map的數(shù)據(jù)在1起而不被其他信息穿插了。

3.11.2 不加鎖流操作

既然開發(fā)人員選擇手動控制鎖的范圍,那末就沒必要在讀寫文件時再次加鎖了。標(biāo)準(zhǔn)庫提供了1系列不加鎖的庫函數(shù)。

#define _GNU_SOURCE #include <stdio.h> int fgetc_unlocked (FILE *stream); char *fgets_unlocked (char *str, int size, FILE *stream); size_t fread_unlocked (void *buf, size_t size, size_t nr,FILE *stream); int fputc_unlocked (int c, FILE *stream); int fputs_unlocked (const char *str, FILE *stream); size_t fwrite_unlocked (void *buf, size_t size, size_t nr, FILE *stream); int fflush_unlocked (FILE *stream); int feof_unlocked (FILE *stream); int ferror_unlocked (FILE *stream); int fileno_unlocked (FILE *stream); void clearerr_unlocked (FILE *stream);

這些函數(shù)除不再加鎖外,行動與加鎖版本1致。
感興趣的同學(xué)可以做1下小練習(xí),將之前校驗標(biāo)準(zhǔn)I/O線程安全的代碼改用非加鎖的調(diào)用,試試看輸出文件有甚么變化。
另外還可以用系統(tǒng)調(diào)用write()來測試1下write()是不是是線程安全的(事實上系統(tǒng)調(diào)用基本都是原子操作,即線程安全的,但是write()比較特殊,其內(nèi)部是兩個調(diào)用:定位和寫入。不使用O_APPEND模式的話,可能會由于偏移量沒有增加而致使寫入內(nèi)容被覆蓋,這里有資料,因此在多線程讀寫時,如果不打算自己做線程同步的話,使用系統(tǒng)調(diào)用write()時1定要加上O_APPEND標(biāo)志)

3.12 對標(biāo)準(zhǔn)I/O的批評

首先需要明確的是標(biāo)準(zhǔn)I/O提供了非常方便的用戶空間緩沖機(jī)制,使開發(fā)人員無需關(guān)注系統(tǒng)的塊大小而提高文件I/O效力;其次庫函數(shù)提供了便利的操作,能夠按行讀寫文本;另外由因而標(biāo)準(zhǔn)庫,其代碼可移植性非常高,使用也廣泛。
但標(biāo)準(zhǔn)I/O庫也有1些缺點,其中1個就是雙副本問題。雙副本問題是指,標(biāo)準(zhǔn)I/O庫內(nèi)部保護(hù)了1個緩沖區(qū),從內(nèi)核讀取到的數(shù)據(jù)拷貝到該緩沖區(qū)中保護(hù),在用戶需要數(shù)據(jù)時,要再次拷貝到用戶指定的地址中:1段數(shù)據(jù)在用戶空間中有兩個副本,同時也有兩次拷貝操作,寫入時也是類似情況。
對讀取操作,1個改良方式是返回1個指向標(biāo)準(zhǔn)I/O緩沖區(qū)的指針,用戶程序只有在修改讀取內(nèi)容或在緩沖區(qū)被清空之前拷貝數(shù)據(jù)便可。另外setvbuf()函數(shù)設(shè)置的用戶緩沖區(qū)是否是也能減少1次拷貝?
對寫操作,可使用[分散輸入和集中輸出]的I/O模式,見后面章節(jié)內(nèi)容。
另外一些函數(shù)庫也提供了相干解決方案,例如快速I/O庫(fio、sfio)、映照文件(mmap函數(shù))。

生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 欧美一区二区在线 | 国产精品久久久久婷婷二区次 | 日本激情| 中文字幕福利 | 久久91精品国产一区二区三区 | 91久久久久久 | 精品成人av | 中文字幕av网站 | 不卡一二三区 | 天堂成人国产精品一区 | 亚洲精品一二 | 成人午夜影院 | 日本福利一区二区三区 | 日韩国产在线播放 | 国产精品美女久久久 | 亚洲精品乱码久久久久久按摩观 | 嫩呦国产一区二区三区av | 国产精品日韩一区二区 | 国产免费一区 | 国产精品久久久久久久久免费看 | 在线播放a| 在线久热| 日韩一区二区三区在线 | 国产成人精品a视频一区www | 日韩高清一级 | 成人欧美一区二区三区在线播放 | 免费国产一区二区 | 精品国产一区二区三区麻豆小说 | 色网在线观看 | 日韩城人免费 | 久久久久国产一区二区 | 中文字幕一区二区av | 欧洲一区二区 | 久久久久久久一区二区三区 | 免费在线播放av | 91亚洲国产精品 | 国产在线不卡视频 | 免费av网站在线看 | 成人久久久 | 欧美黄色一区二区 | 日本中文字幕电影 |