在C語言中用一個指針變量指向一個文件,這個指針稱爲文件指針。linux
typedef struct { short level; //緩衝區"滿"或者"空"的程度 unsigned flags; //文件狀態標誌 char fd; //文件描述符 unsigned char hold; //如無緩衝區不讀取字符 short bsize; //緩衝區的大小 unsigned char *buffer;//數據緩衝區的位置 unsigned ar; //指針,當前的指向 unsigned istemp; //臨時文件,指示器 short token; //用於有效性的檢查 }FILE;
FILE是系統使用typedef定義出來的有關文件信息的一種結構體類型,結構中含有文件名、文件狀態和文件當前位置等信息。web
聲明FILE結構體類型的信息包含在頭文件「stdio.h」中,通常設置一個指向FILE類型變量的指針變量,而後經過它來引用這些FILE類型變量。經過文件指針就可對它所指的文件進行各類操做。
windows
C語言中有三個特殊的文件指針由系統默認打開,用戶無需定義便可直接使用:svg
10.2.2 文件的打開
任何文件使用以前必須打開:函數
#include <stdio.h> FILE * fopen(const char * filename, const char * mode); 功能:打開文件 參數: filename:須要打開的文件名,根據須要加上路徑 mode:打開文件的模式設置 返回值: 成功:文件指針 失敗:NULL
第一個參數的幾種形式:ui
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");
第二個參數的幾種形式(打開文件的方式):this
打開模式 | 含義 |
---|---|
r或rb | 以只讀方式打開一個文本文件(不建立文件,若文件不存在則報錯) |
w或wb | 以寫方式打開文件(若是文件存在則清空文件,文件不存在則建立一個文件) |
a或ab | 以追加方式打開文件,在末尾添加內容,若文件不存在則建立文件 |
r+或rb+ | 以可讀、可寫的方式打開文件(不建立新文件) |
w+或wb+ | 以可讀、可寫的方式打開文件(若是文件存在則清空文件,文件不存在則建立一個文件) |
a+或ab+ | 以添加方式打開文件,打開文件並在末尾更改文件,若文件不存在則建立文件 |
注意:spa
int main(void) { FILE *fp = NULL; // "\\"這樣的路徑形式,只能在windows使用 // "/"這樣的路徑形式,windows和linux平臺下均可用,建議使用這種 // 路徑能夠是相對路徑,也但是絕對路徑 fp = fopen("../test", "w"); //fp = fopen("..\\test", "w"); if (fp == NULL) //返回空,說明打開失敗 { //perror()是標準出錯打印函數,能打印調用庫函數出錯緣由 perror("open"); return -1; } return 0; }
任何文件在使用後應該關閉:操作系統
#include <stdio.h> int fclose(FILE * stream); 功能:關閉先前fopen()打開的文件。此動做讓緩衝區的數據寫入文件中,並釋放系統所提供的文件資源。 參數: stream:文件指針 返回值: 成功:0 失敗:-1
FILE * fp = NULL; fp = fopen("abc.txt", "r"); fclose(fp);
1)寫文件指針
#include <stdio.h> int fputc(int ch, FILE * stream); 功能:將ch轉換爲unsigned char後寫入stream指定的文件中 參數: ch:須要寫入文件的字符 stream:文件指針 返回值: 成功:成功寫入文件的字符 失敗:返回-1
char buf[] = "this is a test for fputc"; int i = 0; int n = strlen(buf); for (i = 0; i < n; i++) { //往文件fp寫入字符buf[i] int ch = fputc(buf[i], fp); printf("ch = %c\n", ch); }
2)文件結尾
在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:沒有到文件結尾
3)讀文件
#include <stdio.h> int fgetc(FILE * stream); 功能:從stream指定的文件中讀取一個字符 參數: stream:文件指針 返回值: 成功:返回讀取到的字符 失敗:-1
char ch; #if 0 while ((ch = fgetc(fp)) != EOF) { printf("%c", ch); } printf("\n"); #endif while (!feof(fp)) //文件沒有結束,則執行循環 { ch = fgetc(fp); printf("%c", ch); } printf("\n");
1)寫文件
#include <stdio.h> int fputs(const char * str, FILE * stream); 功能:將str所指定的字符串寫入到stream指定的文件中,字符串結束符 '\0' 不寫入文件。 參數: str:字符串 stream:文件指針 返回值: 成功:0 失敗:-1
char *buf[] = { "123456\n", "bbbbbbbbbb\n", "ccccccccccc\n" }; int i = 0; int n = 3; for (i = 0; i < n; i++) { int len = fputs(buf[i], fp); printf("len = %d\n", len); }
2)讀文件
#include <stdio.h> char * fgets(char * str, int size, FILE * stream); 功能:從stream指定的文件內讀入字符,保存到str所指定的內存空間,直到出現換行字符、讀到文件結尾或是已讀了size - 1個字符爲止,最後會自動加上字符 '\0' 做爲字符串結束。 參數: str:字符串 size:指定最大讀取字符串的長度(size - 1) stream:文件指針 返回值: 成功:成功讀取的字符串 讀到文件尾或出錯: NULL
char buf[100] = 0; while (!feof(fp)) //文件沒有結束 { memset(buf, 0, sizeof(buf)); char *p = fgets(buf, sizeof(buf), fp); if (p != NULL) { printf("buf = %s", buf); } }
1)寫文件
#include <stdio.h> int fprintf(FILE * stream, const char * format, ...); 功能:根據參數format字符串來轉換並格式化數據,而後將結果輸出到stream指定的文件中,指定出現字符串結束符 '\0' 爲止。 參數: stream:已經打開的文件 format:字符串格式,用法和printf()同樣 返回值: 成功:實際寫入文件的字符個數 失敗:-1 fprintf(fp, "%d %d %d\n", 1, 2, 3);
2)讀文件
#include <stdio.h> int fscanf(FILE * stream, const char * 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);
1)寫文件
#include <stdio.h> size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); 功能:以數據塊的方式給文件寫入內容 參數: ptr:準備寫入文件數據的地址 size: size_t 爲 unsigned int類型,此參數指定寫入文件內容的塊數據大小 nmemb:寫入文件的塊數,寫入文件數據總大小爲:size * nmemb stream:已經打開的文件指針 返回值: 成功:實際成功寫入文件數據的塊數目,此值和nmemb相等 失敗:0
typedef struct Stu { char name[50]; int id; }Stu; Stu s[3]; int i = 0; for (i = 0; i < 3; i++) { sprintf(s[i].name, "stu%d%d%d", i, i, i); s[i].id = i + 1; } int ret = fwrite(s, sizeof(Stu), 3, fp); printf("ret = %d\n", ret);
2)讀文件
#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
typedef struct Stu { char name[50]; int id; }Stu; Stu s[3]; int ret = fread(s, sizeof(Stu), 3, fp); printf("ret = %d\n", ret); int i = 0; for (i = 0; i < 3; i++) { printf("s = %s, %d\n", s[i].name, s[i].id); }
#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:已經打開的文件指針 返回值: 無返回值
typedef struct Stu { char name[50]; int id; }Stu; //假如已經往文件寫入3個結構體 //fwrite(s, sizeof(Stu), 3, fp); Stu s[3]; Stu tmp; int ret = 0; //文件光標讀寫位置從開頭往右移動2個結構體的位置 fseek(fp, 2 * sizeof(Stu), SEEK_SET); //讀第3個結構體 ret = fread(&tmp, sizeof(Stu), 1, fp); if (ret == 1) { printf("[tmp]%s, %d\n", tmp.name, tmp.id); } //把文件光標移動到文件開頭 //fseek(fp, 0, SEEK_SET); rewind(fp); ret = fread(s, sizeof(Stu), 3, fp); printf("ret = %d\n", ret); int i = 0; for (i = 0; i < 3; i++) { printf("s === %s, %d\n", s[i].name, s[i].id); }
判斷文本文件是Linux格式仍是Windows格式:
#include<stdio.h> int main(int argc, char **args) { if (argc < 2) return 0; FILE *p = fopen(args[1], "rb"); if (!p) return 0; char a[1024] = { 0 }; fgets(a, sizeof(a), p); int len = 0; while (a[len]) { if (a[len] == '\n') { if (a[len - 1] == '\r') { printf("windows file\n"); } else { printf("linux file\n"); } } len++; } fclose(p); return 0; }
#include <sys/types.h> #include <sys/stat.h> int stat(const char *path, struct stat *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; //最後一次改變時間(指屬性) };
#include <sys/types.h> #include <sys/stat.h> #include <stdio.h> int main(int argc, char **args) { if (argc < 2) return 0; struct stat st = { 0 }; stat(args[1], &st); int size = st.st_size;//獲得結構體中的成員變量 printf("%d\n", size); return 0; }
#include <stdio.h> int remove(const char *pathname); 功能:刪除文件 參數: pathname:文件名 返回值: 成功:0 失敗:-1 #include <stdio.h> int rename(const char *oldpath, const char *newpath); 功能:把oldpath的文件名改成newpath 參數: oldpath:舊文件名 newpath:新文件名 返回值: 成功:0 失敗: - 1
ANSI C標準採用「緩衝文件系統」處理數據文件。
所謂緩衝文件系統是指系統自動地在內存區爲程序中每個正在使用的文件開闢一個文件緩衝區從內存向磁盤輸出數據必須先送到內存中的緩衝區,裝滿緩衝區後才一塊兒送到磁盤去。
若是從磁盤向計算機讀入數據,則一次從磁盤文件將一批數據輸入到內存緩衝區(充滿緩衝區),而後再從緩衝區逐個地將數據送到程序數據區(給程序變量) 。
#include <stdio.h> int fflush(FILE *stream); 功能:更新緩衝區,讓緩衝區的數據立馬寫到文件中。 參數: stream:文件指針 返回值: 成功:0 失敗:-1