零基礎入門學習C語言012講:文件操作(1)

C文件概述

所謂“文件”是指一組相關數據的有序集合。這個數據集有一個名稱,叫做文件名。實際上在前面的各章中我們已經多次使用了文件,例如源程序文件、目標文件、可執行文件、庫文件 (頭文件)等。

文件通常是駐留在外部介質(如磁盤等)上的,在使用時才調入內存中來。從不同的角度可對文件作不同的分類。從用戶的角度看,文件可分爲普通文件和設備文件兩種。

操作系統是以文件爲單位對數據進行管理的。

文件的分類

從用戶觀點:

特殊文件(標準輸入輸出文件或標準設備文件)

普通文件(磁盤文件)

從操作系統的角度看,每一個與主機相連的輸入、輸出設備看作是一個文件。

例:輸入文件:終端鍵盤

        輸出文件:顯示屏和打印機

按數據的組織形式:

ASCII文件(文本文件):每一個字節放一個ASCII代碼

二進制文件:把內存中的數據按其在內存中的存儲形式原樣輸出到磁盤上存放。

例如整數10000D在內存中的存儲形式以及分別按ASCII碼形式和二進制形式輸出如下圖所示:

ASCII文件和二進制文件的比較:

ASCII文件便於對字符進行逐個處理,也便於輸出字符。但一般佔存儲空間較多,而且要花費轉換時間。

二進制文件可以節省外存空間和轉換時間,但一個字節並不對應一個字符,不能直接輸出字符形式。

一般中間結果數據需要暫時保存在外存上,以後又需要輸入內存的,常用二進制文件保存。

C語言對文件的處理方法

緩衝文件系統:系統自動地在內存區爲每一個正在使用的文件開闢一個緩衝區。用緩衝文件系統進行的輸入輸出又稱爲高級磁盤輸入輸出。

非緩衝文件系統:系統不自動開闢確定大小的緩衝區,而由程序爲每個文件設定緩衝區。用非緩衝文件系統進行的輸入輸出又稱爲低級輸入輸出系統。

課外知識

在UNIX系統下,用緩衝文件系統來處理文本文件,用非緩衝文件系統來處理二進制文件。

ANSI C 標準只採用緩衝文件系統來處理文本文件和二進制文件。

C語言中對文件的讀寫都是用庫函數來實現。

文件的打開與關閉

文件型指針變量:

FILE  *fp;

fp是一個指向FILE類型結構體的指針變量。

我們使fp指向某一個文件的結構體變量,從而通過該結構體變量中的文件信息能夠訪問該文件。

如果有n個文件,一般應設n個指針變量,使它們分別指向n個文件,以實現對文件的訪問。

FILE類型的數組:

FILE f[5]; 定義了一個結構體數組f,它有5個元素,可以用來存放5個文件的信息。

一頭霧水?不明白?接着看具體的使用就明白啦~

一.文件的打開(fopen函數)

函數調用:

FILE  *fp;

fp = fopen(文件名,使用文件方式);

注意:

需要打開的文件名,也就是準備訪問的文件的名字

使用文件的方式(“讀”還是“寫”等);

讓哪一個指針變量指向被打開的文件。

文件使用方式

文件使用方式 含   義

“r”  

(只讀)爲輸入打開一個文本文件
“w”   (只寫)爲輸出打開一個文本文件
“a”   (追加)向文本文件尾增加數據
rb (只讀)爲輸入打開一個二進制文件
wb (只寫)爲輸出打開一個二進制文件
"ab“ (追加)向二進制文件尾增加數據
"r+“   (讀寫)爲讀/寫打開一個文本文件
"w+” (讀寫)爲讀/寫建立一個新的文本文件
"a+” (讀寫)爲讀/寫打開一個文本文件
"rb+“  (讀寫)爲讀/寫打開一個二進制文件
wb+“ (讀寫)爲讀/寫建立一個新的二進制文件
ab+”  (讀寫)爲讀/寫打開一個二進制文件

 

對於文件使用方式有以下幾點說明

凡用“r”打開一個文件時,該文件必須已經存在,且只能從該文件讀出。

用“w”打開的文件只能向該文件寫入。若打開的文件不存在,則以指定的文件名建立該文件,若打開的文件已經存在,則將該文件刪去,重建一個新文件。

若要向一個已存在的文件追加新的信息,只能用“a”方式打開文件。但此時該文件必須是存在的,否則將會出錯。

在打開一個文件時,如果出錯,fopen將返回一個空指針值NULL。

在程序中可以用這一信息來判別是否完成打開文件的工作,並作相應的處理。

把一個文本文件讀入內存時,要將ASCII碼轉換成二進制碼,而把文件以文本方式寫入磁盤時,也要把二進制碼轉換成ASCII碼,因此文本文件的讀寫要花費較多的轉換時間。對二進制文件的讀寫不存在這種轉換。

舉例:

//文件打開
#include <stdio.h>
#include <stdlib.h>

void main()
{
	FILE *fp;
	if (!(fp = fopen("H:\\csdn.txt", "rb")))  // 注意要雙“ \”
	{
		printf("Can not open H:\\csdn file!\n");
		//system("pause");//暫停在黑色窗口
	}
	else
	{
		printf("Open success!\n");
	}
}

最好把每種打開方式都試一下,看看有什麼區別。

二、文件的關閉(fclose函數)

函數調用:

fclose(文件指針);

函數功能:

使文件指針變量不指向該文件,也就是文件指針變量與文件“脫鉤”,此後不能再通過該指針對原來與其相聯繫的文件進行讀寫操作。

返回值:

關閉成功返回值爲0;否則返回EOF(-1)

文件的讀寫

對文件的讀和寫是最常用的文件操作。在C語言中提供了多種文件讀寫的函數:

 

字符讀寫函數    :fgetc 和 fputc

字符串讀寫函數:fgets 和 fputs

數據塊讀寫函數:fread 和 fwrite

格式化讀寫函數:fscanf 和 fprinf

下面分別予以介紹。使用以上函數都要求包含頭文件stdio.h。

字符讀寫函數:fgetc和fputc

一、字符輸入輸出函數(fputc()和fgetc())

fputc()函數調用:

fputc ( ch,fp ) ;

函數功能:

將字符(ch的值)輸出到 fp 所指向的文件中去。

對於fputc函數的使用要說明幾點

用寫或讀寫方式打開一個已存在的文件時將清除原有的文件內容,寫入字符從文件首開始。如需保留原有文件內容,希望寫入的字符以文件末開始存放,必須以追加方式打開文件。被寫入的文件若不存在,則創建該文件。

每寫入一個字符,文件內部位置指針向後移動一個字節。

fputc函數有一個返回值,如寫入成功則返回寫入的字符,否則返回一個EOF。可用此來判斷寫入是否成功。

//文件寫入
#include <stdio.h>
#include <stdlib.h>

void main()
{
	FILE *fp;
	char ch, filename[20];

	printf("Please input the filename you want to write: ");
	scanf("%s", filename);

	if (!(fp = fopen(filename, "wt+")))
	{
		printf("Cannot open the file!\n");
		exit(0);   // 終止程序
	}

	printf("Please input the sentences you want to write: ");
	// ch = getchar();  // 請思考……
	ch = getchar();
	while (ch != EOF)   // ctrl + z
	{
		fputc(ch, fp);
		ch = getchar();
	}

	fclose(fp);
}

第一個 ch = getchar(); 是爲了消除scanf 產生的換行,如果沒有這一行,產生的文件的開頭就會多一個空行。

字符讀寫函數:fgetc和fputc

fgetc()函數調用:

ch = fgetc(fp);

函數功能:

其意義是從打開的文件 fp 中讀取一個字符並送入 ch 中。

對於fgetc函數的使用要說明幾點

在fgetc函數調用中,讀取的文件必須是以讀或讀寫方式打開的。

在文件內部有一個位置指針。用來指向文件的當前讀寫字節。

在文件打開時,該指針總是指向文件的第一個字節。使用fgetc 函數後,該位置指針將向後移動一個字節。因此可連續多次使用fgetc函數,讀取多個字符。

應注意文件指針和文件內部的位置指針不是一回事。

文件指針是指向整個文件的,須在程序中定義說明,只要不重新賦值,文件指針的值是不變的。

文件內部的位置指針用以指示文件內部的當前讀寫位置,每讀寫一次,該指針均向後移動,它不需在程序中定義說明,而是由系統自動設置的。

#include <stdio.h>
#include <stdlib.h>

void main()
{
	FILE *fp;
	char ch= 0, filename[20];

	printf("Please input the filename you want to read: ");
	scanf("%s", filename);

	if (!(fp = fopen(filename, "r")))
	{
		printf("Cannot open the file!\n");
		exit(0);   // 終止程序
	}

	while (ch != EOF)   // ctrl + z
	{
		ch = fgetc(fp);
		putchar(ch);
	}

	fclose(fp);
}

補充 一下

從一個文本文件順序讀入字符並在屏幕上顯示出來:

   ch = fgetc(fp);

   while(ch!= EOF)

  {

       putchar(ch);

        ch = fgetc(fp);

  }

注意:EOF不是可輸出字符,因此不能在屏幕上顯示。由於字符的ASCII碼不可能出現-1,因此EOF定義爲-1是合適的。當讀入的字符值等於-1時,表示讀入的已不是正常的字符而是文件結束符。

補充 兩下

從一個二進制文件順序讀入字符:

   while(!feof(fp))

  {

        ch = fgetc(fp);

  }

注意:ANSI C提供一個feof()函數來判斷文件是否真的結束。如果是文件結束,函數feof(fp)的值爲1(真);否則爲0(假)。以上也適用於文本文件的讀取。

作業:圖片、文件合成器!

什麼是圖片、文件合成?

就是有一張圖片A(名爲a.jpg)和一個其他的文件類型(例如壓縮包B文件b.rar),我們將他們合成,得到一個文件C,當我們把文件C的後綴名改爲.jpg時,是一個可以打開顯示爲A圖片的圖片文件,當我們將C的後綴名改爲.rar時,它是一個可以打開的爲B壓縮包的文件。

原理就是把B文件的源碼放到A文件的源碼的後面,合成的文件就是文件C。

#include <stdio.h>
#include <stdlib.h>

void main()
{
      FILE *f_file, *f_pic, *f_finish;
      char ch, pic_name[20], file_name[20], finish_name[20];

      printf("請輸入要合成的圖片、文件名稱: \n");
      printf("圖片: ");
      scanf("%s", pic_name);
      printf("文件: ");
      scanf("%s", file_name);
      printf("結果: ");
      scanf("%s", finish_name);
      
      if( !(f_pic = fopen(pic_name, "rb")))
      {
            printf("Cannot open the ficture %s!\n", pic_name);
            exit(0);   // 終止程序
      }
      if( !(f_file = fopen(file_name, "rb")))
      {
            printf("Cannot open the file %s!\n", file_name);
            exit(0);   // 終止程序
      }
      if( !(f_finish = fopen(finish_name, "wb")))
      {
            printf("Cannot open the file %s!\n", finish_name);
            exit(0);    // 終止程序
      }

      while( !feof(f_pic) )  //feof()測試是否爲文件結尾,不是文件的結尾就返回0
      {
            ch = fgetc(f_pic);
            fputc(ch, f_finish);
      }
      fclose(f_pic);

      while( !feof(f_file) )
      {
            ch = fgetc(f_file);
            fputc(ch, f_finish);
      }
      fclose(f_file);
      fclose(f_finish);
}

字符串讀寫函數:fgets和fputs

二、字符串輸入輸出函數(fputs()和fgets())

fgets函數

函數調用形式如:

fgets(str,n,fp);

函數作用:

從fp所指的文件中讀出n-1個字符送入字符數

組str中,因爲在最後加一個’\0’。

返回值:

str的首地址

//字符串讀出
#include <stdio.h>
#include <stdlib.h>

#define LEN 50

void main()
{
	FILE *fp;

	char buffer[LEN];

	if (!(fp = fopen("csdn.txt", "rt")))
	{
		printf("\nCannot open file strike any key exit!");
		exit(1);
	}

	fgets(buffer, LEN, fp);

	printf("%s\n", buffer);

	fclose(fp);
}

fputs函數

函數調用方式:

fputs(“csdn.net”,fp);

函數作用:

其意義是把字符串“csdn.net”寫入fp所指的文件之中。

返回值:

輸入成功,返回值爲0;

輸入失敗,返回EOF.

//字符串寫入
#include <stdio.h>
#include <stdlib.h>

#define LEN 20

void main()
{
	FILE *fp;

	char ch, buffer[LEN];

	if (!(fp = fopen("csdn.txt", "at+")))
	{
		printf("Cannot open file strike any key exit!");
		exit(1);
	}

	printf("Please input a string:\n"); 
	fgets(buffer, LEN, stdin);  // 爲什麼不用scanf()?   因爲scanf() 不能接收有空格的字符串。
	                           //stdin又是啥? stdin 文件是鍵盤輸入緩衝文件。

	fputs(buffer, fp);

	rewind(fp);             // 重新定義文件內部指針去到開頭處

	ch = fgetc(fp);

	while (ch != EOF)
	{
		putchar(ch);
		ch = fgetc(fp);
	}

	printf("\n");

	fclose(fp);
}

數據塊讀寫函數(fread()和fwrite())

函數調用:

fread (buffer, size, count, fp);

fwrite(buffer, size, count, fp);

參數說明:

buffer:是一個指針。

對fread 來說,它是讀入數據的存放地址。

對fwrite來說,是要輸出數據的地址(均指起始地址)。

size:  要讀寫的字節數。

count: 要進行讀寫多少個size字節的數據項。

fp:    文件型指針。

使用舉例

若有如下結構類型:

struct student_type

{char name[10];

 int num;

 int age;

 char addr[30];} stud[40];

可以用fread和fwrite來進行數據的操作:

for(i=0;i<40;i++)

      fread(&stud[i],sizeof(struct student-type),1,fp); 

for(i=0;i<40,i++)

      fwrite(&stud[i],sizeof(struct student-type),1,fp);

要求:

從鍵盤輸入4個學生的有關數據,然後把它們以二進制的格式存儲到磁盤文件中。

#include <stdio.h>

#define SIZE 4

struct student
{
	char name[10];
	int num;
	int age;
	char addr[15];
}stu[SIZE];

void save()
{
	FILE *fp;
	int i;

	if (!(fp = fopen("student-list", "wb")))
	{
		printf("Cannot open the file!\n");
		return;
	}

	for (i = 0; i < SIZE; i++)
	{
		if (fwrite(&stu[i], sizeof(struct student), 1, fp) != 1)
		{
			printf("File write error!\n");
			fclose(fp);
		}
	}
}

void main()
{
	int i;

	printf("Please input the student's name, num, age and address: \n");
	for (i = 0; i < SIZE; i++)
	{
		scanf("%s %d %d %s", stu[i].name, &stu[i].num, &stu[i].age, &stu[i].addr);
	}

	save();
}

// 作業: 寫一個load()函數將該文件讀取並顯示出來! 聰明如你,認真思考一定能做到的! 

答案請看下一節 -->>  零基礎入門學習C語言012講:文件操作(2)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章