10. 文件操做linux
10.1 概述windows
10.1.1磁盤文件和設備文件編輯器
l 磁盤文件函數
指一組相關數據的有序集合,一般存儲在外部介質(如磁盤)上,使用時才調入內存。ui
l 設備文件this
在操做系統中把每個與主機相連的輸入、輸出設備看做是一個文件,把它們的輸入、輸出等同於對磁盤文件的讀和寫。編碼
10.1.2 磁盤文件的分類spa
計算機的存儲在物理上是二進制的,因此物理上全部的磁盤文件本質上都是同樣的:以字節爲單位進行順序存儲。操作系統
從用戶或者操做系統使用的角度(邏輯上)把文件分爲:指針
l 文本文件:基於字符編碼的文件
l 二進制文件:基於值編碼的文件
10.1.3 文本文件和二進制文件
1)文本文件
l 基於字符編碼,常見編碼有ASCII、UNICODE等
l 通常可使用文本編輯器直接打開
l 數5678的以ASCII存儲形式(ASCII碼)爲:
00110101 00110110 00110111 00111000
2)二進制文件
l 基於值編碼,本身根據具體應用,指定某個值是什麼意思
l 把內存中的數據按其在內存中的存儲形式原樣輸出到磁盤上
l 數5678的存儲形式(二進制碼)爲:00010110 00101110
10.2 文件的打開和關閉
10.2.1 文件指針
在C語言中用一個指針變量指向一個文件,這個指針稱爲文件指針。
1 typedef struct 2 3 { 4 5 short level; //緩衝區"滿"或者"空"的程度 6 7 unsigned flags; //文件狀態標誌 8 9 char fd; //文件描述符 10 11 unsigned char hold; //如無緩衝區不讀取字符 12 13 short bsize; //緩衝區的大小 14 15 unsigned char *buffer;//數據緩衝區的位置 16 17 unsigned ar; //指針,當前的指向 18 19 unsigned istemp; //臨時文件,指示器 20 21 short token; //用於有效性的檢查 22 23 }FILE;
FILE是系統使用typedef定義出來的有關文件信息的一種結構體類型,結構中含有文件名、文件狀態和文件當前位置等信息。
聲明FILE結構體類型的信息包含在頭文件「stdio.h」中,通常設置一個指向FILE類型變量的指針變量,而後經過它來引用這些FILE類型變量。經過文件指針就可對它所指的文件進行各類操做。
C語言中有三個特殊的文件指針由系統默認打開,用戶無需定義便可直接使用:
l stdin: 標準輸入,默認爲當前終端(鍵盤),咱們使用的scanf、getchar函數默認今後終端得到數據。
l stdout:標準輸出,默認爲當前終端(屏幕),咱們使用的printf、puts函數默認輸出信息到此終端。
l stderr:標準出錯,默認爲當前終端(屏幕),咱們使用的perror函數默認輸出信息到此終端。
10.2.2 文件的打開
任何文件使用以前必須打開:
#include <stdio.h>
FILE * fopen(constchar * filename, constchar * mode);
功能:打開文件
參數:
filename:須要打開的文件名,根據須要加上路徑
mode:打開文件的模式設置
返回值:
成功:文件指針
失敗:NULL
第一個參數的幾種形式:
FILE *fp_passwd = NULL;
//相對路徑:
//打開當前目錄passdw文件:源文件(源程序)所在目錄
FILE *fp_passwd = fopen("passwd.txt", "r");
//打開當前目錄(test)下passwd.txt文件
fp_passwd = fopen(". / test / passwd.txt", "r");
//打開當前目錄上一級目錄(相對當前目錄)passwd.txt文件
fp_passwd = fopen(".. / passwd.txt", "r");
//絕對路徑:
//打開C盤test目錄下一個叫passwd.txt文件
fp_passwd = fopen("c://test//passwd.txt","r");
第二個參數的幾種形式(打開文件的方式):
打開模式 |
含義 |
r或rb |
以只讀方式打開一個文本文件(不建立文件,若文件不存在則報錯) |
w或wb |
以寫方式打開文件(若是文件存在則清空文件,文件不存在則建立一個文件) |
a或ab |
以追加方式打開文件,在末尾添加內容,若文件不存在則建立文件 |
r+或rb+ |
以可讀、可寫的方式打開文件(不建立新文件) |
w+或wb+ |
以可讀、可寫的方式打開文件(若是文件存在則清空文件,文件不存在則建立一個文件) |
a+或ab+ |
以添加方式打開文件,打開文件並在末尾更改文件,若文件不存在則建立文件 |
注意:
l b是二進制模式的意思,b只是在Windows有效,在Linux用r和rb的結果是同樣的
l Unix和Linux下全部的文本文件行都是\n結尾,而Windows全部的文本文件行都是\r\n結尾
l 在Windows平臺下,以「文本」方式打開文件,不加b:
n 當讀取文件的時候,系統會將全部的 "\r\n" 轉換成 "\n"
n 當寫入文件的時候,系統會將 "\n" 轉換成 "\r\n" 寫入
n 以"二進制"方式打開文件,則讀\寫都不會進行這樣的轉換
l 在Unix/Linux平臺下,「文本」與「二進制」模式沒有區別,"\r\n" 做爲兩個字符原樣輸入輸出
1 int main(void) 2 3 { 4 5 FILE *fp = NULL; 6 7 8 9 // "\\"這樣的路徑形式,只能在windows使用 10 11 // "/"這樣的路徑形式,windows和linux平臺下均可用,建議使用這種 12 13 // 路徑能夠是相對路徑,也但是絕對路徑 14 15 fp = fopen("../test", "w"); 16 17 //fp = fopen("..\\test", "w"); 18 19 20 21 if (fp == NULL) //返回空,說明打開失敗 22 23 { 24 25 //perror()是標準出錯打印函數,能打印調用庫函數出錯緣由 26 27 perror("open"); 28 29 return -1; 30 31 } 32 33 34 35 return 0; 36 37 } 38 39
10.2.3 文件的關閉
任何文件在使用後應該關閉:
l 打開的文件會佔用內存資源,若是老是打開不關閉,會消耗不少內存
l 一個進程同時打開的文件數是有限制的,超過最大同時打開文件數,再次調用fopen打開文件會失敗
l 若是沒有明確的調用fclose關閉打開的文件,那麼程序在退出的時候,操做系統會統一關閉。
#include <stdio.h>
int fclose(FILE * stream);
功能:關閉先前fopen()打開的文件。此動做讓緩衝區的數據寫入文件中,並釋放系統所提供的文件資源。
參數:
stream:文件指針
返回值:
成功:0
失敗:-1
FILE * fp = NULL;
fp = fopen("abc.txt", "r");
fclose(fp);
10.3 文件的順序讀寫
10.3.1 按照字符讀寫文件fgetc、fputc
#include <stdio.h>
int fputc(int ch, FILE * stream);
功能:將ch轉換爲unsigned char後寫入stream指定的文件中
參數:
ch:須要寫入文件的字符
stream:文件指針
返回值:
成功:成功寫入文件的字符
失敗:返回-1
1 char buf[] = "this is a test for fputc"; 2 3 int i = 0; 4 5 int n = strlen(buf); 6 7 for (i = 0; i < n; i++) 8 9 { 10 11 //往文件fp寫入字符buf[i] 12 13 int ch = fputc(buf[i], fp); 14 15 printf("ch = %c\n", ch); 16 17 }
在C語言中,EOF表示文件結束符(end of file)。在while循環中以EOF做爲文件結束標誌,這種以EOF做爲文件結束標誌的文件,必須是文本文件。在文本文件中,數據都是以字符的ASCII代碼值的形式存放。咱們知道,ASCII代碼值的範圍是0~127,不可能出現-1,所以能夠用EOF做爲文件結束標誌。
#define EOF (-1)
當把數據以二進制形式存放到文件中時,就會有-1值的出現,所以不能採用EOF做爲二進制文件的結束標誌。爲解決這一個問題,ANSI C提供一個feof函數,用來判斷文件是否結束。feof函數既可用以判斷二進制文件又可用以判斷文本文件。
#include <stdio.h>
int feof(FILE * stream);
功能:檢測是否讀取到了文件結尾。判斷的是最後一次「讀操做的內容」,不是當前位置內容(上一個內容)。
參數:
stream:文件指針
返回值:
非0值:已經到文件結尾
0:沒有到文件結尾
#include <stdio.h>
int fgetc(FILE * stream);
功能:從stream指定的文件中讀取一個字符
參數:
stream:文件指針
返回值:
成功:返回讀取到的字符
失敗:-1
1 char ch; 2 3 #if 0 4 5 while ((ch = fgetc(fp)) != EOF) 6 7 { 8 9 printf("%c", ch); 10 11 } 12 13 printf("\n"); 14 15 #endif 16 17 18 19 while (!feof(fp)) //文件沒有結束,則執行循環 20 21 { 22 23 ch = fgetc(fp); 24 25 printf("%c", ch); 26 27 } 28 29 printf("\n"); 30 31
10.3.2按照行讀寫文件fgets、fputs
#include <stdio.h>
int fputs(constchar * str, FILE * stream);
功能:將str所指定的字符串寫入到stream指定的文件中,字符串結束符 '\0' 不寫入文件。
參數:
str:字符串
stream:文件指針
返回值:
成功:0
失敗:-1
1 char *buf[] = { "123456\n", "bbbbbbbbbb\n", "ccccccccccc\n" }; 2 3 int i = 0; 4 5 int n = 3; 6 7 for (i = 0; i < n; i++) 8 9 { 10 11 int len = fputs(buf[i], fp); 12 13 printf("len = %d\n", len); 14 15 }
#include <stdio.h>
char * fgets(char * str, int size, FILE * stream);
功能:從stream指定的文件內讀入字符,保存到str所指定的內存空間,直到出現換行字符、讀到文件結尾或是已讀了size - 1個字符爲止,最後會自動加上字符 '\0' 做爲字符串結束。
參數:
str:字符串
size:指定最大讀取字符串的長度(size - 1)
stream:文件指針
返回值:
成功:成功讀取的字符串
讀到文件尾或出錯: NULL
1 char buf[100] = 0; 2 3 4 5 while (!feof(fp)) //文件沒有結束 6 7 { 8 9 memset(buf, 0, sizeof(buf)); 10 11 char *p = fgets(buf, sizeof(buf), fp); 12 13 if (p != NULL) 14 15 { 16 17 printf("buf = %s", buf); 18 19 } 20 21 }
有個文件大小不肯定,每行內容都是一個四則運算表達式,尚未算出結果,寫一個程序,自動算出其結果後修改文件。
10.3.3按照格式化文件fprintf、fscanf
#include <stdio.h>
int fprintf(FILE * stream, constchar * format, ...);
功能:根據參數format字符串來轉換並格式化數據,而後將結果輸出到stream指定的文件中,指定出現字符串結束符 '\0' 爲止。
參數:
stream:已經打開的文件
format:字符串格式,用法和printf()同樣
返回值:
成功:實際寫入文件的字符個數
失敗:-1
fprintf(fp, "%d %d %d\n", 1, 2, 3);
#include <stdio.h>
int fscanf(FILE * stream, constchar * format, ...);
功能:從stream指定的文件讀取字符串,並根據參數format字符串來轉換並格式化數據。
參數:
stream:已經打開的文件
format:字符串格式,用法和scanf()同樣
返回值:
成功:參數數目,成功轉換的值的個數
失敗: - 1
int a = 0;
int b = 0;
int c = 0;
fscanf(fp, "%d %d %d\n", &a, &b, &c);
printf("a = %d, b = %d, c = %d\n", a, b, c);
10.3.4按照塊讀寫文件fread、fwrite
#include <stdio.h>
size_t fwrite(constvoid *ptr, size_t size, size_t nmemb, FILE *stream);
功能:以數據塊的方式給文件寫入內容
參數:
ptr:準備寫入文件數據的地址
size: size_t 爲 unsigned int類型,此參數指定寫入文件內容的塊數據大小
nmemb:寫入文件的塊數,寫入文件數據總大小爲:size * nmemb
stream:已經打開的文件指針
返回值:
成功:實際成功寫入文件數據的塊數目,此值和nmemb相等
失敗:0
1 2 3 typedef struct Stu 4 5 { 6 7 char name[50]; 8 9 int id; 10 11 }Stu; 12 13 14 15 Stu s[3]; 16 17 int i = 0; 18 19 for (i = 0; i < 3; i++) 20 21 { 22 23 sprintf(s[i].name, "stu%d%d%d", i, i, i); 24 25 s[i].id = i + 1; 26 27 } 28 29 30 31 int ret = fwrite(s, sizeof(Stu), 3, fp); 32 33 printf("ret = %d\n", ret);
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:以數據塊的方式從文件中讀取內容
參數:
ptr:存放讀取出來數據的內存空間
size: size_t 爲 unsigned int類型,此參數指定讀取文件內容的塊數據大小
nmemb:讀取文件的塊數,讀取文件數據總大小爲:size * nmemb
stream:已經打開的文件指針
返回值:
成功:實際成功讀取到內容的塊數,若是此值比nmemb小,但大於0,說明讀到文件的結尾。
失敗:0
1 typedef struct Stu 2 3 { 4 5 char name[50]; 6 7 int id; 8 9 }Stu; 10 11 12 13 Stu s[3]; 14 15 int ret = fread(s, sizeof(Stu), 3, fp); 16 17 printf("ret = %d\n", ret); 18 19 20 21 int i = 0; 22 23 for (i = 0; i < 3; i++) 24 25 { 26 27 printf("s = %s, %d\n", s[i].name, s[i].id); 28 29 }
10.4 文件的隨機讀寫
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
功能:移動文件流(文件光標)的讀寫位置。
參數:
stream:已經打開的文件指針
offset:根據whence來移動的位移數(偏移量),能夠是正數,也能夠負數,若是正數,則相對於whence往右移動,若是是負數,則相對於whence往左移動。若是向前移動的字節數超過了文件開頭則出錯返回,若是向後移動的字節數超過了文件末尾,再次寫入時將增大文件尺寸。
whence:其取值以下:
SEEK_SET:從文件開頭移動offset個字節
SEEK_CUR:從當前位置移動offset個字節
SEEK_END:從文件末尾移動offset個字節
返回值:
成功:0
失敗:-1
#include <stdio.h>
long ftell(FILE *stream);
功能:獲取文件流(文件光標)的讀寫位置。
參數:
stream:已經打開的文件指針
返回值:
成功:當前文件流(文件光標)的讀寫位置
失敗:-1
#include <stdio.h>
void rewind(FILE *stream);
功能:把文件流(文件光標)的讀寫位置移動到文件開頭。
參數:
stream:已經打開的文件指針
返回值:
無返回值
1 typedef struct Stu 2 3 { 4 5 char name[50]; 6 7 int id; 8 9 }Stu; 10 11 12 13 //假如已經往文件寫入3個結構體 14 15 //fwrite(s, sizeof(Stu), 3, fp); 16 17 18 19 Stu s[3]; 20 21 Stu tmp; 22 23 int ret = 0; 24 25 26 27 //文件光標讀寫位置從開頭往右移動2個結構體的位置 28 29 fseek(fp, 2 * sizeof(Stu), SEEK_SET); 30 31 32 33 //讀第3個結構體 34 35 ret = fread(&tmp, sizeof(Stu), 1, fp); 36 37 if (ret == 1) 38 39 { 40 41 printf("[tmp]%s, %d\n", tmp.name, tmp.id); 42 43 } 44 45 46 47 //把文件光標移動到文件開頭 48 49 //fseek(fp, 0, SEEK_SET); 50 51 rewind(fp); 52 53 54 55 ret = fread(s, sizeof(Stu), 3, fp); 56 57 printf("ret = %d\n", ret); 58 59 60 61 int i = 0; 62 63 for (i = 0; i < 3; i++) 64 65 { 66 67 printf("s === %s, %d\n", s[i].name, s[i].id); 68 69 }
10.5 Windows和Linux文本文件區別
l b是二進制模式的意思,b只是在Windows有效,在Linux用r和rb的結果是同樣的
l Unix和Linux下全部的文本文件行都是\n結尾,而Windows全部的文本文件行都是\r\n結尾
l 在Windows平臺下,以「文本」方式打開文件,不加b:
n 當讀取文件的時候,系統會將全部的 "\r\n" 轉換成 "\n"
n 當寫入文件的時候,系統會將 "\n" 轉換成 "\r\n" 寫入
n 以"二進制"方式打開文件,則讀\寫都不會進行這樣的轉換
l 在Unix/Linux平臺下,「文本」與「二進制」模式沒有區別,"\r\n" 做爲兩個字符原樣輸入輸出
判斷文本文件是Linux格式仍是Windows格式:
1 #include<stdio.h> 2 3 4 5 int main(int argc, char **args) 6 7 { 8 9 if (argc < 2) 10 11 return 0; 12 13 14 15 FILE *p = fopen(args[1], "rb"); 16 17 if (!p) 18 19 return 0; 20 21 22 23 char a[1024] = { 0 }; 24 25 fgets(a, sizeof(a), p); 26 27 28 29 int len = 0; 30 31 while (a[len]) 32 33 { 34 35 if (a[len] == '\n') 36 37 { 38 39 if (a[len - 1] == '\r') 40 41 { 42 43 printf("windows file\n"); 44 45 } 46 47 else 48 49 { 50 51 printf("linux file\n"); 52 53 } 54 55 } 56 57 len++; 58 59 } 60 61 62 63 fclose(p); 64 65 66 67 return 0; 68 69 } 70 71
10.6 獲取文件狀態
#include <sys/types.h>
#include <sys/stat.h>
intstat(constchar *path, structstat *buf);
功能:獲取文件狀態信息
參數:
path:文件名
buf:保存文件信息的結構體
返回值:
成功:0
失敗-1
struct stat {
dev_t st_dev; //文件的設備編號
ino_t st_ino; //節點
mode_t st_mode; //文件的類型和存取的權限
nlink_t st_nlink; //連到該文件的硬鏈接數目,剛創建的文件值爲1
uid_t st_uid; //用戶ID
gid_t st_gid; //組ID
dev_t st_rdev; //(設備類型)若此文件爲設備文件,則爲其設備編號
off_t st_size; //文件字節數(文件大小)
unsigned long st_blksize; //塊大小(文件系統的I/O 緩衝區大小)
unsigned long st_blocks; //塊數
time_t st_atime; //最後一次訪問時間
time_t st_mtime; //最後一次修改時間
time_t st_ctime; //最後一次改變時間(指屬性)
};
1 #include <sys/types.h> 2 3 #include <sys/stat.h> 4 5 #include <stdio.h> 6 7 8 9 int main(int argc, char **args) 10 11 { 12 13 if (argc < 2) 14 15 return 0; 16 17 18 19 struct stat st = { 0 }; 20 21 22 23 stat(args[1], &st); 24 25 int size = st.st_size;//獲得結構體中的成員變量 26 27 printf("%d\n", size); 28 29 return 0; 30 31 }
10.7 刪除文件、重命名文件名
#include <stdio.h>
intremove(constchar *pathname);
功能:刪除文件
參數:
pathname:文件名
返回值:
成功:0
失敗:-1
#include <stdio.h>
intrename(constchar *oldpath, constchar *newpath);
功能:把oldpath的文件名改成newpath
參數:
oldpath:舊文件名
newpath:新文件名
返回值:
成功:0
失敗: - 1
10.8 文件緩衝區
10.8.1文件緩衝區
ANSI C標準採用「緩衝文件系統」處理數據文件。
所謂緩衝文件系統是指系統自動地在內存區爲程序中每個正在使用的文件開闢一個文件緩衝區從內存向磁盤輸出數據必須先送到內存中的緩衝區,裝滿緩衝區後才一塊兒送到磁盤去。
若是從磁盤向計算機讀入數據,則一次從磁盤文件將一批數據輸入到內存緩衝區(充滿緩衝區),而後再從緩衝區逐個地將數據送到程序數據區(給程序變量) 。
10.8.2磁盤文件的存取
l 磁盤文件,通常保存在硬盤、U盤等掉電不丟失的磁盤設備中,在須要時調入內存
l 在內存中對文件進行編輯處理後,保存到磁盤中
l 程序與磁盤之間交互,不是當即完成,系統或程序可根據須要設置緩衝區,以提升存取效率
10.8.3更新緩衝區
#include <stdio.h>
intfflush(FILE *stream);
功能:更新緩衝區,讓緩衝區的數據立馬寫到文件中。
參數:
stream:文件指針
返回值:
成功:0
失敗:-1