【C言語】ファイル操作(超詳しく解説)

1. ドキュメントとは何ですか?

コンピュータ ファイルはファイルの一種で、通常のファイル キャリアとは異なり、ハードディスクをキャリアとしてコンピュータに保存される情報の集合です。
プログラミングでは、通常、プログラム ファイルとデータ ファイルという 2 種類のファイルについて話します。

プログラム ファイル:ソース プログラム ファイル (拡張子 .c)、ターゲット ファイル (Windows 環境の拡張子 .obj)、実行可能プログラム (Windows 環境の拡張子 .exe) が含まれます。
データ ファイル:ファイルの内容は必ずしもプログラムではありませんが、プログラムがデータを読み取る必要があるファイルや内容を出力するファイルなど、プログラムの実行中に読み書きされるデータです。

この記事の内容はデータファイルを対象としており、以前に学習したデータの入出力は端末をベースに、つまり端末のキーボードからデータを入力し、実行結果をモニターに表示します。ただし、データの出力と入力はメモリとファイルの間で転送することもでき、これについてもこの記事で説明します。データの出力はメモリからファイルに書き込まれ、データの入力はファイルに書き込まれます。ファイルからメモリに読み取ります

1. ファイル名

ファイルには一意のファイル識別子が必要であり、ファイル名はファイルの存在を示す識別子でもあり、オペレーティングシステムはファイル名に基づいてファイルを制御、管理します。ファイル名はユーザーの識別と参照のために存在します。
ファイル名は、ファイル パス + ファイル名トランク + ファイル接尾辞の 3 つの部分で構成されます
。次に例を示します。c:\code\test\test.txt

ファイルパス:c:\code\test\
ファイル名トランク:test
ファイルサフィックス:.txt

2. ファイルの種類

データの編成方法に応じて、データ ファイルはテキスト ファイルまたはバイナリ ファイルに分類できます。
データは内部メモリにバイナリ形式で保存されますが、変換せずに外部ストレージに出力する場合はバイナリファイル、外部ストレージにASCIIコード形式で保存する必要がある場合はバイナリファイルとなります。保存する前に変換する必要があります。ASCII 文字の形式で保存されたファイルはテキスト ファイルです。

文字はすべて ASCII 形式で保存され、数値データは ASCII 形式またはバイナリ形式で保存できます。

整数 100 があります。これが ASCII コード形式でディスクに出力される場合、ディスク上で 3 バイト (各文字に 1 バイト) を占有します。また、バイナリ形式で出力される場合、ディスク上で 4 バイトしか占有しません。ディスク (バイナリ形式で保存されたメモリ内のデータ)。

ここに画像の説明を挿入

3. ファイルバッファ

ASIC 標準では、データ ファイルの処理に「バッファ ファイル システム」が使用されています。いわゆるバッファ ファイル システムとは、システムがプログラムで使用されるファイルごとにメモリ内に「ファイル バッファ」を自動的に作成することを意味します。メモリからディスクに出力されたデータは、まずメモリ内の出力バッファに送信され、バッファがいっぱいになった後にまとめてディスクに送信されます。ディスクからコンピュータにデータを読み込む場合、ディスクファイルからデータを読み取ってメモリ上の入力バッファに入力し、バッファからプログラムデータ領域(プログラム変数など)にデータを送信します。一つずつ。バッファのサイズは C コンパイル システムによって決定されます。もちろん、常にこのような条件を満たしてデータを送受信する必要はなく、緊急の条件が発生した場合には、バッファがフルになるのを待たずに直接送信することも可能である。

ここに画像の説明を挿入

#include <stdio.h>
#include <windows.h>
int main()
{
    
    
	FILE* pf = fopen("test.txt", "w");
	fputs("abcdef", pf);//此时只是将数据放到了缓冲区当中
	printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
	Sleep(10000);
	printf("刷新缓冲区\n");
	fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到了磁盘当中
	printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
	Sleep(10000);
	//fclose在关闭文件的时候也会刷新缓冲区
	fclose(pf);
	pf = NULL;
	return 0;
}

このコードはそれ自体で検証できます。fputs 関数の実行後、test.txt ファイルを開くと、データがないことがわかります。バッファを更新すると、test.txt ファイルにデータが表示されます。fflush 機能は緊急事態であると考えられます。
注: バッファが存在するためです。C言語でファイル操作を行う場合、ファイル操作終了時にバッファをリフレッシュするかファイルを閉じる必要があります。そうしないと、ファイルの読み取りおよび書き込みで問題が発生する可能性があります。

2. ファイル操作

1. ファイルポインタ

キャッシュ ファイル システムでは、重要な概念は「ファイル タイプ ポインター」であり、「ファイル ポインター」と呼ばれます
使用された各ファイルは、メモリ内の対応するファイル情報領域を開き、ファイルの関連情報 (ファイル名、ファイルのステータス、ファイルの現在の場所など) を保存するために使用されます。 )。この情報は構造体変数に保存されます。構造体のタイプは、 FILEという名前でシステムによって宣言されます

たとえば、VS2013 コンパイル環境によって提供される stdio.h ヘッダー ファイルには、次のファイル タイプ宣言があります。

struct _iobuf {
    
    
        char *_ptr;
        int   _cnt;
        char *_base;
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname;
       };

typedef struct _iobuf FILE;

ファイルが開かれるたびに、システムはファイルの状況に応じて FILE 構造の変数を自動的に作成し、情報を埋め込みます。通常、FILE 構造の変数は FILE ポインタを介して保持されます。この FILE 構造では、最初の A 変数はファイル名であり、対応するファイルはファイル名を通じて維持できます。

FILE* ポインター変数を作成します。

FILE* pf;//文件指针变量

pf は、FILE タイプのデータを指すポインタ変数です。pf ポインタは、ファイルのファイル情報領域 (FILE 構造変数) を指すことができ、ファイル情報領域には、test.txt ファイルの特定の詳細が含まれます。ファイルであると言われます 情報領域の内容はファイルについて説明します。
ここに画像の説明を挿入

2. ファイルの開閉

ファイルのオープンとクローズには、対応する関数があります。fopen() と fclose() はペアで表示されます。前述のように、バッファが更新されたり、ファイル操作の最後にファイルが閉じられていない場合、読み取りとファイルの書き込みが問題です。プログラムを作成するとき、ファイルを開くとき、ファイルを指す FILE* ポインター変数が返されます。これは、ポインターとファイルの間の関係を確立することと同じです。

FILE * fopen ( const char * filename, const char * mode );

int fclose ( FILE * stream );

ファイルを開く方法:

ファイルを開く方法 意味 指定したファイルが存在しない場合
「r」(読み取り専用) データを入力するには、既存のテキスト ファイルを開きます うまくいかない
「w」(書き込みのみ) データを出力するには、テキスト ファイルを開きます 新しいファイルを作成する
“a”(追加) テキストファイルの末尾にデータを追加します うまくいかない
「rb」(読み取り専用) データを入力するには、バイナリ ファイルを開きます うまくいかない
「wb」(書き込みのみ) データを出力するには、バイナリ ファイルを開きます 新しいファイルを作成する
“ab”(追加) バイナリファイルの末尾にデータを追加する うまくいかない
「r+」(読み取りおよび書き込み) テキスト ファイルを開いて読み取りと書き込みを行う うまくいかない
「w+」(読み取りおよび書き込み) 読み取りと書き込みの場合は、新しいファイルを提案します 新しいファイルを作成する
「a+」(読み取りおよび書き込み) ファイルの最後で読み取りと書き込みを行うためにファイルを開きます。 新しいファイルを作成する
「rb+」(読み取りおよび書き込み) バイナリ ファイルを読み書き用に開きます。 うまくいかない
「wb+」(読み取りおよび書き込み) 読み取りおよび書き込み用の新しいバイナリ ファイルを作成します 新しいファイルを作成する
「ab+」(読み取りおよび書き込み) ファイルの最後でバイナリ ファイルを読み書き用に開きます。 新しいファイルを作成する

ファイルのオープンとクローズの例:

#include <stdio.h>
int main ()
{
    
    
  FILE* pFile = fopen ("test.txt","w");
  if (pFile!=NULL)
 {
    
    
    fputs ("Hello,World!",pFile);
    fclose (pFile);
 }
  return 0;
}

3. ファイルのシーケンシャル読み取りと書き込み

関数 関数名 に適用する
文字入力機能 fgetc すべての入力ストリーム
文字出力機能 fputc すべての出力ストリーム
テキスト行入力機能 fgets すべての入力ストリーム
テキスト行出力機能 fputs すべての出力ストリーム
フォーマット入力機能 fscanf すべての入力ストリーム
フォーマット出力機能 fprintf すべての出力ストリーム
バイナリ入力 恐れる 書類
バイナリ出力 fwrite 書類

注: 次の手順はペアごとに対応しています。

3.1 文字出力関数(fputc())

ここに画像の説明を挿入

//将26个英文字母输出到test.txt文件中
#include <stdio.h>
int main()
{
    
    
	FILE* pf = (FILE*)fopen("test.txt", "w");
	if (pf==NULL)
	{
    
    
		perror("fopen");
		return -1;
	}
	for (int i = 0; i < 26; i++)
	{
    
    
		fputc('a'+i, pf);
	}
    fclose(pf);
    pf=NULL;
	return 0;
}

3.2 文字入力関数(fgetc())

ここに画像の説明を挿入

//将26个英文字母输入到内存当中并将其打印在屏幕上
#include <stdio.h>
int main()
{
    
    
	FILE* pf = (FILE*)fopen("test.txt", "r");
	if (pf==NULL)
	{
    
    
		perror("fopen");
		return -1;
	}
	char c = 0;
	while ((c = fgetc(pf)) != EOF)
	{
    
    
		printf("%c", c);
	}
	fclose(pf);
    pf=NULL;
	return 0;
}

3.3 テキスト行出力関数(fputs())

ここに画像の説明を挿入

#include <stdio.h>
int main()
{
    
    
	FILE* pf = (FILE*)fopen("test.txt", "w");
	if (pf==NULL)
	{
    
    
		perror("fopen");
		return -1;
	}
	fputs("Hello,World! ", pf);
    fclose(pf);
    pf=NULL;
	return 0;
}

3.4 テキスト行入力関数(fgets())

ここに画像の説明を挿入

#include <stdio.h>
int main()
{
    
    
	FILE* pf = (FILE*)fopen("test.txt", "r");
	if (pf==NULL)
	{
    
    
		perror("fopen");
		return -1;
	}
	char arr[10] = {
    
     0 };
	fgets(arr, 7, pf);
	printf("%s", arr);
	fclose(pf);
	pf=NULL;
	return 0;
}

3.5 整形出力関数(fprintf())

ここに画像の説明を挿入

#include <stdio.h>
int main()
{
    
    
	FILE* pf = (FILE*)fopen("test.txt", "w");
	if (pf==NULL)
	{
    
    
		perror("fopen");
		return -1;
	}
	fprintf(pf, "%s %d", "zhuxu", 115);
	fclose(pf);
	pf = NULL;
	return 0;
}

3.6 フォーマット入力関数(fscanf())

ここに画像の説明を挿入

#include <stdio.h>
int main()
{
    
    
	FILE* pf = (FILE*)fopen("test.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return -1;
	}
	char str[10] = {
    
     0 };
	int n = 0;
	fscanf(pf, "%s", str);
	fscanf(pf, "%d", &n);
	printf("%d\n", n);
	printf("%s\n",str);
	fclose(pf);
	pf = NULL;
	return 0;
}

3.7 バイナリ出力 (fwrite())

ここに画像の説明を挿入
関数パラメータ:

ptr メモリ ブロックへのポインタ。最小スペース サイズは (size*count) バイトです。
size 読み取る各要素のバイト単位のサイズ。
count 要素の数。各要素は size バイトです。
stream 入力ストリームを指定する FILE オブジェクトへのポインタ。

#include <stdio.h>
int main()
{
    
    
	char buffer[] = {
    
     'x', 'y', 'z' };
	FILE* pf = fopen("test.txt", "wb");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return -1;
	}
	fwrite(buffer,1,3,pf);
	fclose(pf);
	return 0;
}

3.8 バイナリ入力 (fread())

ここに画像の説明を挿入

#include <stdio.h>
int main()
{
    
    
	char buffer[5] = {
    
     0 };
	FILE* pf = fopen("test.txt", "rb");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return -1;
	}
	fread(buffer, 1, 3, pf);
	printf("%c ", buffer[0]);
	printf("%c ", buffer[1]);
	printf("%c ", buffer[2]);
	return 0;
}

4. ファイルのランダムな読み取りと書き込み

4.1 fseek関数

ファイル ポインタの位置とオフセットに基づいてファイル ポインタを配置します。

int fseek ( FILE * stream, long int offset, int origin );

ここに画像の説明を挿入

#include <stdio.h>
int main ()
{
    
    
	FILE* pf = fopen ("test.txt","w");
  	fputs ( "This is an apple." , pf );
  	fseek ( pf , 9 , SEEK_SET );
  	fputs ( " sam" , pf );
 	fclose ( pf );
  	return 0;
}
// This is a sample.

int main()
{
    
    
	FILE* pf = fopen ("test.txt","w");
	fputs("This is an apple.", pf);
	fseek(pf, -8, SEEK_END);
	fputs(" sam", pf);
	fclose(pf);
	return 0;
}

4.2 フィート関数

開始位置を基準としたファイル ポインタのオフセットを返します。

long int ftell ( FILE * stream );
//计算test.txt文件里的数据长度
#include <stdio.h>

int main ()
{
    
    
  	long size;
    FILE *pf = fopen ("test.txt","r");
  	if (pf == NULL)
	{
    
    
		perror("fopen");
		return -1;
	}
    else
    {
    
    
    	fseek (pFile, 0, SEEK_END);   // non-portable
   	 	size=ftell (pFile);
   	 	fclose (pFile);
    	printf ("Size of myfile.txt: %ld bytes.\n",size);
 	}
 	return 0;
}

4.3 巻き戻し機能

ファイルポインタの位置をファイルの先頭に戻します

void rewind ( FILE * stream );
#include <stdio.h>
int main ()
{
    
    
  	int n;
  	char buffer [27];
  	FILE* pf = fopen ("test.txt","w+");
  	for ( n='A' ; n<='Z' ; n++)
  	{
    
    
    	fputc ( n, pf );
    }
  	rewind (pf);
  	fread (buffer,1,26,pf );
  	fclose (pf);
  	buffer[26]='\0';
  	puts (pf);
  	return 0;
}

4. ファイル終了判定

  1. テキストファイルの読み込みが終了したか、戻り値がEOF(fgetc)かNULL(fgets)かを判定

fgetc は EOF かどうかを判定し、
fgets は戻り値が NULL かどうかを判定します。

注:ファイルの読み込み処理中、feof 関数の戻り値を使用してファイルが終了したかどうかを直接判断することはできません。代わりに、ファイルの読み取りが終了したときに適用され、読み取りが終了できなかったのか、ファイルの終わりに達したかが判断されます。

  1. バイナリファイルの読み込み終了を判定し、戻り値が実際に読み込む数値より小さいかどうかで判定します。

fread は戻り値が実際に読み込む数値より小さいかどうかを判断します。

テキストファイルは正しく判定されます

#include <stdio.h>
#include <stdlib.h>
int main()
{
    
    
    int c; // 注意:int,非char,要求处理EOF
    FILE* fp = fopen("test.txt", "r");
  	if (pf == NULL)
	{
    
    
		perror("fopen");
		return -1;
	}
 //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
    while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
   	{
    
     
       	putchar(c);
   	}
 //判断是什么原因结束的
    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
        puts("End of file reached successfully");
    fclose(fp);
    fp = NULL;
    return 0;
}

バイナリファイルが正しく判定される

#inlcude <stdio.h>
int main(void)
{
    
    
    double a[5] = {
    
    1.0,2.0,3.0,4.0,5.0};
    double b = 0.0;
    size_t ret_code = 0;
    FILE *fp = fopen("test.txt", "wb"); // 必须用二进制模式
    fwrite(a, sizeof(*a), 5, fp); // 将 a 数的元素写到test.txt文件中
    fclose(fp); 
    fp = fopen("test.txt","rb");
    // 将 a 数组的元素读到变量 b 中,返回值为读取数据的个数
    while((ret_code = fread(&b, sizeof(double), 1, fp))>=1)
   	{
    
    
        printf("%lf\n",b);
   	}
    if (feof(fp))
        printf("Error reading test.bin: unexpected end of file\n");
    else if (ferror(fp)) {
    
    
        perror("Error reading test.bin");
   	}
    fclose(fp);
    fp = NULL;
    return 0;
}

おすすめ

転載: blog.csdn.net/weixin_47648037/article/details/127259629