C言語の基礎(9) ファイルに関する操作


はじめてわかるC言語シリーズ集

10. 書類

10.1 C ファイルの概要

ファイル: 外部メディアに保存されているデータの集合。オペレーティング システムのデータ管理の単位です。
データファイルを使用する目的:
1) プログラムとデータの分離: データファイルの変更はプログラムの変更を引き起こさない
2) データ共有: 異なるプログラムが同じデータファイル内のデータにアクセスできる
3) 中間データを保存できる長時間にわたるプログラム動作のデータまたは結果データ

ファイル分類:
(1) ファイルの論理構造による レコード
ファイル: 一定の構造(固定長または可変長)を持つレコードで構成される
ストリームファイル: 文字(バイト)データ列で構成される(2)共通ストレージ
によるメディア
ファイル:記憶媒体ファイル(ディスク、テープなど)
デバイス ファイル:非記憶媒体(キーボード、モニタ、プリンタなど)
(3)データの構成に応じて
テキスト ファイル:ASCII ファイル、各バイトにデータが格納されます。 1 文字の ASCII コード。
テキストファイルの特徴:記憶容量が大きい、速度が遅い、文字操作が容易
バイナリファイル:データをそのままメモリ上に記憶形式で保存する バイナリファイル
の特徴:記憶容量が小さい、速度が速い、中間結果の保存が容易

ファイル処理方法:
バッファ ファイル システム: 高レベル ファイル システム、システムは使用中のファイルのメモリ バッファを自動的に開きます。
非バッファ ファイル システム: 低レベル ファイル システム、ユーザーがプログラム内の各ファイルのバッファを設定します。

10.2 ファイルタイプポインタ

ファイル構造 FILE:
バッファ ファイル システムは、使用されるファイルごとにメモリ内にファイル情報領域を開き、ファイル情報は FILE という名前のシステム定義構造によって記述されます。

FILEはstudio.hで定義されています

typedef struct{
    
    
	int _fd;  //	文件号
	int _cleft;  //缓冲区剩下的字符数
	int _mode;  //文件操作方式
	char *_next;  //文件当前读写位置
	char *_buff;  //文件缓冲区位置
}FILE;

ファイル タイプ ポインタ:
ポインタ変数の説明: FILE *fp;
使用法: ファイルが開かれると、システムは自動的にファイル構造を構築してそのファイルへのポインタを返し、プログラムはこのポインタを通じてファイル情報を取得してファイルにアクセスします。ファイルが閉じられると、ファイル構造が解放されます。
ここに画像の説明を挿入

10.3 ファイルの開閉

10.3.1 ファイルを開く

C ファイルの操作は、studio.h ファイルを含むライブラリ関数を呼び出すことによって実装されます
。使用方法: ファイルを開きます -- ファイルの読み取りと書き込み -- ファイルを閉じます。
システムは 3 つの標準ファイルを自動的に開閉します:
標準入力: キーボード stdin
標準出力 : モニタ stdout
標準エラー出力 : モニタ stderr

ファイル fopen を開きます:
関数プロトタイプ:

FILE   *fopen (char *name, char *mode)

機能: 指定されたメソッドに従ってファイルをオープンします
戻り値: 正常にオープンします (ファイル構造へのポインタ)、オープンに失敗すると NULL を返します
例: ファイルのオープンとテスト

FILE *fp;
fp = fopen("a.c""w");
if(fp == NULL){
    
    
	prentf("file open error\n");
	exit(0);
}

ファイルを開く方法:

3 つの基本モード:
「r」(読み取り) モードは常に既存のファイルを開き、ファイルが存在しない場合はエラーになります。
「w」(書き込み)モードでは新しいファイルが作成されます。ファイルがすでに存在する場合は、まず既存のファイルを削除してから、新しいファイルを作成します。
「a」(追加) は既存のファイルを開き、ファイルの末尾にデータを追加します。

3 つのアペンダー:
「b」(バイナリ) はバイナリ ファイルを意味します。
「t」(またはデフォルト)はテキスト ファイルを意味します。
「+」はモードを読み書き可能に拡張することを意味します。

ファイルの開き方 意味
'r' (読み取り専用) 入力用にテキスト ファイルを開く
'w' (書き込みのみ) 出力用にテキスト ファイルを開く
’ a '(追加) テキスト ファイルの末尾にデータを追加する
'rb' (読み取り専用) 入力用にバイナリ ファイルを開く
'wb' (書き込みのみ) 出力用にバイナリ ファイルを開く
’ ab '(追加) バイナリファイルの末尾にデータを追加します
「r+」 (読み取りおよび書き込み) テキスト ファイルを読み書き用に開きます
' w+ ' (読み取りおよび書き込み) 読み取り/書き込み用の新しいテキスト ファイルを作成します
' a+ ' (読み取りおよび書き込み) テキスト ファイルを読み書き用に開きます
'rb+' (読み取りおよび書き込み) バイナリファイルを読み取り/書き込み用に開きます
' wb+ ' (読み取りおよび書き込み) 読み取り/書き込み用の新しいバイナリ ファイルを作成します
'ab+' (読み取りおよび書き込み) バイナリファイルを読み取り/書き込み用に開きます

10.3.2 ファイルを閉じる

関数: ファイルポインタ変数をファイルから「切り離し」、ファイル構造とファイルポインタを解放する
関数プロトタイプ: int fclose(FILE *fp);
*fp: ファイルを開いたときに返されるファイルタイプポインタ
関数: ファイルを閉じるfp の戻り値が指す
: 通常のシャットダウンは 0、エラーは 0 以外
ここに画像の説明を挿入

10.4 ファイルの読み取りと書き込み

10.4.1 fputc関数とfgetc関数

文字 I/O: fputc および fgetc
1) fputc
関数プロトタイプ:

int fputc(int c,FILE *fp)

関数: fp が指すファイルに半角コード c を書き込む
戻り値: 成功、c を返す、エラー、EOF を返す
2) fgetc
関数のプロトタイプ: int fgetc(FILE *fp)
関数: fp が指すファイルから読み取る半角コード
戻り値:正常、読み取ったコード値を返す、ファイルの最後まで読み込むかエラーになる

终端I/O 文件I/O
#定義 putc ( ch 、 fp ) fputc (ch,fp)
#定義 getc ( fp ) fgetc ( fp )
#定義 putchar ( c ) fputc ( c,stdout )
#定義 getchar ( ) fgetc (標準入力)

例:
1. キーボードから文字を入力し、「#」が入力されるまで 1 つずつディスク ファイルに保存します。

#include <stdio.h>
#include <stdlib.h>
int main(){
    
    
	//FILE *fp 是声明,声明fp是指针,用来指向FILE类型的对象。
	FILE *fp;
	char ch,filename[10];
	printf("请输入文件名称:\n");
	scanf("%s",filename);
	if((fp=fopen(filename,"w"))==NULL){
    
    
		printf("open file is false,exit...\n");
		exit(0);
	}
	printf("open file is true,Please input word\n");
	//前面的scanf()在读取输入时会在缓冲区中留下一个字符'\n'
    //所以如果不在此加一个getchar()把这个回车符取走的话,
	//而是会直接取走这个“无用的”回车符,从而导致读取有误。
	ch=getchar();
	//首次获取键盘输入
	ch=getchar();
	while(ch!='#'){
    
    
		//fputc 将字符ch写到文件指针fp所指向的文件的当前写指针的位置
		fputc(ch,fp);
		ch=getchar();
	}
	fclose(fp);
	return 0;
}

入力:
file1.c
コンピューターと c#
出力:
コンピューターと c
2. あるディスク ファイルから別のディスク ファイルに情報をコピーします。

#include <stdio.h>
#include <stdlib.h>
int main()
{
    
    
    FILE *in,*out;
	char ch,infile[10],outfile[10];
	printf("enter the infile name:");
	scanf("%s",infile);
	printf("enter the outfile name:");
	scanf("%s",outfile);
	if((in=fopen(infile,"r"))==NULL){
    
    
        printf("cannot open this file\n");
        exit(0);
	}
	if((out=fopen(outfile,"w"))==NULL){
    
    
        printf("cannot open this file\n");
        exit(0);
	}
	ch=fgetc(in);
	// 对feof()来说,站在光标所在位置,向后看看还有没有字符。如果有,返回0;如果没有,返回非0。
	//它并不会读取相关信息,只是查看光标后是否还有内容。
	//
	while(!feof(in)){
    
    
	    fputc(ch,out);
		ch=fgetc(in);
	}
	fclose(in);
	fclose(out);
	return 0;
}

入力:
file1.c
file2.c

10.4.2 fread関数とfwrite関数

データ ブロック I/O: fread および fwrite
関数のプロトタイプ:

size_t fread( void *buffer, size_t size, size_t count, FILE *fp)
size_t fwrite( void *buffer, size_t size, size_t count, FILE *fp)

*buffer、size_t:入出力するデータブロックの先頭アドレスへのポインタ
size、size_t:読み書きする各データブロックのサイズ(バイト数)
count、FILE:入出力するデータブロック数読み取り/書き込み
* fp: 読み取り/書き込み対象のファイル ポインタ
機能: データ ブロックの読み取りおよび書き込み
戻り値: 成功の場合は、読み取りおよび書き込みのブロック数を返します。エラーまたはファイルの終わりの場合は、0 を返します。

例:生徒4人のデータをキーボードから入力し、ディスクファイルに保存し、画面に表示する

#include <stdio.h>
#define SIZE 4
struct Student_type
{
    
    
	char name[10];
	int num;
	int age;
	char addr[15];
}stud[SIZE];
void save()
{
    
    
	FILE *fp;
	int i;
	if ((fp = fopen("stu_data", "wb")) == NULL)
	{
    
    
		printf("cant open file\n");
		return;
	}
	for (i = 0; i < SIZE; i++)
	{
    
    
		if (fwrite(&stud[i], sizeof(struct Student_type), 1, fp) != 1)
			printf("file write error\n");
	}
	fclose(fp);
}
void display()
{
    
    
	int i;
	FILE *fp;
	if ((fp = fopen("stu_data", "rb")) == NULL)
	{
    
    
		printf("cannot open file\n");
		return;
	}
	for (i = 0; i < SIZE; i++)
	{
    
    
		fread(&stud[i], sizeof(struct Student_type), 1, fp);
		printf("%-10s %4d %4d %-15s\n", stud[i].name, stud[i].num, stud[i].age, stud[i].addr);
	}
	fclose(fp);
}
int main()
{
    
    
	int i;
	printf("please enter date of studnet:\n");
	for (i = 0; i < SIZE; i++)
	{
    
    
		scanf("%s %d %d %s", stud[i].name, &stud[i].num, &stud[i].age, stud[i].addr);
	}
	save();
    display();
}

10.4.3 fprintf関数とfscanf関数

フォーマットされた I/O: fprintf および fscanf
関数のプロトタイプ:

int fprintf ( FILE *fp, const char  *format [argument...])
int fscanf ( FILE *fp,const char  *format [address...] )

機能: 形式に従ってファイルに対する I/O 操作を実行します
戻り値: 成功した場合は I/O の数を返します; 失敗した場合はエラーまたはファイルの終わりを返します EOF を返します

fprintf (fp, "%d,%6.2f",i,t);
//将i和t按%d,%6.2f格式输出到fp文件
fscanf(fp, "%d,%f",&i,&t);
//将文件中的整型数据输入i,浮点型数据输入t

10.4.4 その他の読み取りおよび書き込み関数

文字列I/O: fgetsとfputs

char *fgets( char *s, int n,FILE *fp)
int fputs(char *s,FILE *fp)

機能: fp が指すファイルから文字列を読み書きする
戻り値:
fgets は正常な場合は読み取った文字列の先頭アドレスを返し、エラーまたはファイルの終わりの場合は NULL を返し、
fputs は最後の文字を返す正常な場合は書き込み、EOF の場合はエラー

fgets は、fp が指すファイルから n-1 文字を読み取り、s が指すメモリ領域に送信し、最後に「\0」を追加します (読み取り前に改行文字またはファイルの終わり (EOF) が見つかった場合) n-1 文字、つまり終了)
fputs は、s が指す文字列を fp が指すファイルに書き込みます

10.5 ファイルの場所

10.5.1 巻き戻し機能

ファイル位置ポインタ ----- 現在の読み取りおよび書き込み位置へのポインタ
シーケンシャル読み取りおよび書き込み: 位置ポインタはバイト位置の順序に従って移動します
ランダム読み取りおよび書き込み: 位置ポインタは必要に応じて任意の位置に移動します 関数プロトタイプ
:

void rewind(FILE *fp)

機能: ファイル位置ポインタをファイルの先頭に
リセット 戻り値: なし

例: ファイルから、その内容を初めて画面に表示し、それを別のファイルにコピーします

#include<stdio.h>
int main()
{
    
    
    FILE *fp1,*fp2;
    fp1 = fopen("file1.c","r");
    fp2 = fopen("file2.c","w");
    while(!feof(fp1)) putchar(getc(fp1));
    rewind(fp1);
    while(!feof(fp1)) putc(getc(fp1),fp2);
    fclose(fp1);
    fclose(fp2);
}

10.5.2 fseek関数とランダム読み書き

fseek 関数の
関数プロトタイプ:

int fseek(FILE *fp, long offset, int from)

機能: ファイル位置ポインタの位置を変更
戻り値: 成功、0 を返す; 失敗、0 以外を返す;
オフセット: ディスプレースメント、型はlongで、からの移動量の相対値(バイト数)を示します。
from: 動きの開始位置。
値の意味から:

値から 宏名 意味
0 SEEK_SET ファイルヘッダー
1 SEEK_CUR 現在位置
2 SEEK_END ファイルの終わり

例 1: ディスク ファイル上に 4 つの生徒データがあり、1 番目と 3 番目の生徒データを読み取って表示する必要がある

#include <stdio.h>
#include<stdlib.h>
struct student_type
{
    
        char name[10];
     int num;
     int age;
     char addr[15];
}stud[10];
int main()
{
    
    
    FILE * fp;
    int i;
    if ((fp = fopen( "stu_data" , "rb" )) == NULL)
    {
    
    
    printf( "cannot open file\n " );
    exit(0);
    }
    for (i = 0 ;i < 4;i ++ )
    {
    
    
        fseek(fp,i*sizeof(struct student_type),0);
        fread(&stud[i],sizeof(struct student_type),1,fp);
        printf("%s %d %d %s \n",stud[i].name,stud[i].num,stud[i].age,stud[i].addr);
    }
    fclose(fp);
}

例 2:

fseek(fp,10L,SEEK_SET);   //将读写指针移动到离文件头10个字节处
fseek(fp,20L,1);  //将读写指针移动到离当前位置20个字节处
fseek(fp,-10L,2);   //将读写指针移动到离文件末尾处10个字节处。

10.5.3 ftell 関数

関数プロトタイプ:

long ftell(FILE *fp)

機能: 位置ポインタの現在位置を返します (ファイルの先頭からの相対的な変位で示されます)
戻り値: 成功した場合は、現在位置ポインタの位置を返します; 失敗した場合は、-1L を返します

10.6 エラー検出

10.6.1 フェラー関数

関数プロトタイプ:

int  ferror(FILE  *fp)

機能: ファイルにエラーがあるかどうかをテストします
。 戻り値: エラーなし、0、エラーあり、0 以外

注:
1) ファイル入出力関数が呼び出されるたびに、新しい ferror 関数値が生成されるため、時間内にテストする必要があります。 2)
fopen がファイルを開くと、ferror 関数の初期値は自動的に 0 に設定されます。

10.6.2 クリア関数

関数プロトタイプ:

 void  clearerr(FILE  *fp)

機能: ファイルエラーフラグを 0 に設定します
。 戻り値: なし
説明: エラーが発生した後、clearerr (fp) または rewind、またはその他の入出力関数が同じファイルに対して呼び出されるまで、エラーフラグは残ります。

10.6.3 feof関数

関数:
feof() はストリーム上のファイルの終わりを検出する関数です。ファイルが終了した場合はゼロ以外の値を返し、それ以外の場合は 0 を返します。

EOF:
1) EOF はコンピュータ用語で、End Of File の頭字語で、オペレーティング システムにおいて、データ ソースに読み取るデータがなくなったことを意味します。データ ソースは、ファイルまたはストリームと呼ばれることがよくあります。この文字は通常、資料の終わりを示すためにテキストの最後に表示されます。
2) 文書の最後に隠し文字「EOF」があり、プログラムがそれを読み取ると、ファイルが最後に達したことがわかります。
3) EOF の値は通常 -1 ですが、システムによって異なります。

feof() の原理:
カーソルの位置に立ち、後ろを向いて文字があるかどうかを確認します。存在する場合は 0 を返し、存在しない場合は 0 以外を返します。関連情報を読み取るのではなく、カーソルの後にコンテンツがあるかどうかを確認するだけです。

注:
1) ファイルの場合、空のファイルであっても、情報のあるファイルであっても、ファイルを開いたときにカーソルがデフォルトの先頭にある場合、カーソルの後に情報が存在します。このとき feof() を呼び出します。カーソルが Content であるかどうかを確認するのは無意味です。
2) 同じものとの違いを見つける必要があります。まず getc() を使用してファイルから文字を読み取り、カーソルを 1 文字後方に移動します。このとき、時空ファイルのカーソルはEOFの後ろに移動しており、このときfeof()は1を返します。これが feof() の正しい使用法です。
3) ただし、ファイルが空かどうかを判断する前に、カーソルをファイルの先頭に戻す必要があることに注意してください。ファイルが空であるかどうかを判断する前に、カーソルを 1 つ進めてから、カーソルを先頭に戻す必要があります。ファイルの通常の読み取り。

rewind(p);//将光标跳回到文件开头
分類 関数名
ファイルを開く fopen()
ファイルを閉じる fclose()
ファイルの場所 fseek() ; 巻き戻し() ; ftell()
ファイルの読み取りと書き込み fgetc() 、 getc() 、 fputc() 、 putc() 、 fgets() 、 fputs() 、 getw() 、 putw() 、 fread() 、 fwrite() 、 fscan() 、 fprintf()
ファイルステータス feof() 、 ferror() 、 clearerr()

おすすめ

転載: blog.csdn.net/qq_43310387/article/details/124245804