以下內容爲本人看“傳智播客”C++基礎教程完整版視頻所做的筆記
文件的基本概念
按文件的邏輯結構:
- 記錄文件:由具有一定結構的記錄組成(定長和不定長)
- 流式文件:由一個個字符(字節)數據順序組成
按存儲介質:
- 普通文件:存儲介質文件(磁盤、磁帶等)
- 設備文件:非存儲介質(鍵盤、顯示器、打印機等)
按數據的組織形式:
- 文本文件: ASCII文件,每個字節存放一個字符的ASCII碼
- 二進制文件:數據按其在內存中的存儲形式原樣存放
寫文件
int main()
{
errno_t err;
char buf[] = "this is a test\n";
FILE *fp;
err = fopen_s(&fp, "./test.txt", "w+");
//"w+",寫讀方式打開,如果文件不存在,則創建;如果文件存在,清空內容,再寫
fputs(buf, fp);
printf("\n");
system("pause");
return 0;
}
在以下路徑中生成文件“test.txt”
流概念
流是一個動態的概念,可以將一個字節形象地比喻成一滴水,字節在設備、文件和程序之間的傳輸就是流,類似於水在管道中的傳輸,可以看出,流是對輸入輸出源的一種抽象,也是對傳輸信息的一種抽象。通過對輸入輸出源的抽象,屏蔽了設備之間的差異,使程序員能以一種通用的方式進行存儲操作,通過對傳輸信息的抽象,使得所有信息都轉化爲字節流的形式傳輸,信息解讀的過程與傳輸過程分離。
C語言中,I/O操作可以簡單地看作是從程序移進或移出字節,這種搬運的過程便稱爲流(stream)。程序只需要關心是否正確地輸出了字節數據,以及是否正確地輸入了要讀取字節數據,特定I/O設備的細節對程序員是隱藏的。
文件處理方法
- 緩衝文件系統:高級文件系統,系統自動爲正在使用的文件開闢內存緩衝區
- 非緩衝文件系統:低級文件系統,由用戶在程序中爲每個文件設定緩衝區
文件句柄(實際上就是一個結構體變量)
typedef struct
{
short level; //緩衝區“滿”或者“空”的程度
unsigned flags; //文件狀態標識
char fd; //文件描述符
unsigned char hold; //如無緩衝區不讀取字符
short bsize; //緩衝區的大小
unsigned char *buffer; //數據緩衝區的位置
unsigned ar; //指針,當前的指向
unsigned istemp; //臨時文件,指示器
short token; //用於有效性的檢查
}FILE;
文件操作API
fgetc fputc 按照字符讀寫文件
fputs fgets 按照行讀寫文件 (讀寫配置文件)
fread fwirte 按照塊讀寫文件 (大數據塊遷移)
fprintf fscanf 按照格式化進行讀寫文件
char ch;
ch=fgetc(stdin); //std -> 鍵盤
fputc(ch, stdout); //stdout->屏幕
fputc(ch,stderr); //stderr ->屏幕,錯誤信息
絕對路徑和相對路勁的區別
絕對路徑指的是:C:\Users\apple\Documents\C提高視頻\03.txt【針對windows平臺】
相對路徑指的是:/,45度, ./, ../(建議)【針對linux和windows平臺】
VS:編譯代碼時,相對於項目工程
直接運行可執行程序,相對於程序
int main()
{
//用相對路徑來讀取文件時,一定要將文件與可執行程序放在一個文件夾中
errno_t err;
FILE *fp = NULL;
err = fopen_s(&fp,"./03.txt", "r+");
if (fp == NULL)
{
perror("fopen");
system("pause");
return -1;
}
printf("\n");
system("pause");
return 0;
}
下面舉一個例子,以相對路徑創建一個文件,並用fputc函數將字符串寫入文件中:
void my_fputs(char *path)
{
errno_t err;
FILE *fp = NULL;
err = fopen_s(&fp, path, "w+");
if (fp == NULL)
{
perror("my_fputs fopen");
return;
}
//寫文件
char buf[] = "this is a test for fputs";
int n = strlen(buf);
int i = 0;
for (i = 0; i < n; i++)
{
//fputc的返回值是成功寫入文件的字符
int ch = fputc(buf[i], fp);
printf("ch = %c\n", ch);
}
if (fp != NULL)
{
fclose(fp);
fp = NULL;
}
}
int main()
{
my_fputs("../03.txt");//文件的存放方式是以相對路徑存放的
printf("\n");
system("pause");
return 0;
}
剛剛寫文件自己編了一個my_fputs函數來實現,現在要實現讀文件,再編一個my_fgets函數來實現,代碼如下:
void my_fgets(char *path)
{
FILE *fp = NULL;
errno_t err;
err = fopen_s(&fp, path, "r+");
if (fp == NULL)
{
perror("my_fgets fopen");
return;
}
char ch;
while(ch = fgetc(fp) != EOF)
{
printf("%c",ch);
}
printf("\n");
if(fp != NULL)
{
fclose(fp);
fp = NULL;
}
}
最後在main函數中調用my_fgets(“../03.txt”);就可以實現在顯示屏上打印出“03.txt”文件中的字符串。
按照塊讀寫文件
#define _CRT_SECURE_NO_WARNINGS
#include "stdafx.h"
typedef struct
{
char name[50];
int id;
}Stu;
void my_fwrite(char *path)
{
errno_t err;
FILE *fp = NULL;
err = fopen_s(&fp, path, "w+");
if (fp == NULL)
{
perror("my_fputs fopen");
return;
}
Stu s[3];
int i = 0;
char buf[50];
for (i = 0; i < 3; i++)
{
sprintf_s(buf, "stu%d%d%d", i, i, i);
strcpy_s(s[i].name, buf);
s[i].id = i + 1;
}
//寫文件
//s,寫入文件內容的內存首地址
//sizeof(Stu):塊數據的大小
//3:寫數據的塊數。那麼寫文件數據的大小就是sizeof(Stu)*3
//fp:文件指針
//返回值ret爲成功寫入文件的塊數目
int ret = fwrite(s, sizeof(Stu),3,fp);
printf("ret = %d\n", ret);
if (fp != NULL)
{
fclose(fp);
fp = NULL;
}
}
void my_fread(char *path)
{
errno_t err;
FILE *fp = NULL;
err = fopen_s(&fp, path, "r+");
if (fp == NULL)
{
perror("my_fputs fopen");
return;
}
Stu s[3];
//讀文件
//s,要讀的文件內容的內存首地址
//sizeof(Stu):塊數據的大小
//3:寫數據的塊數。那麼寫文件數據的大小就是sizeof(Stu)*3
//fp:文件指針
//返回值ret爲成功度取文件的塊數目
int ret = fread(s, sizeof(Stu), 3, fp);
printf("ret = %d\n", ret);
int i = 0;
for (i = 0; i < 3; i++)
{
printf("%s,%d\n", s[i].name, s[i].id);
}
if (fp != NULL)
{
fclose(fp);
fp = NULL;
}
}
int main()
{
my_fwrite("../05.txt");
my_fread("../05.txt");
printf("\n");
system("pause");
return 0;
}
讀寫結果如下:
按照格式化讀寫文件
void my_fprintf(char *path)
{
errno_t err;
FILE *fp = NULL;
err = fopen_s(&fp, path, "w+");
if (fp == NULL)
{
perror("my_fprintf fopen");
return;
}
fprintf(stdout,"hello,today is %d",20171206); //和printf("hello,today is %d",20171206);功能一樣
fprintf(fp,"hello,today is %d",20171206);//寫入文件中了
if (fp != NULL)
{
fclose(fp);
fp = NULL;
}
}
void my_fscanf(char *path)
{
errno_t err;
FILE *fp = NULL;
err = fopen_s(&fp, path, "r+");
if (fp == NULL)
{
perror("my_fscanf fopen");
return;
}
int a =0;
fscanf(fp,"hello,today is %d",&a);
printf("a = %d",a);
if (fp != NULL)
{
fclose(fp);
fp = NULL;
}
}
隨機位置讀文件
int fseek(FILE *stream,long offset,int whence);
//返回值:成功返回0,出錯返回-1並設置errno; offset是偏移量;whence是參考點
long ftell(FILE *stream);
//返回值:成功返回當前讀寫位置,出錯返回-1並設置errno;測光標移動的長度
void rewind(FILE *stream); //將光標恢復到文件最開始的地方
fseek函數中的參數offset和whence共同決定了讀寫位置移動到何處,whence參數的含義如下:
SEEK_SET:
從文件開頭移動offset個字節
SEEK_CUR:
從當前位置移動offst個字節
SEEK_END:
從文件末尾向之前移動-offset個字節