linux高階程式設計——IO
1,檔案IO
1)open——開啟或建立一個檔案
open(char *,flag,mode)在fcntl.h檔案中宣告。
引數:
char * 包含有檔名和路徑
flag 開啟檔案方式
mode 建立檔案的許可權
flag 內容
flag | 功能 |
O_RDONLY | 只讀 |
O_WRONLY | 只寫 |
O_RDWR | 讀寫 |
O_CREAT | 建立一個檔案 |
O_EXCL | 如果使用O_CREAT是檔案存在,則可返回錯誤訊息。這一引數可測試檔案是否存在 |
O_TRUNC | 開啟檔案(會刪除已存在的內容) |
O_APPEND | 追加方式開啟檔案(不會刪除已存在的內容) |
許可權:檔案許可權 == mode&(~umask)
返回值:
成功:檔案描述符(在一個程序中,為了區別每個檔案),非負正整數,即檔案的ID號;
出錯:-1;
2)write————寫
write (int fd,void *buf,size t count);
引數:
fd 向哪個檔案去寫
*buf 寫什麼內容
t 寫多少個
返回值:
實際寫的位元組數
3)read————讀
read (int fd,void *buf, size t count)
引數:
fd 從哪個檔案去讀
*buf 讀什麼內容
t 讀多少個
返回值:
實際讀的位元組數
4)close————關閉檔案
close(fd);
——————————————————————————————————————————————————————————————————
——————————————————————————————————————————————————————————————————
5) lseek ————調整讀寫位置指標
lseek(int fd,off_t offset,int whence);
標頭檔案:sys/types.h unist.h;
引數:
fd : 要調整的檔案的檔案描述符
offset : 偏移量,每一讀寫操作所需要移動的距離,單位是位元組的數量,可正可負;
whence : 當前位置的基點,有三個標誌:
SEEK_SET : 當前位置為檔案的開頭,新位置為偏移量的大小(後移為正,前移為負)
SEEK_CUR : 當前位置為檔案指標的位置,新位置為當前位置加偏移量
SEEK_END : 當前位置為檔案的結尾,新位置為檔案大小加偏移量的大小
返回值:
成功:檔案當前的位置
出錯:-1
******************************************************************************************************************************************************************************
檔案IO:是直接呼叫核心提供的系統呼叫函式,標頭檔案:unistd.h
標準IO:是間接點用系統呼叫函式,標頭檔案: stdio.h
三個快取:
1,程式中的快取,就是你想從核心讀寫的快取(陣列)——使用者空間的快取
2,每開啟一個檔案,核心在核心空間中也會開闢一塊快取,——核心空間快取
檔案IO的 寫 ——> 將使用者空間的快取寫到核心空間的快取中
檔案IO的 讀 ——>將核心空間的快取讀到使用者空間的快取
3,標準IO的庫函式中也有一個快取 —— 庫快取
2,標準IO
printf滿足一定條件才能將庫快取的內容寫到核心:遇到\n;庫快取寫滿時,會呼叫系統呼叫函式。(庫快取為1024位元組)
1)fopen 開啟
2) fclose 關閉 ,在關閉之前重新整理快取區,強制寫入核心
3) fseek,rewind 位置指標
4) 讀寫函式較多(分三類:全快取,行快取,無快取)
1) FILE *fopen (const char *path , const char *mode); 建立一個檔案設定的許可權為666,生成檔案的許可權為 666&(~umask)
返回值:FILE * 檔案流指標 類似於檔案IO中的檔案描述符
FILE 定義 : struct_IO_FILE 在/usr/include/libio.h
包含讀寫快取的首地址、大小、位置指標等
標準的輸入流:stdin 0
標準的輸出流:stdout 1
標準的出錯流: stderr 2
引數:path 檔案的位置
mode 相當於檔案IO的flag (char * 字串)
b : 二進位制檔案
r : 只讀方式開啟檔案,檔案必須存在
w/a : 只寫方式開啟檔案,檔案不存在則建立;
區別: w == O_TRUNC ; a == O_APPEND
+ : 讀寫方式開啟檔案,檔案必須存在;
2)fcloes
3)讀寫函式
1, 行快取 遇到新行符(\n) 或寫滿快取時,即呼叫系統呼叫函式
讀: fgets,gets,printf,fprintf,sprintf
寫: fputs,puts,scanf
2, 無快取 只要使用者呼叫這個函式,就會將其內容寫到核心中
3,全快取 只有寫滿快取再呼叫系統呼叫函式
讀 :fread
寫 :fwrite
3.1 行快取的讀寫函式fgets, fputs
char *fgets (char *s,int size , FILE *stream);
引數:
s : 快取,即讀到哪裡去
size : 讀多少位元組
stream : 從什麼地方讀
返回值:
成功: s (快取的地址)
已處於檔案尾端或出錯: null
int fputs (const char *s,FILE *stream);
引數:
s : 快取。即寫什麼內容
stream : 寫到哪裡去
返回值:
成功:非負值
出錯:EOF -1
3.2 fflush(FILE *fp)
把庫函式的快取內容強制寫入核心(在fclose 中包含)
3.3 無快取: stderr
stdout 行快取
3.4 調整位置指標
fseek()
引數與lseek()一致,但返回值不同
返回值:
成功:0
失敗:-1
rewind(FILE *fp) 用於設定流的檔案位置指示為檔案開始,該函式呼叫成功無返回值。
rewind() == (void) fseek(fp 0,SEEK_SET);
ftell(FEIL *fp)
用於取得當前的檔案位置,呼叫成功則為當前檔案位置指示,出錯則為 -1L;
3.5 行快取的讀寫函式 gets , puts
char *gets (char *s);
int puts (const char *s);
gets 與 fgets 的區別:
gets() 時不能指定快取的長度,可能造成快取越界,寫到快取之後的儲存空間,產生不可預料的後果;
gets()只能從標準輸入中讀;
gets() 並不將新行符存入快取,fgets()將新行符存入快取;
puts 與 fputs 的區別:
puts()只能向標準輸出中寫;
puts() 輸出是會新增一個新行符,fputs() 不會新增;
3.6 fprintf, printf, sprintf 行快取的函式
int fprintf (FILE *stream,"字串格式")
fprintf 可以輸出到檔案中,也可以輸出到顯示器 eg: fprintf(fp,"hello linux");
printf 只能輸出到顯示器
int sprintf (str *,"字串格式")
輸出內容到一個字串中 eg: char buf[128] = 0; sprintf (buf,"hello linux");
3.7 一個字元的讀寫函式
int fgetc(FILE *fp) 將檔案中的內容一個字元的輸出到顯示器,到檔案結尾時返回EOF
功能: 從檔案讀取一個字元
引數: 檔案流
返回值: 正確為讀取到的字元;到檔案結尾或出錯時返回EOF
int fputc(int c, FILE *fp) 輸入一個字元到檔案中,成功則返回輸入的字元,出錯則返回EOF
功能:寫一個特字元到檔案中
引數:第一個引數為要寫的字元,第二個為檔案流
返回值: 正確為返回輸入的字元,出錯返回EOF
fputs 有快取,但不是行快取
——————————————————————————————————————————————————————————————————————————————
——————————————————————————————————————————————————————————————————————————————
3.8 feof 判斷受否已經到檔案結尾
int feof (FILE *stream);
引數:檔案流
返回值:檔案結束,返回非0;沒有則返回0;
3.9 ferror 判斷是否讀寫錯誤
int derror (FILE *stream);
引數:檔案流
返回值: 是讀寫錯誤,返回非0;不是則返回0;
3.10 clearerr 清除流錯誤
void clearerr (FILE *stream);
引數:檔案流
————————————————————————————————————————————————————————————————————————————————
————————————————————————————————————————————————————————————————————————————————
全快取
fread 和 fwrite 全快取的讀寫函式
size_t fread (void *ptr ,size_t size,size_t nmemb,FILE *stream);
size_t fwrite (const void *ptr,size_t size,xize_t nmemb,FILE *stream);
引數:
ptr: 寫的內容
size: 寫的內容中,每一個單元所佔的位元組數
nmemb: 寫的內容中,有多少個單元
stream: 寫到哪裡去
總共所寫的位元組:size * nmemb
返回值: 實際讀寫的單元數
linux下靜態庫和動態庫的製作與使用
- 靜態庫
libxxx.a , 在編譯時就將庫編譯進可執行程式中。
優點:程式的執行環境中不需要外部的函式庫
缺點:可執行程式大
- 動態庫
又稱共享庫,libxxx.so ,在執行時將庫載入到可執行程式中。
優點:可執行程式小
缺點:程式的執行環境中必須提供相應的庫。
函式庫目錄:/lib /usr/lib
靜態庫的製作:
1,生成目標檔案:gcc -c file.c
2,靜態庫建立命令 ar
ar -cr libfile.a file.o
-c : create
-r :replace ,表示當插入的模組 file.o 已經存在 libfile.a 中,則覆蓋。反之 ar 顯示一個錯誤訊息
1)由原始檔生成目標檔案 gcc -c -o sub.o sub.c
2)把目標檔案生成靜態庫 ar -cr -o libsub.a sub.o
3) gcc -o a main.c -L. -lsub . 代表當前目錄;-lcub 預設libxxx.o
動態庫製作:
1,生成目標檔案 :gcc -c -o file.c
2,gcc -shared -fpic -o libfile.so file.o
-fpic : 產生位置無關程式碼
-shared: 生成共享庫。
用上述命令生成 libsub.so 動態函式庫
gcc -o out main.c -L. -lsub
此時還不能直接 ./out ,因為在動態函式庫使用時,會查詢/usr/lib /lib 目錄下的動態函式庫,而此時生成的庫還不在裡邊
解決方法:
1) 把 libsub.so 放到 /usr/lib /lib 中去
2)假設 libsub.so 在/home/linux/file 中 環境變數的方式
export LD_LIBRARY_PATH = /home/linux/sddsub
LD_LIBRARY_PATH
3) 在 /etc/l.so.conf 檔案中加入生成庫的路徑,然後 /sbin/ldconfig
/etc/ld.so.conf 時非常重要的一個目錄,裡面存放的時連結器和載入器搜尋共享庫時要檢查的目錄,預設是從 /usr/lib /lib 中讀取,所以可以把庫的目錄假如這個檔案並執行 /sbin/ldconfig
目錄IO
#include <sys/types.h>
#inlcude <dirent.h>
目錄IO | 檔案IO |
opendir 只能開啟目錄 mkdir 建立目錄 |
open |
readdir 讀目錄 | read |
rewinddir 調整指標位置 telldir seekdir |
rewind ftell fseek |
closedir 關閉目錄 | close |
1,opendir
DIR *opendir (const char *pathname);
引數:開啟的目錄及路徑
返回值: 成功返回目錄流指標,出錯返回NULL
int mkdir (const char * path ,mode_t mode )
path: 為想建立的目錄檔案路徑
mode: 為該目錄的訪問許可權
返回值:若目錄建立,則返回0;否則-1;
生成的目錄許可權仍和umask有關
2,readdir
struct dirent *readdir (DIR *dr)
引數:目錄流指標
返回值:成功 則為 struct dirent 指標,瑞在目錄尾或出錯則返回NULL
struct dirent 定義在標頭檔案 dirent.h中
此結構至少包括下列兩個成員:
struct dirent
{
ino_t d_ino ; // inode 號
char d_name[NAME_MAX+1]; //檔名
}
3,rewinddir: 重置讀取目錄的位置為開頭
void rewinddir(DIR *dr);
引數:目錄流指標
long telldir(DIR *dirp) 讀取當前指標的位置
引數:目錄流指標
返回值:目錄流當前位置
void seekdir(DIR *dirp,long loc);
類似於檔案定位函式fseek(), 在目錄流上設定下一個 readdir() 操作的位置
引數:目錄流指標和偏移量