[C 言語] ファイル内容の効率的な処理: C 言語でのファイル操作のヒントとコツ

目次

1. ファイルの分類

1. 記憶媒体による分類

2. 保管方法による分類

2. テキストファイル

3. バイナリコードファイル 

第 4 に、バイナリ ファイルとファイル ファイルの違い 

5、ファイルバッファ 

 1. ファイルバッファをリフレッシュする方法

2. アナログ時計

3. ファイルポインタ

6. ファイルAPI

1. ファイル fopen を開きます

2. ファイル fclose を閉じます。

3. fgetc fputc を 1 文字ずつ読み書きします

4. 文字列を一度に読み書きする fgets fputs

5. 一度に n ブロックのファイル データを読み書きする fread fwrite

 6. 読み取りおよび書き込みの fscanf fprintfEdit のフォーマット

 1. fprintf をフォーマットして書き込みます (ファイル ポインタ、フォーマット文字列、出力リスト)

2. フォーマットされた fscanf 読み取り (ファイル ポインタ、フォーマット文字列、出力リスト)

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

1. シーケンシャルな読み取りと書き込みでは、ランダムな読み取りと書き込みのケースが導入されます。

2. ランダム読み取りおよび書き込み API

(1) 巻き戻しはファイル ストリーム ポインタをリセットします

 (2) ftell はファイルストリームポインタからファイルヘッダまでのバイト数を返します。

(3) fseek ファイルストリームポインタの位置決め

8. ファイル暗号化ツール


1. ファイルの分類

1.記憶媒体による分類

ディスクファイル: ファイルのデータはディスクに保存されます (オーディオとビデオ、画像ファイル、ドキュメントファイル)

デバイスファイル: システムを通じて外部デバイス ファイルを抽象化します。

2. 保管方法による分類

物理的に: どのディスク ファイルも物理的にはバイナリ ストレージです。

論理的に: ディスク ファイルはバイナリ ファイルテキスト ファイルに分割されます

2.テキストファイル

テキスト ファイルは文字エンコーディング        に基づいており、一般的なエンコーディングにはASCII、UNICODE などが含まれます。通常、テキストエディタで直接開くことができます。

        例えば:

        (1) 数値 5678 は、ASCII コードとして ASCII に保存されます。

                 00110101(==53=='5')    00110110   00110111    00111000         合計4B

        (2)歌詞ファイル(lrc):テキストファイル 

3.バイナリコードファイル 

エンコーディング        に基づいて、メモリ上のデータがそのままディスクに出力されますが、一般的にはデータ形式を自分で判断するか、専用のソフトウェアを使用して解析する必要があります。

        例: 数値 5678 の格納形式は次のとおりです: バイナリ コード: 00010110 00101110

第 4 に、バイナリ ファイルとファイル ファイルの違い 

テキストファイル:

利点: 1 バイトで 1 つの意味を表し、見やすくなります。

短所: 広いスペース、低効率

バイナリファイル:

利点: 高効率、省スペース

短所: 長さが可変、閲覧が不便

5、ファイルバッファ 

 1.ファイルバッファをリフレッシュする方法

1. 行の更新:改行文字が見つかったときに更新します。

2. フルリフレッシュ: バッファデータがフルになり、リフレッシュされます。

3. 強制リフレッシュfflush関数を使用してバッファをリフレッシュします。

4. 新規再生をオフにします。プログラムの実行が終了すると、すべてのバッファ データが更新されます。

2. アナログ時計

#include<unistd.h>
void test()
{
    int i=0;
    while(1)
    {
        printf(\r%02d:%02d",i/60,i%60);//\r回到行首
        fflush(stdout);//强制刷新
        sleep(1);
        i++;
}

3. ファイルポインタ

        ファイルを操作するすべてのライブラリ関数は、ファイルを操作するためにファイル ポインターを使用する必要があります

各プロセスに対してデフォルトで開かれる 3 つのファイル ポインター:

(1) stdin : 標準入力はデフォルトで現在の端末 (キーボード) であり、
使用する scanf 関数と getchar 関数はデフォルトでこの端末からデータを取得します。

(2) stdout : 標準出力、デフォルトは現在の端末 (画面)
使用する printf 関数と put 関数は、デフォルトでこの端末に情報を出力します
(3) stderr : 標準エラー出力デバイス ファイルのデフォルトは現在の端末 (画面)

プログラムがエラーを起こしてperror関数を使用すると、情報がこの端末に出力されます。

例:fgets(buf,sizeof(buf),stdin);

        fwrite("hello world",12,1,stdout);//1 バイト出力の 12 ブロック

6. ファイルAPI

ファイル操作手順: 開く、読み取り、書き込み、閉じる

1. ファイルfopenを開きます

        fopen の f はそれをライブラリ関数として記述し、その最下層は open 関数を使用してシステム コールを完了します。

定義: FILE *fopen(const char *path, const char *mode);

パス: ファイルのパス

モード: オープンファイルモード

戻り値:

        成功: 開いているファイル ポインタ

        失敗: NULL

ファイルを開くモード: r、w、a、+、t、b

r :読み取り専用として開きます

w :書き込み専用にオープン

a :追加して開く(クリアして書き直す)

+ :読み取りおよび書き込み可能モードで開きます

t :テキストファイルとして開く (デフォルト、省略可能)

b :バイナリモードで開きます(説明を表示する必要があります)

 組み合わせ方法:

モデル 関数
rまたはrb ファイルを読み取り専用で開きます (ファイルは作成しません)
wまたはwb 書き込み用にファイルを開きます (ファイルの長さを 0 バイトに切り捨て (削除)、ファイルを作成します)
aまたはab ファイルを追加モード、つまり最後に内容を追加して開きます ファイルが存在しない場合は追加書き込み用のファイルを作成します
r+または rb+ 読み取りと書き込みのためにファイルを開きます (新しいファイルを作成しないでください)
w+または wb+ ファイルを読み取り可能、書き込み可能として開きます
(ファイルの長さを 0 バイトにする (削除)、ファイルを作成します)
a+または ab+ ファイルを追加として開き、ファイルを開いて最後にファイルを変更します(ファイルが存在しない場合は作成します)

2. ファイル fclose を閉じます。

定義: int fclose(FILE *fp);

戻り値:

        成功すると 0 を返します

        失敗した場合は 0 以外を返す

void test()
{
	FILE* fp = NULL;
	fp = fopen("test.txt", "r");
	if (fp = NULL)//文件不存在
	{
		perror("fopen");
		return;
	}
	fclose(fp);
}

3. fgetc fputc を 1 文字ずつ読み書きします

一度に1 バイトずつ書き込みます: fputc

関数定義: int fputc(int c, FILE *stream)

関数の説明: fputc は、c の値を stream で表されるファイルに書き込みます。

戻り値:
        出力が成功した場合は、出力のバイト値を返します。

        出力が失敗した場合はEOFを返します

EOF は、stdio.h ファイルで定義されたマクロ シンボル定数で、値は -1 です。EOF はテキストファイルでのみ有効です。

 hello world 文字列を記述します。

void test()
{
	FILE* fp = NULL;
	fp = fopen("test.txt", "w");
	if (fp = NULL)
	{
		perror("fopen");
		return;
	}
	char* file_data = "hello word";
	while (*file_data != '\0')
	{
		fputc(*file_data, fp);
		file_data++;
	}
	fclose(fp);
}

一度に1 バイトずつ読み取ります: fgetc

関数定義: int fgetc(FILE *stream);

関数の説明: fgetc は、stream でマークされたファイルからバイトを読み取り、バイト値を返します。

戻り値:t
の         場合:ファイルの最後まで読み込んでEOFを返すbの場合:ファイルの最後まで読み込ん         で、 feof関数(後述)で終了を判定する

 文字列を 1 つずつ読み取ります。

void test()
{
	FILE* fp = NULL;
	fp = fopen("test.txt", "r");
	if (fp = NULL)
	{
		perror("fopen");
		return;
	}
	while(1)
	{
		char ch = fgetc(fp);
		if (ch != EOF)
			break;
		printf("%c", ch);
	}
	fclose(fp);
}

4. 文字列を一度に読み書きする fgets fputs

文字列を書き込みます: int fputs(const char *s, FILE *stream)

文字列を読み取ります: char *fgets(char *s, int size, FILE *stream)

文字列(改行の終わり)を読み取り、ファイルデータの行を読み取ります

宛先配列の最初のアドレス、つまり s を正常に返します。

失敗した場合はNULLを返します

test.txt ファイル内のデータを読み取り test.txtファイルの下の b.txt に書き込むテスト プログラムが あります。

void test06()
{
    FILE *fp_r = fopen("test.txt", "r");
    if (fp_r == NULL)
    {
         perror("fopen");
         return;
    }
    FILE *fp_w = fopen("b.txt", "w");
    if (fp_w == NULL)
    {
        perror("fopen");
        return;
    }

    while (1)
    {
        char buf[128] = "";//存放读到的数据并写到b.txt中
        //读一行
        char *ret = fgets(buf, sizeof(buf), fp_r);
        if (ret == NULL)
        break;

        //写一行
        fputs(buf, fp_w);
    }

 fclose(fp_r);
 fclose(fp_w);
}

5. 一度に n ブロックのファイル データを読み書きする fread fwrite

块写:size_t fwrite(void *ptr, size_t size, size_t n, FILE *stream);

関数の説明: fwrite 関数は、ptr が指すメモリ内のデータを、stream でマークされたファイルに書き込みます。1 ブロックは size バイト、合計 n ブロックです。

ブロックライトメモリ上のデータを そのままディスクファイル書き込みます

戻り値:実際に書き込まれたブロック数

簡単な書き込みの例: 

#include <string.h>
typedef struct
{
    int num;
    char name[30];
}STU;
void test()
{
    STU A[3]={
   
   {1,"lucy"},{2,"bob"},{3,"张三",{4,"李四"}};
    int n = sizeof(hero) / sizeof(hero[0]);
    FILE *fp = fopen("S.txt", "w");
    if (fp == NULL)
    {
         perror("fopen");
        return;
     }
    fwrite(A, sizeof(A), n, fp);
    fclose(fp);
}

快读:size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

クイックリード: ディスクデータを そのままメモリ入力

戻り値:実際に読み取ったブロック全体の数: 1 ブロック未満はカウントされませんが、データは読み取られます。

ブロック読み取りインスタンス 

#include <string.h>
void test02()
{
    STU A[3];
    memset(A, 0, sizeof(A));
    FILE *fp = fopen("S.txt", "r");
    if (fp == NULL)
    {
        perror("fopen");
        return;
    }
    fread(A, sizeof(STU), 3, fp);
    int i = 0;
    for (i = 0; i < 3; i++)
    {
        printf("%d %s\n", A[i].num, A[i].name);
    }
    fclose(fp);
}

 6. 読み取りおよび書き込み fscanf fprintf のフォーマット

 1. fprintf をフォーマットして書き込みます (ファイル ポインタ、フォーマット文字列、出力リスト)

#include <string.h>
typedef struct
{
    int num;
    char name[30];
}STU;
void test()
{
    STU A[3]={
   
   {1,"lucy"},{2,"bob"},{3,"张三",{4,"李四"}};
    int n = sizeof(hero) / sizeof(hero[0]);
    FILE *fp = fopen("S.txt", "w");
    if (fp == NULL)
    {
         perror("fopen");
        return;
     }
    //格式化写
   int i = 0;
    for (i = 0; i < n; i++)
    {
        fprintf(fp, "%s %d \n", A[i].num, A[i].name);
    }

    fclose(fp);
}

2. フォーマットされた fscanf 読み取り (ファイル ポインタ、フォーマット文字列、出力リスト)

#include <string.h>
void test02()
{
    STU A[3];
    memset(A, 0, sizeof(A));
    FILE *fp = fopen("S.txt", "r");
    if (fp == NULL)
    {
        perror("fopen");
        return;
    }
    int i = 0;
    for (i = 0; i < 3; i++)
    {
        fscanf(fp, "%d %s",&A[i].num, A[i].name);
    }
    int i = 0;
    for (i = 0; i < 3; i++)
    {
        printf("%d %s\n", A[i].num, A[i].name);
    }
    fclose(fp);
}

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

デフォルトでは、ファイルはストリーム ポインタの順序で読み書きされ、ユーザーはストリーム ポインタを移動して読み書きの順序を変更することはできません

                             ランダム読み取りおよび書き込み: ユーザーはファイル ストリーム ポインターの位置を変更できます。

1. シーケンシャルな読み取りと書き込みでは、ランダムな読み取りと書き込みのケースが導入されます。

void test()
{
	FILE* fp = NULL;
	fp = fopen("test.txt", "w+");
	if (fp = NULL)
	{
		perror("fopen");
		return;
	}
	fpus("hello world", fp);//此时流指针指向该字符串末尾
	char buf[100] = "";
    //读时从流指针开始往后顺序读,会读不到字符串hello world
	fgets(buf, sizeof(buf), fp);
	printf("读到的数据:%s\n", buf);//无数据显示
	fclose(fp);
}

シーケンシャルな読み取りと書き込みにより、この問題は解決されます。ファイルを閉じて再度開いた後、ストリーム ポインタがリセットされます。ただし、ファイルは 2 回開かれ、2 回閉じられます。

void test()
{
	FILE* fp = NULL;
	fp = fopen("test.txt", "w+");
	if (fp = NULL)
	{
		perror("fopen");
		return;
	}
	fpus("hello world", fp);//此时流指针指向该字符串末尾
    //流指针复位
    fclose(fp);
    fp=fopen("test.txt","r");
    //读取数据
	char buf[100] = "";
	fgets(buf, sizeof(buf), fp);
	printf("读到的数据:%s\n", buf);
	fclose(fp);
}

2. ランダム読み取りおよび書き込み API

(1) 巻き戻しはファイル ストリーム ポインタをリセットします

void rewind(FILE *stream);

void test()
{
	FILE* fp = NULL;
	fp = fopen("test.txt", "w+");
	if (fp = NULL)
	{
		perror("fopen");
		return;
	}
	fpus("hello world", fp);//此时流指针指向该字符串末尾
    //复位文件流指针
    rewind(fp);
    //读取数据
	char buf[100] = "";
	fgets(buf, sizeof(buf), fp);
	printf("读到的数据:%s\n", buf);
	fclose(fp);
}

 (2) ftell はファイルストリームポインタからファイルヘッダまでのバイト数を返します。

長い ftell(FILE *stream);

void test()
{
	FILE* fp = NULL;
	fp = fopen("test.txt", "w+");
	if (fp = NULL)
	{
		perror("fopen");
		return;
	}
	fpus("hello world", fp);//此时流指针指向该字符串末尾
    //复位文件流指针
    long len=ftell(fp);
	printf("文件的大小:%ld\n", len);
	fclose(fp);
}

(3) fseek ファイルストリームポインタの位置決め

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

 wherece はストリーム ポインタの開始位置を特定します

ファイルはSEEK_SET 0                で始まります

                ファイル現在位置 SEEK_ CUR 1

                ファイルの終わりSEEK_END 2

offset:ストリーム ポインタのオフセット。正の数の場合は右へのオフセット (バイト単位) が負の数の場合、左へのオフセットになります。

ケース:ファイルデータを一度に読み込む

主な手順:

(1) ファイルストリームポインタを最後尾に配置する

(2) ftell はファイル ストリーム ポインタのオフセット (合計ファイル サイズ len) を返します。

(3) 合計ファイルサイズに応じて、ヒープ領域から len+1 個の領域を確保します。

(4) freadを使用してファイルデータを一括読み込み 

 実装コード:

#include <stdlib.h>
#include <string.h>
void test06()
{
    FILE *fp = fopen("c.txt", "r");
    if (fp == NULL)
    {
        perror("fopen");
        return;
    }

     fseek(fp, 0, 2);
     long len = ftell(fp);
    //复位文件流指针
    rewind(fp);
    printf("文件总大小:len=%ld\n", len);

     unsigned char *text = (unsigned char *)calloc(1, len + 1);
     fread(text, len, 1, fp);

     printf("%s\n", text);
     fclose(fp);

     //释放堆区空间(不是必须操作)
     if (text != NULL)
     {
         free(text);
        text = NULL;
     }
 }

8. ファイル暗号化ツール

main.c

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

int main(int argc ,char *argv[])
{
	while(1)
	{	
		


		int cmd=0;
		print_help();
		printf("请输入指令:");
		scanf("%d",&cmd);



		if(cmd==1)
		{
			char dest_file[31]="";
			char src_file[31]="";
			unsigned long file_length=0;
			char  *read=NULL;
			unsigned int password=0;
			//从键盘获取源文件和目的文件名字
			get_file_name(dest_file,src_file);
			
			//从文件中读出内容

			read = read_src_file(&file_length,src_file);
			//获取加密password
			printf("请输入密码:");
			scanf("%u",&password);
			//字符数组加密
			read=file_text_encrypt(read,file_length,password);
			
			//保存文件
			save_file(read,file_length,dest_file);
			

		}
		else if (cmd==2)
		{
			char dest_file[31]="";
			char src_file[31]="";
			unsigned long file_length=0;
			char  *read=NULL;
			unsigned int password=0;
			//从键盘获取源文件和目的文件名字
			get_file_name(dest_file,src_file);
			
			//从文件中读出内容

			read = read_src_file(&file_length,src_file);
			//获取加密password
			printf("请输入密码:");
			scanf("%u",&password);
			//字符数组加密
			read=file_text_decrypt(read,file_length,password);
			
			
			//保存文件
			save_file(read,file_length,dest_file);
			
		}
		else if (cmd==3)
		{
			break;
		}
		else
		{
			printf("输入指令出错!!!\n");
		}

	
	}
	
	return 0;
}

 楽しい

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

void print_help()
{
	printf("********1:加密文件***********\n");
	printf("********2:解密文件***********\n");
	printf("********3:退出程序***********\n");
}


void get_file_name(char * dest_file_name,char * src_file_name)
{
	printf("请输入源文件的名称:");
	scanf("%s",src_file_name);
	printf("请输入目的文件的名称:");
	scanf("%s",dest_file_name);
	return;
}


char *read_src_file(unsigned long  *file_length,char *src_file_name)
{
	char *data=NULL;
	FILE *fp;

	
	fp=fopen(src_file_name,"r");//只读的方式打开文件
	if(fp==NULL)
	{
		perror("fopen");
		return NULL;
	}
	
	//流指针go尾部
	fseek(fp,0,2);
	//流指针的偏移量
	*file_length = ftell(fp);
	//流指针复位
	rewind(fp);

	//申请空间保存文件
	data=(char *)calloc(1,*file_length);
	if(NULL==data)
	{
		perror("calloc");
		return NULL;
	}

	//一次性读
	fread(data,*file_length,1,fp);

	fclose(fp);
	return data;

}


char *file_text_encrypt(char * src_file_text,unsigned long int length,unsigned int password)
{
	char *data=NULL;
	unsigned int i=0;
	for(i=0;i<length;i++)
	{
		src_file_text[i] += password;
	}
	
	return src_file_text;

	
}


void save_file(char* text,unsigned long int length,char * file_name)
{	
	char *data=NULL;
	FILE *fp;
	fp=fopen(file_name,"w");
	if(NULL==fp)
	{
		perror("fp");
		return;
	}
	
	//写
	fwrite(text,length,1,fp);

	fclose(fp);
	if(text !=NULL)
	{
		free(text);
		text =NULL;

	}
	return;
}


char *file_text_decrypt(char * src_file_text,unsigned long int length,unsigned int password)
{
	char *data=NULL;
	unsigned int i=0;
	for(i=0;i<length;i++)
	{
		src_file_text[i] -= password;
	}
	
	return src_file_text;	
}

 楽しい。

#ifndef __FUN_H__
#define __FUN_H__

extern void print_help();
extern void get_file_name(char * dest_file_name,char * src_file_name);
extern char *read_src_file(unsigned long  *file_length,char *src_file_name);
extern char *file_text_encrypt(char * src_file_text,unsigned long int length,unsigned int password);
extern void save_file(char* text,unsigned long int length,char * file_name);
extern char *file_text_decrypt(char * src_file_text,unsigned long int length,unsigned int password);

#endif

おすすめ

転載: blog.csdn.net/m0_75045191/article/details/131750810