目錄
- 1.流
- 1.1 流的概念
- 1.2 常見的的流
- 2.文件的打開和關閉
- 2.1 fopen函數
- 2.2 fclose函數
- 2.3 文件的打開和關閉
- 3.文件的輸入輸出函數
- 3.1 fputc函數
- 3.2 fgetc函數
- 3.3 feof函數和ferror函數
- 3.4 fputs函數
- 3.5 fgets函數
- 3.6 fwrite函數
- 3.7 fread函數
- 3.8 fprintf函數
- 3.9 fscanf函數
- 4 sprintf和sprintf函數
- 5. fseek函數
- 6. ftell函數和rewind函數
- 7.fflush函數
1.流
1.1 流的概念
外部設備需要從內存中寫入數據進行輸出,而內存需要從外部設備讀取數據進行輸入,為了方便外部設備與內存數據的輸入輸出,需要借助流幫助數據的寫入與讀取。
常見的外部設備有:屏幕,文件,硬盤,畫面等。
1.2 常見的的流
stdin:標準輸入流,從外部設備上讀取數據,scanf函數就是從標準輸入流(鍵盤)獲取數據的;
stdout:標準輸出流,從內存獲取數據,將數據輸出或寫入在外部設備上,printf函數就是標準的輸出流函數;
stderr:標準錯誤流,將錯誤信息輸出到屏幕上;
對于文件而言,以上三種流的類型是FILE*,即文件流。
2.文件的打開和關閉
2.1 fopen函數
fopen函數的功能是將一個文件打開,并返回該文件的起始地址,類型是FILE*,第一個參數是文件路勁,第二個參數是以什么方式打開文件;
常見的文件打開方式如下
2.2 fclose函數
fclose函數的作用是打開的文件進行關閉操作,參數是需要關閉參數的起始地址,如果文件成功關閉返回0,如果關閉失敗,返回EOF(-1)。
使用fclose函數成功關閉文件時,需要即時將指針置空指針,防止野指針的使用,導致程序奔潰。
2.3 文件的打開和關閉
#include<stdio.h>//文件
int main()
{//打開text.txt的文件,以寫入的方式FILE* pf = fopen("test.txt", "w");//判斷方式打開成功if (pf == NULL){//輸出錯誤從原因perror("fopen");//終止程序return 1;}//使用//......//......//關閉文件,置空指針fclose(pf);pf = NULL;return 0;
}
當程序運行成功后,沒有創建文件會默認創建以test.txt為路勁的文件。
3.文件的輸入輸出函數
3.1 fputc函數
fputc函數的功能是將指定字符通過文件輸出流寫入到指定的文件中,第一個參數是字符的ASCII碼值,第二個參數文件的起始位置的指針。
如果返回成功寫入,返回這個寫入字符的ASCII碼值,如果失敗,就返回EOF(-1),并在輸出流上設置錯誤信息,可以使用ferror函數輸出錯誤信息。
fputc的使用
#include<stdio.h>//文件
int main()
{//打開text.txt的文件,以寫入的方式FILE* pf = fopen("test.txt", "w");//判斷方式打開成功if (pf == NULL){//輸出錯誤從原因perror("fopen");//終止程序return 1;}//fputc使用//將a - z的字符輸出寫入到test.txt文件中int i = 0;for (i = 'a'; i <= 'z'; i++){putc(i, pf);}//關閉文件,置空指針fclose(pf);pf = NULL;return 0;
}
打開此時的test.txt文件:可以觀察到a - z字符的內容已經輸出寫入到此文件中。
3.2 fgetc函數
fgetc函數的功能是從文件輸入流中讀取數據到內存中,參數為讀取文件的起始地址。
如果讀取成功,返回讀取字符的ASCII碼值,如果沒有讀取到有效內容,返回EOF(-1);分為兩種情況:第一種是遇到文件末尾,在文件末尾設置指示器,可以通過feof函數檢測;第二種情況是讀取中途讀取失敗,會在讀取失敗的位置設置指示器,可以通過ferror函數檢測。
fgetc函數的使用:讀取上面的test.txt文件
#include<stdio.h>//文件
int main()
{//打開text.txt的文件,以讀取的方式FILE* pf = fopen("test.txt", "r");//判斷方式打開成功if (pf == NULL){//輸出錯誤從原因perror("fopen");//終止程序return 1;}//fgetc使用//將test.txt文件中的a - z 字符讀取int i = 0;for (i = 'a'; i <= 'z'; i++){printf("%c ",getc(pf));}//關閉文件,置空指針fclose(pf);pf = NULL;return 0;
}
3.3 feof函數和ferror函數
ferror函數是檢測是否文件在讀取或者寫入的過程有失敗的情況,可以通過指示器檢測,如果檢測到指示器,就返回非0值,如果沒有檢測到返回0值;
feof函數的功能是檢測文件是否讀取到末尾;通過指示器可以檢測,如果檢測到指示器,返回非0值,沒有檢測到指示器返回0;
feof和feeor的使用
int main()
{//打開text.txt的文件,以讀取的方式FILE* pf = fopen("test.txt", "r");//判斷方式打開成功if (pf == NULL){//輸出錯誤從原因perror("fopen");//終止程序return 1;}//以讀的形式打開需要輸入函數讀取//使用輸出函數會導致讀取失敗//使用ferror函數和feof函數觀察int r = fputc('a', pf);if (r == EOF)//讀取失敗的返回值{//1.判斷是否讀取到文件末尾if (feof(pf) != 0){printf("讀取到文件末尾,返回EOF\n");}//2.判斷是否在文件中途讀取失敗else if (ferror(pf) != 0){printf("文件在中途讀取失敗,返回EOF\n");}}//關閉文件,置空指針fclose(pf);pf = NULL;return 0;
}
如果將test.txt的內容刪除后保存(a -z 的數據刪除后CTRL + S 保存),使用以上程序的輸出結果如下
3.4 fputs函數
fupus函數的功能是將內存的數據通過文件輸出流中寫入到文件中;第一個參數是一個不可被修改的字符串的起始地址,第二個參數是文件流的起始地址,返回類型是int。
如果寫入成功返回非0值,如果寫入失敗,設置指示器,可以同ferror函數檢測,并返回EOF(-1)。
fputs函數的使用:1.將字符串寫入文件;2.將字符串輸出到屏幕(控制臺);
#include<stdio.h>
#include<stdlib.h>int main()
{FILE* pf = fopen("test.txt", "w");if (pf == NULL){perror("fopen");return 1;}//寫入//1.寫入到文件fputs("Hello", pf);//2.輸出到屏幕,stdout是標準輸出流fputs("World", stdout);//關閉fclose(pf);pf = NULL;return 0;
}
寫入到test.txt文件中的數據
輸出到控制臺的數據
3.5 fgets函數
fgets函數是從文件中讀取數據通過文件輸入流鍵將數據存儲到內存中;第一個參數是讀取字符串的起始地址,第二個參數是讀取的字符個數,第三個參數是文件流的起始地址,返回類型是char*。
如果讀取成功,返回讀取的字符串起始地址;在讀取字符時遇到文件末尾會設置文件指示器,可以通過feof函數檢測,在可讀取的字符數據全部讀取完成前遇到這個指示器,會返回空指針(NULL);如果讀取的字符發生錯誤,會設置錯誤指示器,可以通過ferror函數檢測,并返回空指針(NULL)。
fgets函數的使用:1.從文件讀取;2.從外部設備讀取(鍵盤)
#include<stdio.h>
#include<stdlib.h>int main()
{FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return 1;}char ch[12] = "************";//寫入//1.讀取文件信息到數組中fgets(ch,6,pf);//2.從鍵盤讀取數據,存儲到數組中//stdin是標準輸入流fgets(ch + 5,7, stdin);puts(ch);//輸出//關閉fclose(pf);pf = NULL;return 0;
}
按F10啟動調試,打開調試監視窗口,輸出ch觀察數組的內容:執行ch的初始化語句
此時的text.txt文件存放的是Hello,只有5個字符,需要讀取6個字符的數組,fgets函數會在末尾存放一個\0。
第二條fgets函數是從鍵盤讀取數據,輸入“ World",用空格替換’\0’的位置,后續補上World,末尾再添加一個\0。
最后通過puts函數輸出數組ch的內容,將pf指向的文件關閉并置為空指針。
3.6 fwrite函數
fwrite函數是從內存獲取的數據通過文件輸出流以二進制是形式寫入到文件中;第一個參數是寫入數據的起始地址,第二個參數是元素的大小,第三個參數是個數,第四個參數是文件起始地址,返回類型是size_t.
返回值是成功寫入的元素個數;如果最終讀取的個數與參數的個數不一樣有以下兩種情況:如果返回值是0,發生寫入失敗,會設置錯誤指示器,可以通過ferror函數檢測;第二種情況返回非0值,會設置文件寫入結束的指示器,可以通過feof函數檢測。
fwrite函數的使用
//fwrite
#include<stdio.h>
#include<stdlib.h>int main()
{//二進制寫入的形式打開文件FILE* pf = fopen("test.txt", "wb");if (pf == NULL){perror("fopen");return 1;}int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };//使用:將arr數組的十個元素寫入到文件中 fwrite(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf);//關閉fclose(pf);pf = NULL;return 0;
}
程序成功運行后,使用fwrite函數會將上一次寫入的數據進行刪除,后進行覆蓋,以二進制的形式寫入
3.7 fread函數
fread函數的功能是從文件中讀取數據通過文件輸入流以二進制形式輸入到內存中;第一個參數數據存放位置的起始地址,第二個參數是元素的大小,第三個參數是讀取的個數,第四個參數是讀取數據的文件起始地址,返回類型是size_t。
如果讀取成功,返回值是成功讀取的個數;如果讀取的個數與參數不一樣有以下兩種情況:如果返回值是0,發生寫入失敗,會設置錯誤指示器,可以通過ferror函數檢測;第二種情況返回非0值,會設置文件寫入結束的指示器,可以通過feof函數檢測。
fread函數的使用:以上述的text,txt文件為例。
#include<stdio.h>
#include<stdlib.h>int main()
{//二進制讀取的形式打開文件FILE* pf = fopen("test.txt", "rb");if (pf == NULL){perror("fopen");return 1;}int arr[10] = {0};//使用:將pf的數據讀取后存放于arr數組中. fread(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf);//輸出arrfor (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", arr[i]);}//關閉fclose(pf);pf = NULL;return 0;
}
將鼠標移向源文件窗口,點擊右鍵打開添加中的現有項,點擊text.txt文件,添加到源文件中。
點擊test.txt文件,點擊鼠標右鍵選擇打開方式,選擇以二進制方式打開。
可以觀察到執行以上程序后arr數組讀取數據的內容:1 - 10(十六進制的形式,小端存儲)
3.8 fprintf函數
fprinf函數是將內存的數據通過文件輸出流以指定格式的數據寫入到文件中;第一個參數是文件流,第二個參數是數據的格式,第三個參數是對于的變量,返回類型是int。
如果寫入成功返回寫入的個數;如果寫入過程出現錯誤,設置錯誤信息的指示器,并返回一個負數;如果在寫入寬字符時出現多個錯誤,會將錯誤碼(errno)實在為EILSEQ,并返回一個負數。
fprintf函數的使用
#include<stdio.h>
#include<stdlib.h>
#pragma warning(disable:4996)struct Stu
{char name[20];int age;char id[8];
}s = { "James",21,"22334455" };int main()
{//以寫入的形式打開文件FILE* pf = fopen("test.txt", "w");if (pf == NULL){perror("fopen");return 1;}//使用:將結構體按照指定格式寫入文件中fprintf(pf, "%s %d %s", s.name, s.age, s.id);struct Stu s1;//關閉fclose(pf);pf = NULL;return 0;
}
程序運行后的text.txt的信息
3.9 fscanf函數
fscanf函數的功能是從文件中讀取的數據通過文件輸入流將數據輸入到內存中;第一個參數是讀取數據的文件起始地址,第二個參數是按照指定格式讀取數據,第三個參數是將數據存儲位置的地址,返回類型是int.
如果成功讀取,返回成功讀取的個數;如果在全部數據讀取完成前發生讀取錯誤或讀取到文件末尾,返回EOF(-1),分別通過ferror函數和feof函數檢測。
fscanf函數的使用:以上述的text.txt文件的數據讀取.
#include<stdio.h>
#include<stdlib.h>
#pragma warning(disable:4996)struct Stu
{char name[20];int age;char id[8];
}s1 ;
int main()
{//以讀取的形式打開文件FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return 1;}//使用:將文件的數據按照指定格式存放于變量s1fscanf(pf, "%s%d%s", &s1.name, &s1.age, &s1.id);//按照格式輸出printf("name: %s\nage: %d\nid: %s", s1.name, s1.age, s1.id);//關閉fclose(pf);pf = NULL;return 0;
}
輸出從文件中按照指定格式的數據
4 sprintf和sprintf函數
sprintf函數的功能是將格式化的數據寫入到字符串中;第一個參數是字符串的起始地址,第二個參數是指定格式,第三個參數是指定成員。
如果輸出成功,返回成功輸出的個數,如果輸出失敗返回一個負數。
sscanf函數的功能是從字符串中按照格式化的方式讀取數據;第一個參數是字符串的起始地址,第二個參數是指定格式,第三個參數是變量的地址。
如果轉換成功返回的是格式列表的項數(與scanf函數的返回值一樣,例如:”%s %d“的格式讀取成功返回2 ),如果讀取失敗返回-1.
sscanf和sprintf的使用
#include <stdio.h>
#include<stdlib.h>
#pragma warning(disable:4996)
struct Stu
{char name[30];int age;float score;
};
int main()
{struct Stu s = { "zhangsan", 100, 85.5f };//將s中的結構數據轉換成?個字符串char arr[100] = { 0 };sprintf(arr, "%s %d %.1f", s.name, s.age, s.score);printf("%s\n", arr);//將字符串按照格式輸出struct Stu s1;sscanf(arr, "%s %d %f", s1.name, &s1.age, &s1.score);printf("%s %d %.1f", s1.name, s1.age, s1.score);return 0;
}
輸出內容
scanf,printf,fscanf,fprintf,sscanf,sprintf的作用如下
5. fseek函數
fseek可以設置光標位置,使文件從此光標位置開始讀取;第一個參數是文件起始位置的地址,第二個參數是偏移量的大小,第三個參數是光標的起始位置,返回類型為int.
第三個參數的取值可以是以上三種,SEEK_SET(起始位置),SEEK_CUR(當前光標的位置),SEEK_END(文件末尾)。
如果成功設置光標位置,返回0,如果設置失敗,返回非0值并設置錯誤指示器(ferror)。
fseek的使用:將text.txt的內容先輸入abcdef后保存。
#include<stdio.h>
int main()
{FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return 1;}//fseek函數使用//開始光標位置在0偏移處,將光標設置在1偏移量位置fseek(pf, 1, SEEK_SET);//指向字符a后面的位置int c = fgetc(pf);//讀取到b字符,光標移向b后面的位置printf("%c", c);//輸出字符b//將光標設置在當前位置的后1偏移量位置fseek(pf, 1, SEEK_CUR);//指向b后面的位置c = fgetc(pf);//讀取到字符c,光標指向c后面位置printf("%c", c);//輸出c//將光標設置在文件末尾的前1偏移量位置fseek(pf, -1,SEEK_END);c = fgetc(pf);//讀取到字符f,光標指向字符f后面printf("%c", c);//輸出f//關閉fclose(pf);pf = NULL;return 0;
}
6. ftell函數和rewind函數
ftell函數是將當前光標的位置與起始位置的偏移量值返回,如果未能讀取返回-1L(double);
rewind函數是將光標設置為起始位置,參數是文件指針,沒有返回值。
/* ftell and rewind example : getting size of a file */
#include <stdio.h>int main()
{FILE* pf = fopen("test.txt", "r");//文件內容:abcdefif (pf == NULL) perror("Error opening file");else{fseek(pf, 0, SEEK_END); // non-portablelong size = ftell(pf);printf("Size of test.txt.txt: %ld bytes.\n", size);//重新設置光標位置rewind(pf);printf("%c", fgetc(pf));//關閉文件,設置空指針fclose(pf);pf = NULL;}return 0;
}
7.fflush函數
fflush是將文件緩沖區的數據進行刷新,對于文件輸入流的數據,終止讀取,對于文件輸出流的數據進行寫入,函數的參數是文件指針,返回類型是int。
成功刷新緩沖區返回0值,刷新失敗返回-1,并設置錯誤指示器。
fflush的使用
/* fflush example */
#pragma warning(disable:4996)
#include <stdio.h>
#include<windows.h>
char mybuffer[80];
int main()
{char mybuffer[10];FILE* pf = fopen("test.txt", "r+");if (pf == NULL){perror("fopen");//輸出錯誤信息return 1;//終止程序}fputs("abcdef", pf);printf("數據正在存儲在緩沖區中....\n");Sleep(5000);//休眠5秒fflush(pf); // flushing or repositioning requiredprintf("緩沖區已經刷新,數據寫入中...\n");rewind(pf);//將光標設置在起始文件指針的位置fgets(mybuffer, 10, pf);//獲取信息puts(mybuffer);//輸出//關閉文件,置空指針fclose(pf);pf = NULL;return 0;
}
程序運行中還未刷新緩沖區數據,文件的內容是空的。
刷新后,abcdef寫入文件中。