7.C標準ファイルI/O

43882 ワード

コアコンセプト


•ファイルには、すべてのデータが連続バイトで格納されます.
•ファイルを使用するには、ファイルfopen()を開く必要があります.ファイルを開くと、FILE構造体へのポインタが返されます.
•FILEポインタは開いているファイルを表します.
•fgetc()関数とfputc()関数を使用して、ファイルのI/Oを文字単位で行うことができます.
•fgets()関数とfputs()関数を使用して、テキストファイル内で行単位で読み取りまたは書き込みできます.
•fread()およびfwrite()関数は、一定サイズのデータを一度に読み取りまたは書き込みます.
•開いているファイルの中で、次に読み書きするファイル内の場所を現在のファイルの場所と呼び、ファイルの場所ポインタがそのファイルの現在のファイルの場所を指します.
•fseek()関数は、現在のファイルの場所を指定した場所に移動します.

7.1ファイルとファイルポインタ


システムコール

  • Unixカーネル要求サービスのプログラミングインターフェース
  • C関数のように呼び出すことができます.
  • アプリケーションは、システム呼び出しによってカーネルにサービスを要求する.

  • Cライブラリ関数

  • Cライブラリ関数は、通常、システム呼び出しの関数
  • を含む.
  • は、通常、内部でシステム呼び出しを行う.
  • ファイル


  • どうしてCプログラムにファイルが必要ですか?
    :変数に格納された情報は、実行終了時に保存されますが、ファイルに書き込むと永続的に保存できます.

  • Unixファイル
    :すべてのデータを連続バイトで格納します.
  • C言語におけるファイルタイプ

  • テキストファイル
  • ファイルで、人々が読むことができる文字を格納します.
  • テキストファイルでは、「1行の終了」を表す式は、ファイルが取得されたときにC内部で変換される.
  • バイナリファイル
  • は、すべてのデータをそのまま保持します.すなわち、
  • バイトを連続的に格納します.
  • バイナリファイルを使用すると、メモリに格納された変数値の形式でファイルに保存できます.
  • ファイルI/O

  • C言語のファイルI/Oプロセス
  • ファイルを開く:fopen()関数を使用する
    ->open()システムコール
  • ファイルを使用するには、ファイルを開く必要があります.
  • ファイルを開くと、FILE構造体へのポインタが返され、FILEポインタは開いているファイルを表します.
  • fopen()とopen()の違い:http://blog.yes24.com/blog/blogMain.aspx?blogid=ukyo&artSeqNo=36268172
  • FILE構造体:バッファへのポインタ、バッファサイズを指すストリームの情報を含む構造体.など、ファイルを開く現在の状態を表すフィールド変数があります.
  • 関数fopen():FILE fopen(const char filename,const charモード);
    :const char filename:ファイル名のポインタ
    :const char*モード:ファイルI/Oモード
  • ex)
    FILE *fp;
    fp = fopen("~/sp/text.txt","r");
    if(fp == NULL)
    {
    	printf("파일 열기 오류\n");
    }

  • ファイルI/O:各種ファイルI/O関数を使用

  • ファイルを閉じる:fclose()を使用する
    ->close()システムコール
    オフに成功した場合は0を返し、エラーが発生した場合はEOF(-1)を返します.
  • 実行方法:fclose(fp);

    7.2テキストファイル


    ファイルI/O関数



  • fgetc()関数:ファイルに文字単位を入力する
    fputc()関数:文字単位をファイルに出力する

  • int fgetc(FILE *fp)
    -getc、fgetc関数は、fpで指定したファイルから文字を読み出すことで返されます.
  • ファイルの末尾に達すると、EOF(-1)は
  • を返す.

  • int fputc(int c, FILE *fp)
    -putc、fputc関数はファイルにワード単位で出力される関数です
  • の戻り値で出力文字は
  • を返す.
  • の出力時にエラーが発生すると、EOF(-1)は
  • を返す.
    ex1) cat.c
    #include <stdio.h>
    
    /* 텍스트 파일 내용을 표준출력에 프린트 */
    
    int main(int argc, char *argv[])
    {
    
    	FILE *fp;
    	int c;
    
    	if (argc < 2) 
    	fp = stdin; // 명령줄 인수가 없으면 표준입력 사용
    
    	else fp = fopen(argv[1],"r"); // 읽기 전용으로 파일 열기
    
    	c = getc(fp); // 파일로부터 문자 읽기
    
    	while (c != EOF)
    	{
            putc(c, stdout); // 읽은 문자를 표준출력에 출력
    	c = getc(fp); // 파일로부터 문자 읽기
    	}
        
    	fclose(fp);
    	return 0;
    }
    
    ex2) copy.c
    #include <stdio.h>
    
    int main(int argc, char* argv[])
    {
    	char c;
    	FILE *fp1, *fp2;
    
    	if (argc!=3)
    	{
    	fprintf(stderr,"How to use : %s FILE1 FILE2\n",argv[0]);
    	return 1;
    	}
    	
        	// 첫번째 파일 읽기모드로 오픈
    	fp1= fopen(argv[1],"r");
    	
       	 // 파일열기 실패시 오류메시지 출력
    	if(fp1 == NULL)
    	{
    		fprintf(stderr,"Open %s  error!\n",argv[1]);
    		return 2;
    	}
    
    	// 두번째 파일 쓰기모드로 오픈
    	fp2 = fopen(argv[2], "w");
        
       	// 내용복사 
    	while((c= fgetc(fp1))!=EOF)
    	{
    		fputc(c,fp2);
    	}
    
    	fclose(fp1);
    	fclose(fp2);
    
    	return 0;
    }
    
  • その他のファイル関連関数

  • int feof(FILE *fp)
    :ファイルポインタfpがファイルの末尾を検出した場合、ゼロ以外の値を返し、ファイルの末尾の場合、0を返します.

  • int fflush(FILE *fp)
    :記録されていないバッファに残っているデータをfp指向の出力ファイルに送信します.
    バッファクリア機能を実行する関数
  • 行単位の入出力

  • fgets()関数とfputs()関数
    :テキストファイルに行単位で読み取りまたは書き込みできます.
  • ex) line.c
    #include <stdio.h>
    #include <stdlib.h>
    
    #define MAXLINE 80
    
    int main(int argc, char* argv[])
    {
    	FILE *fp;
    	int line = 0;
    	char buffer[MAXLINE];
    
    	if(argc!=2)
    	{
    		fprintf(stderr, "사용법:line 파일이름\n");
    
    		exit(1);			
    	}
    
    	if( (fp = fopen(argv[1],"r")) ==NULL)
    	{
    		fprintf(stderr, "파일 열기 error \n");
    		exit(2);
    	}
    
    	while(fgets(buffer,MAXLINE,fp)!=NULL)
    	{
    		line++;
    		printf("%3d %s", line,buffer);
    	}
    
    
    	fclose(fp);
    	return 0;
    }
    

    フォーマットI/O


  • fprintf()関数
    データはprintf()関数と同様にファイルに出力できます.

  • fscanf()関数
    :scanf()関数と同じ方法でファイルからデータを取得できます.
  • ex1) fprintf.c
    #include <stdio.h>
    #include "student.h"
    /* 학생 정보를 읽어 텍스트 파일에 저장한다. */
    int main(int argc, char* argv[])
    {
    	struct student rec;
    	FILE* fp;
    	
    	if (argc != 2) {
    	fprintf(stderr, "사용법: %s 파일이름\n", argv[0]);
    	return 1; 
    	}
    	
        	// argv[1]를 쓰기모드로 오픈 
    	fp = fopen(argv[1],"w");
    	
    	printf("%-9s %-7s %-4s\n","학번", "이름", "점수");
    	
        	// 학번 이름 점수 입력받고
    	while(scanf("%d %s %d", &rec.id, rec.name, &rec.score)==3)
    	// fp에 저장 
         	   fprintf(fp,"%10d %6s %6d\n",rec.id,rec.name,rec.score);
    	
            fclose(fp);
    	return 0;
    }
    
    

    ex2 ) fscan.c
    #include <stdio.h> 
    #include "student.h"
    /* 텍스트 파일에서 학생 정보를 읽어 프린트한다. */ 
    
    int main(int argc, char* argv[]) { 
    
    struct student rec;
    FILE *fp;
    
    if (argc != 2) {
    fprintf(stderr, "사용법: %s 파일이름\n", argv[0]);
    return 1; 
    }
    
    fp = fopen(argv[1], "r");
    printf("%-9s %-7s %-4s\n", "학번", "이름", "점수"); 
    
    while (fscanf(fp,"%d %s %d", &rec.id, rec.name, &rec.score)==3) 
    printf("%10d %6s %6d\n", rec.id, rec.name, rec.score);
    
    fclose(fp);
    return 0;
    }
    
    

    7.3バイナリファイル


    バイナリファイル
  • は、すべてのデータをそのまま保持します.すなわち、
  • バイトを連続的に格納します.
  • バイナリファイルを使用すると、メモリに格納された変数値の形式でファイルに保存できます.
  • fopen():バイナリファイルを開く

    ブロックレベルI/O


  • fread()とfwrite()
    :一度に一定サイズのデータを読み書きするI/O関数

  • int fread(void buf, int size, int n, FILE fp);
    :fpが指すファイルからsizeサイズのn個のブロック(連続するバイト)を読み出し、バッファポインタbufが指す位置に格納し、読み出したブロック数を返す.

  • int fwrite(const void buf, int size, int n, FILE fp);
    :ファイルポインタfpで指定したファイルをバッファbufに格納されたn個のsizeサイズのブロック(連続バイト)に書き込み、出力に成功したブロック数を返します.

  • 基本的な考え方
    :どのデータ型のデータも、連続バイトとして解析され、ファイルに保存されます.
  • :ファイルに格納されているデータを連続バイトで読み込み、元の変数に順番に格納して元のデータを復元します.
    recを保存
    
    struct student rec;
    FILE *fp = fopen("stfile","wb");
    
    ...
    fwrite(&rec,sizeof(rec),1,fp);
    ex) stcreate1.c
    
    #include <stdio.h> 
    #include "student.h"
    
    int main(int argc, char* argv[]) 
    { 
    struct student rec;
    FILE *fp;
      if (argc != 2) {
      fprintf(stderr, "사용법: %s 파일이름\n",argv[0]);
      exit(1); 
      }
      
      // argv[1]을 wb-> 읽기+쓰기모드로 오픈
    fp = fopen(argv[1], "wb");
    printf("%-9s %-7s %-4s\n", "학번", "이름", "점수"); 
    
    // 정보 입력받고
    while (scanf("%d %s %d", &rec.id, rec.name, &rec.score) == 3) 
    // rec버퍼에 기록한 내용을 파일 포인터 fp가 가리키는곳에 기록
    fwrite(&rec, sizeof(rec), 1, fp);
    fclose(fp);
    exit(0);
    }

    7.4ランダムアクセス


    ファイル内の場所


  • 現在のファイルの場所
    :開いているファイルの次の読み取りまたは書き込み先のファイルの場所

  • ファイル位置ポインタ
    :システムにファイルを保存する現在の場所
  • fseek(FILE *fp, long offset, int mode)
    ファイル位置ポインタを任意に設定できる関数
  • rewind(FILE *fp)
    現在のファイルの場所をファイルの先頭に配置します.
  • ftell(FILE *fp)
    •ファイルの現在のファイル位置を示すファイル位置フラグ値を返します.


  • 変更プロセスの記録



    7.5緩衝


    Cライブラリバッファを使用する目的


  • ディスクI/Oの削減
    ->read()関数とwrite()関数の呼び出しを最小化

  • 最適なサイズでI/Oを実行

  • システムパフォーマンスの向上
  • Cライブラリバッファ


    1.完全バッファ方式

  • バッファが満杯の場合、実際のI/Oは
  • である.
  • ディスクファイルI/O
  • 2.ラインバッファ方式


    実際のI/O は、
  • 改行(改行)で実行する.
  • 端末I/O(stdin,stdout)
  • 3.バッファ未使用

  • バッファは使用されません.
  • 標準エラー(stderr)
  • ex)
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define _IO_UNBUFFERED 2
    #define _IO_LINE_BUF 0x200
    
    int main(int argc, char* argv[])
    {
    	FILE *fp;
     
    	if(!strcmp(argv[1],"stdin")) // 표준 입력
    	{
    		fp = stdin;
    		printf(" 한 글자 입력 : ");
    		if(getchar() == EOF) perror("getchar");
    	}
    
    	else if(!strcmp(argv[1],"stdout")) // 표준 출력
    	{
    		fp = stdout;
    	}
    
    	else if(!strcmp(argv[1],"stderr")) // 표준 에러
    	{
    		fp = stderr;
    	}
    
    	else if( (fp= fopen(argv[1],"r")) == NULL)
    	{
    		perror("fopen");
    		exit(1);
    	}
    	else if(getc(fp)==EOF) perror("getc");
    
    
    	printf("스트림 = %s ",argv[1]);
    
    	if(fp-> _flags & _IO_UNBUFFERED)
    	{
    		printf("버퍼 미사용");
    
    	}
    	else if( fp->_flags & _IO_LINE_BUF)
    	{
    		printf("줄 버퍼 사용");
    	}
    	else
    	{
    		printf("완전 버퍼 사용");
    	}
    
    	printf(", 버퍼 크기 = %d\n",fp->_IO_buf_end - fp->_IO_buf_base);
    	exit(0);
    
    
    }

    バッファ管理方法の変更(setbuf()/setvbuf()

    #include <stdio.h>
    
    void setbuf (FILE *fp, char *buf );
    int setvbuf (FILE *fp, char *buf, int mode, size_t size );
    
  • コールタイム
    :ストリームが開いたら、I/O操作を実行する前に呼び出す必要があります.
  • 1. void setbuf (FILE fp, char buf )


    :バッファを有効/無効にできます.
    :bufがNULLの場合、バッファは使用されません
    :bufがBUFSIZサイズの空間を指す場合、完全/行バッファ

  • エンドデバイスラインバッファ

  • そうでなければ、完全にバッファリング

    2. int setvbuf (FILE fp, char buf, int mode, size_t size )


    :バッファの使用方法の変更

  • 正常に0を返し、失敗してNon-0を返します.

  • mode :
    IOFBF:フルバッファ
    IOLBF:ラインバッファ
    IONBF:バッファ未使用

  • modeがIONBFの場合、bufとsizeは無視されます.

  • モードがIOFBFまたはIOLBFの場合.
    bufがNULLの場合、ライブラリは適切なサイズ割り当てを使用します.
    bufがNULLでない場合、bufは同じサイズの空間を使用します.