流文件操作(打開、讀、寫、關閉)
概述
1、流式文件:在C語言中對文件的記錄是以字符(字節)爲單位的。輸入輸出的數據流的開始和結束僅受程序控制而不受物理符號(如回車換行符)控制。也就是說,在輸出時不以回車換行符作爲記錄的間隔(事實上C文件並不由記錄構成)。我們把這種文件稱爲流式文件。
2、磁盤文件:在程序運行時,常常需要將一些數據(運行的最終結果或中間數據)輸出到磁盤上存放起來,以後需要時再從磁盤中輸入到計算機內存。
3、C文件本質:C語言將文件看作是一個字符(字節)的序列,即一個一個字符(字節)的數據順序組成。
- 根據數據的組成形式,可分爲ASCII文件和二進制文件。ASCII文件又稱文本(text)文件,它的每一個字節可放一個ASCII碼,代表一個字符。二進制文件是把內存中的數據按其在內存中的存儲形式按原樣輸出到磁盤上存放。
- 用ASCII碼形式輸出的數據是與字符一一對應的,一個字節代表一個字符,因而便於對字符進行逐個處理,也便於輸出字符。但一般佔存儲空間較多,而且要花費轉換時間(二進制形式與ASCII碼間的轉換)。用二進制形式輸出數值,可以節約外存空間和轉換時間,但一個字節並不對應一個字符,不能直接輸出字符形式。
- 把一個文本文件讀入內存時,要將ASCII碼轉換成二進制碼, 而把文件以文本方式寫入磁盤時,也要把二進制碼轉換成ASCII碼,因此文本文件的讀寫要花費較多的轉換時間。對二進制文件的讀寫不存在這種轉換。
- 例如:有一個整數12345(十進制),在內存中佔2個字節(無符號:0~65535)。如果按ASCII碼形式輸出,則佔5個字節(由高到低:第一個字符1的ASCII值49,二進制表示爲0011_0001;第二個字符0的ASCII值50,二進制表示爲0011_0010;同理後三個字符)。而按二進制形式輸出,在磁盤上只佔2個字節(12345的二進制0011_0000_0011_1001)。
範例
1、打開和關閉一個文件常用方法:fopen函數和fclose函數
FILE* fp;
if((fp = fopen("file.txt", "w+")) == NULL)
{
printf("can not open the file\n");
exit(0);
}
fclose(fp);
表示打開一個file.txt的文件;使用文件方式爲w+(讀/寫/可新建,可按需要選擇文件使用方式);若不能實現打開/新建的任務,此時fopen函數將會帶回一個空指針NULL,NULL在頭文件中已被定義爲0;對於輸出流,fclose函數會在文件關閉前刷新緩衝區,如果它執行成功,fclose返回值爲0,否則返回EOF(-1)。
2、文件的讀寫
C++提供了低級的I/O功能和高級的l/O功能:
- 高級的I/O功能是把若干個字節組合爲一個有意義的單位(如整數、單精度數、雙精度數、字符串或用戶自定義的類型的數據),然後以ASCII字符形式輸人和輸出。例如將數據從內存送到顯示器輸出,就屬於高級I/O功能,先將內存中的數據轉換爲ASCII字符,然後分別按整數、單精度數、雙精度數等形式輸出。這種面向類型的輸入輸出在程序中用得很普遍,用戶感到方便。但在傳輸大容量的文件時由於數據格式轉換,速度較慢,效率不高。
- 所謂低級的I/O功能是以字節爲單位輸入和輸出的,在輸人和輸出時不進行數據格式的轉換。這種輸入輸出是以二進制形式進行的。通常用來在內存和設備之間傳輸一批字節。這種輸入輸出速度快、效率高,一般大容量的文件傳輸用無格式轉換的I/0。但使用時會感到不大方便。
例:將一個文本文件中的內容寫入到一個新的文本文件中。
#include "stdio.h"
#include "stdlib.h"
void main()
{
FILE* fp_r;
if((fp_r = fopen("file_r.txt", "r")) == NULL)
{
printf("can not open the file_r\n");
exit(0);
}
FILE* fp_w;
if((fp_w = fopen("file_w.txt", "w")) == NULL)
{
printf("can not open the file_w\n");
exit(0);
}
int file_size = 0;
unsigned char ch[1] = {0};
fseek(fp_r,0L,SEEK_END);
file_size = ftell(fp_r);
rewind(fp_r);
while(ftell(fp_r) != file_size) //判斷是否讀到文末
{
ch[0] = fgetc(fp_r);// int fgetc(FILE *stream) 讀一個字節
fputc(ch[0],fp_w);// int fputc(int char, FILE *stream) 寫一個字節
// fread(ch,1,1,fp_r); // fread(buffer,size,count,fp)
// fwrite(ch,1,1,fp_w); // fwrite(buffer,size,count,fp)
// fscanf(fp_r,"%c",&ch[0]); // fscanf(文件指針,格式字符串,輸入列表)
// fprintf(fp_w,"%c",ch[0]); // fprintf(文件指針,格式字符串,輸出列表)
}
fclose(fp_r);
fclose(fp_w);
}
特殊符號輸出,以putc爲例:
putc('a',fp_w); 輸出字符a
putc(' ',fp_w); 輸出空格
putc('\n',fp_w); 輸出換行符
putc(10,fp_w); 輸出換行符
注:
- fseek() 一般用於二進制文件,因爲文本文件要發生字符轉換,計算的位置時往往會發生混亂。
- C/C++中對文件的操作分以二進制文件方式讀寫和以文本文件方式讀寫兩種,二者唯一的區別就在於對換行符的處理上 。
詳解連接
判斷是否讀到文末的三種方法
1、ch = feof(fp):返回值ch爲所讀取的一個字節,如果讀到文件末尾或者讀取出錯時返回EOF
ch = fgetc(fp); // 先讀在判斷
while(!feof(fp)) // or while(EOF != ch)
{
//TODO;
printf("%x",ch);
c=fgetc(fp);
}
2、buf = fread(ptr, 1, 2, fp):返回值buf爲所讀取到的字節個數
buf = fread(ptr, 1, 2, fp); // 先讀在判斷
while(buf != 0)
{
//TODO;
printf("%d",buf);
buf = fread(ptr, 1, 2, fp);
}
3、fseek、ftell和rewind:判斷讀取文件大小
fseek(fp,0L,SEEK_END);
file_size = ftell(fp);
rewind(fp);
while(ftell(fp) != file_size)
{
//TODO;
}