프로그램 상에서 파일에 저장되어 있는 데이터를 참조하길 원할 때, 구현한 프로그램과 참조할 데이터가 저장되어 있는 파일 사이에 데이터가 이동할 수 있는 다리를 놓아야 한다.

이를 스트림이라고 한다.


스트림은 운영체제에 의해서 형성되는 소프트웨어적인 상태를 의미하는 것이다.


fopen


스트림을 형성할 때 호출하는 함수. 이 함수의 호출을 통해 프로그램 상에서 파일과의 스트림이 형성된다.


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

- 성공 시 해당 파일의 FILE 구조체 변수의 주소 값, 실패 시 NULL 포인터 반환


첫 번째 인자 : 파일의 이름

두 번째 인자 : 형성할 스트림의 종류에 대한 정보


fopen 함수 호출 시 일어나는 일들


1. fopen 함수가 호출되면 FILE 구조체 변수가 생성된다.

2. 생성된 FILE 구조체 변수에는 파일에 대한 정보가 담긴다.

3. FILE 구조체의 포인터는 사실상 파일을 가리키는 '지시자' 역할을 한다.


입력스트림과 출력스트림


입력스트림 : 데이터를 파일로부터 읽어들이기 위한 스트림


출력 스트림 : 데이터를 파일에 쓰기 위한 출력 스트림


fopen 함수 호출방법


첫 번째 전달 인자 : 스트림을 형성할 파일의 이름

두 번째 전달 인자 : 형성하고자 하는 스트림의 종류


출력 스트림의 fopen 함수 호출


FILE * fp = fopen("data.txt", "wt");    // 출력 스트림의 형성

- 파일 data.txt와 스트림을 형성하되 wt모드로 스트림을 형성해라    // w (write), t ( text)


입력 스트림의 fopen 함수 호출


FILE * fp = fopen("data.txt", "rt");    // 출력 스트림의 형성

- 파일 data.txt와 스트림을 형성하되 rt모드로 스트림을 형성해라    // r (read), t ( text)


fopen 함수 호출 시 파일이 개방(오픈) 되었다 라고 표현하는 것이 일반적인 표현


ex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<stdio.h>
#include<stdlib.h>
 
int main()
{
    FILE * fp = fopen("/Users/gimtaehyeon/Desktop/test.txt","wt");
    
    if(fp == NULL)
    {
        printf("파일 오픈 실패");
        return -1;
    }
    
    fputc('A',fp);
    fputc('B',fp);
    fputc('C',fp);
    
    fclose(fp);
    
    return 0;
}
 

cs

출력결과



6 행 : test.txt와의 출력 스트림을 형성하고 있다. ( 예제처럼 경로를 지정할 수 있다.)

11행 : 비정상적 종료를 의미하기 위해 -1을 반환

18행 : 스트림의 종료


이제 fp는 파일 test.txt를 지칭하는 포인터가 된다. 따라서 다음의 문장이 실행되면,


fputc('A', fp); 


fp가 지칭하는 파일 test.txt에 문자 A가 저장된다. 


스트림의 소멸을 요청하는 함수


fclose

int fclose(FILE * stream);

- 성공 시 0, 실패 시 EOF 반환


fclose를 써줘야 하는 이유!!

- 운영체제가 할당한 자원의 반환

 => 실제로 스트림을 형성하는 주체는 운영체제이다. 운영체제는 스트림의 형성을 위해 시스템의 자원(메모리)을 항당한다.  그런데 이 자원은 파일을 닫아주지 않은면 할당된 채로 남아있게 되어, 그만큼의 자원손실을 초래한다.


- 버퍼링 되었던 데이터의 출력

 => 파일 스트림의 경우에도 중간에 입출력 버퍼가 존재한다. 입출력 버퍼로 인해 성능의 향상을 도모하고 있다. 때문에 fputc와 같은 함수의 호출로 데이터를 파일로 전송한다고 해서 파일에 바로 저장되는게 아니라, 출력버퍼에 저장 후 운영체제가 정해놓은 버퍼링 방식에 따라 뒤늦게 파일에 저장이 된다.

만약 A와 B가 출력버퍼에 존재하는 상태에서 컴퓨터의 전원이 꺼졌다고 가정해보자. 이 때, 문자 A와 B는 파일에 저장되지 않는다. 하지만 fclose 함수의 호출을 통해 파일을 닫아주면 출력버퍼에 저장되어 있던 데이터가 파일로 이동하면서 출력버퍼는 비워지게 된다.


스트림을 종료하지 않고 버퍼만 비우고 싶을 때에는 fflush 함수를 호출하면 된다.


- 출력버퍼를 비운다는 것은 출력버퍼에 저장된 데이터를 목적지로 전송한다는 의미

- 입력버퍼를 비운다는 것은 입력버퍼에 저장된 데이터를 소멸시킨다는 의미

- fflush 함수는 출력버퍼를 비우는 함수

- fflush 함수는 입력버퍼를 대상으로 호출 불가능


int main()

{

FILE * fp = fopen("data.txt", "wt");    // 출력 스트림 생성

. . . .

fflush(fp);    // 출력버퍼를 비워라

}


파일 스트림의 입력버퍼를 비우는 함수는 필요가 없다. 파일에 저장된 데이터는 원할 때 언제든지 읽을 수 있을 뿐만 아니라, 파일 대상의 입력버퍼를 비워야만 하는 상황이 존재하지 않는다. 


ex)파일로부터 데이터 읽기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include<stdio.h>
#include<stdlib.h>
 
int main()
{
    int ch;
    int i;
    FILE * fp = fopen("/Users/gimtaehyeon/Desktop/test.txt","rt");
    
    if(fp == NULL)
    {
        printf("파일 오픈 실패");
        return -1;
    }
    
    for(i=0;i<3;i++)
    {
        ch=fgetc(fp);
        printf("%c \n", ch);
    }
    fclose(fp);
    
    return 0;
}
 

cs

출력결과

A 

B 

C 


8행 : 데이터를 읽기 위한 입력 스트림이 형성된다.

16 ~ 20행 : 저장한 세 개의 문자를 읽어서 출력하고 있다.


파일의 개방 모드


fopen 함수의 두 번째 인자로 "wt", "rt"를 전달하였지만, 형성할 수 있는 스트림의 종류는 훨씬 더 다양하다.

두 가지 기준을 통해 스트림을 구분하게 된다.


1. 읽기 위한 스트림인지, 쓰기 위한 스트림인지

2. 텍스트 데이터를 위한 스트림인지, 바이너리 데이터를 위한 스트림인지


스트림을 구분하는 기준 1: 읽기 위한 스트림 ? 쓰기 위한 스트림 ?


데이터의 이동 방향을 기준으로 다음과 같이 네 가지로 구분할 수 있다.


- data read stream            // 읽기만 가능

- data write stream           // 쓰기만 가능

- data append stream          // 쓰되 덧붙여 쓰기만 가능

- data read / write stream    // 읽기, 쓰기 모두 가능


C언어는 총 6가지로 스트림을 세분화한다.


모드      스트림의 성격                파일이 없으면 ?

r        읽기 가능                   에러

w        쓰기 가능                   생성

a        파일의 끝에 덧붙여 쓰기 가능     생성

r+       읽기 / 쓰기 가능             에러

w+       읽기 / 쓰기 가능             생성

a+       읽기 / 덧붙여 쓰기 가능        생성


스트림의 특성과 일치하는 파일의 개방 모드를 선택하면 되고, 모드의 이름이 fopen 함수의 두 번째 인자가 된다. 


여기서 r+, w+, a+보다는 r, w, a 를 사용하는 것이 좋다.

+가 있는 모드를 사용할 경우 읽기에서 쓰기, 쓰기에서 읽기로 작업을 변경할 때마다 메모리 버퍼를 비워줘야 하고, 잘못된 사용의 위험성도 따른다.

( 스트림은 데이터의 흐름을 물의 흐름에 비유한 것이다. 한쪽 방향으로만 흐르지, +모드처럼 양방향으로 흐른다면 골치아프다 )



스트림을 구분하는 기준 2 : 텍스트파일, 바이너리파일


도서목록, 슈퍼마켓 물품 가격, 주민번호 : 문자 데이터


음원파일, 영상파일 : 바이너리 데이터


사람이 인식할 수 있는 문자를 담고 있는 파일은 텍스트파일 !

컴퓨터가 인식할 수 있는 데이터를 담고 있는 파일은 바이너리파일 !

데이터의 입출력을 위해 스트림을 형성할 때 이와 관련해서 특별히 신경 쓸 부분은 문장의 끝을 의미하는 개행의 표현방식!

누구나 한 장의 흰 종이에 문자 A 하나만을 표시할 수는 있다. 그러나 그 누구도 아무런 약속 없이 흰 종이에 개행 하나만을 표시할 수는 없다.

그래서 C언어에서는 개행을 \n으로 표현하도록 약속하였다. 이는 C언어만의 약속이다.



Windows - \r\n

Mac - \r

Unix / Linux - \n


이렇듯 운영체제마다 차이가 있기 때문에 개행 문자가 포함도는 텍스트 데이터의 저장에는 주의가 필요하다.

C프로그램의 실행과정에서 \n이 Window의 파일에 저장될 때에는 \r\n, Mac의 파일에 저장될 때에는 \r로 저장되어야 해당 운영체제에서 개행으로 인식이 된다. 이 형태의 변환을 대신해주는 것이 텍스트 모드의 개방이다.!

텍스트 모드로 개방하면 형태의 변환이 자동으로 이뤄진다. 


C에서 \n을 파일에 저장하면 \r\n으로 변환되어 저장

파일에 저장된 \r\n을 C에서 읽으면 \n으로 변환되어 읽혀짐


그저 텍스트 모드로 개방을 하면 자동으로 변환이 된다. ( rt, wt, at, r+t, w+t, a+t )


반대로 바이너리 파일은 이러한 형태의 변환이 일어나면 안되기 때문에 바이너리 모드로 파일을 개방해야 한다.(rb, wb, ab, r+b, w+b, a+b)


파일 입출력 함수


int fputc(int c, FILE * stream);    // 문자 출력

int fgetc(FILE * stream);    // 문자 입력

int fputs(const char * s, FILE * stream);    // 문자열 출력

char * fgets(char * s, int n, FILE * stream);    // 문자열 입력


ex) 파일을 생성해 문자와 문자열 저장하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<stdio.h>
 
int main()
{
    FILE * fp ;
    
    if((fp = fopen("/Users/gimtaehyeon/Desktop/test1.txt","wt"))==NULL)
    {
        fputs("파일 오픈 실패!",stderr);
        return -1;
    }
    
    fputc('A', fp);
    fputc('B', fp);
    fputs("My name is yoon \n", fp);
    fputs("Your name is Kim \n", fp);
    
    fclose(fp);
    
    return 0;
}
 

cs


13, 14행 : 문자열에는 개행문자도 포함되어 있다. 따라서 7행에 보이듯이 반드시 텍스트 모드로 파일을 개방해야 한다.


ex) 생성된 파일에 저장된 데이터 읽기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<stdio.h>
 
int main()
{
    char str[30];
    int ch;
    FILE * fp ;
    
    if((fp = fopen("/Users/gimtaehyeon/Desktop/test1.txt","rt"))==NULL)
    {
        fputs("파일 오픈 실패!",stderr);
        return -1;
    }
    
    ch = fgetc(fp);
    printf("%c \n",ch);
    ch = fgetc(fp);
    printf("%c \n",ch);
    
    fgets(str, sizeof(str), fp);    // \n을 만날 때까지 read
    printf("%s", str);
    fgets(str, sizeof(str), fp);    // \n을 만날 때까지 read
    printf("%s", str);
    
    fclose(fp);
    
    return 0;
}
 

cs

출력결과

A 

B 

My name is yoon 

Your name is Kim 


"My name is yoon \n"

"Your name is Kim \n"


문자열이 파일에 저장될 때에는 문자열의 끝을 의미하는 널 문자는 저장되지 않기 때문에, 개행을 기준으로 문자열을 구분한다.

총 두개의 문자열을 읽어 들이기 위해 fgets 함수를 두 번 호출했는데, 매번 호출이 될 때마다 개행 문자를 만날 때까지 문자열을 읽어 들이게 된다. 따라서 fgets 함수의 호출을 통해서 읽어 들일 문자열의 끝에는 반드시 \n 문자가 존재해야 한다.


feof : 파일의 끝에 도달했는지 확인하는 함수 끝에 도달시 0이 아닌 값 반환

int feof(FILE * stream);


ex) 파일 복사 프로그램 (문자단위로)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<stdio.h>
 
int main()
{
    FILE * fp1 = fopen("/Users/gimtaehyeon/Desktop/test1.txt","rt");
    FILE * fp2 = fopen("/Users/gimtaehyeon/Desktop/test2.txt","wt");
    
    if(fp1 == NULL || fp2 == NULL)
    {
        puts("파일 오픈 실패");
        return -1;
    }
    int ch;
    
    while((ch=fgetc(fp1))!=EOF)
        fputc(ch, fp2);
    
    if(feof(fp1)!=0)
        puts("파일 복사 완료");
    else
        puts("파일 복사 실패");
    
    fclose(fp1);
    fclose(fp2);
    
    return 0;
}
 

cs


15행 : 파일의 내용을 한 문자씩 복사하여 16행 : fp2에 붙여넣고 있다. 이는 EOF를 반환할 때까지 계속되는데, fgets 함수는 파일의 끝에 도달을 해서 더 이상 읽을 데이터가 없거나 오류가 발생하는 경우에 EOF를 반환한다.


18행 : fgetc 함수가 EOF를 반환했다고 해서 무조건 파일의 끝에 도달한 것이 아니라 오류가 발생하는 경우에도 EOF가 반환된다. feof 함수 호출을 통해 EOF 반환원인을 확인한다.


ex) 파일 복사 프로그램 (문자열 단위로)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<stdio.h>
 
int main()
{
    char str[30];
    FILE * fp1 = fopen("/Users/gimtaehyeon/Desktop/test1.txt","rt");
    FILE * fp2 = fopen("/Users/gimtaehyeon/Desktop/test2.txt","wt");
    
    if(fp1 == NULL || fp2 == NULL)
    {
        puts("파일 오픈 실패");
        return -1;
    }
    
    while(fgets(str, sizeof(str), fp1)!=NULL)
    {
        fputs(str, fp2);
    }
    
    if(feof(fp1)!=0)
        puts("파일 복사 완료!");
    else
        puts("파일 복사 실패!");
    
    fclose(fp1);
    fclose(fp2);
    
    return 0;
}
 

cs


fgets 함수는 파일의 끝에 도달해서 더 이상 읽을 데이터가 존재하지 않거나 오류가 발생하는 경우 NULL을 반환한다.

때문에 파일복사의 성공을 확인하기 위해 feof 함수를 호출하였다.


바이너리 데이터의 입출력 : fread, fwrite


fread() 입력

=> 성공 시 전달인자 count, 실패 또는 파일의 끝 도달 시 count보다 작은 값 반환


int buf[12];

fread((void*)buf, sizeof(int), 12, fp);    // fp는 FILE 구조체 포인터


" fp로부터 sizeof(int)크기의 데이터 12개를 읽어들여 배열 buf에 저장해라 "


이 함수는 실제로 읽어 들인 데이터의 갯수를 반환하는데, 위 문장은 sizeof(int)크기의 데이터를 12개 읽어 들이는 경우이니, 함수의 호출이 성공을 하고 요청한 분량의 데이터가 모두 읽혀지면 12가 반환된다.


반면 함수의 호출이 성공을 했지만, 파일의 끝에 도달을 해서 12개를 모두 읽어 들이지 못했거나 오류가 발생하는 경우에는 12보다 작은 값이 반환된다. 


fwrite() 출력

=> 성공 시 전달인자 count, 실패 시 count보다 작은 값 반환


int buf[7] = {1,2,3,4,5,6,7};

fwrite((void*)buf, sizeof(int), 7, fp);


" sizeof(int) 크기의 데이터 7개를 buf로 부터 읽어서 fp에 저장해라 "


ex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include<stdio.h>
 
int main()
{
    char str[20];
    int readCnt;
    FILE * src = fopen("/Users/gimtaehyeon/Desktop/src.bin","rt");
    FILE * des = fopen("/Users/gimtaehyeon/Desktop/des.bin","wt");
    
    if(src == NULL || des == NULL)
    {
        puts("파일 오픈 실패!");
        return -1;
    }
    
    while(1)
    {
        readCnt = fread((void*)str, 1sizeof(str), src);
        
        if(readCnt < sizeof(str))
        {
            if(feof(src) != 0)
            {
                fwrite((void*)str, 1, readCnt, des);
                puts("파일 복사 완료");
                break;
            }
            else
                puts("파일 복사 실패");
                break;
        }
        fwrite((void*)str, 1sizeof(str), des);
    }
    
    fclose(src);
    fclose(des);
    
    return 0;
}
 

cs


7,8행 : 바이너리 모드로 파일을 개방

18행 : fread 함수를 이용해서 파일로부터 데이터를 읽고 있따. 두 번째 전달인자가 1, 세번째 전달인자가 sizeof(str)이니, 읽어 들이는 데이터의 크기는 총 1 * sizeof(str) 바이트가 된다.

20행 : 이 if문은 fread 함수가 sizeof(str)의 반환 값보다 작은 값을 반환 했을 때 '참'이 된다. 그런데 이는 오류가 발생했거나 파일의 끝에 도달한 상황이니 feof 함수의 호출을 통해 어떤 상황인지 판단해야 한다.

22 ~ 27행 : 파일의 끝에 도달해서 sizeof(buf)의 반환 값보다 적은 수의 바이트가 읽혀졌을 때 실행되는 영역이다. 비록 적은 수의 바이트가 읽혀졌다 할지라도 이 역시 파일의 일부므로 fwrite 함수호출을 통해 복사를 해야 한다. 그래서 24행에서 마지막 데이터를 출력하고 있다.

32행 : 18행에서 읽어 들인, 배열 str을 꽉 채운 데이터를 그대로 파일에 저장하고 있다.


텍스트 데이터와 바이너리 데이터를 동시에 입출력 하기


텍스트 데이터인 문자와 문자열, 바이너리 데이터인 int형 정수 하나를, 하나의 파일을 대상으로 동시에 입출력 해야 하는 상황


서식에 따른 데이터 입출력 : fprintf, fscanf


printf, scanf 함수와 유사하지만 콘솔이 아닌 파일이라는 점에서 차이가 있다.


fprintf 함수 호출방법


char name[10]="홍길동";    // 텍스트 데이터

char sex = 'M';          // 텍스트 데이터

int age = 24;            // 바이너리 데이터

fprintf(fp, "%s %c %d", name, sex, age);    // fp는 FILE 구조체 포인터


첫 번째 전달 인자 FILE 구조체의 포인터가 지칭하는 파일로 출력이 이뤄진다. fprintf함수 호출 문장도 두 번째 이후의 전달인자를 통해 다음 문자열이 생성


" 홍길동 M 24 "


이렇게 만들어진 문자열이 첫 번째 전달인자가 가리키는 파일에 저장이 된다. (텍스트 데이터 + 바이너리 데이터)


ex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<stdio.h>
 
int main()
{
    char name[10];
    char sex;
    int age;
    
    FILE * fp = fopen("/Users/gimtaehyeon/Desktop/test.txt","wt");
    int i;
    
    for(i=0;i<3;i++)
    {
        printf("이름 성별 나이 입력: ");
        scanf("%s %c %d", name, &sex, &age);
        getchar();  // 버퍼에 남아있는 \n의 소멸을 위해서
        fprintf(fp, "%s %c %d", name, sex, age);
    }
    
    fclose(fp);
 
    return 0;
}
 

cs

출력결과

이름 성별 나이 입력: taehyun M 26

이름 성별 나이 입력: heeeun F 26

이름 성별 나이 입력: ok M 25


test 파일에 내가 입력한 데이터가 저장되었음을 확인할 수도 있다. 하지만 fscanf 함수의 호출을 통해서 확인하기로 한다.


fscanf 호출방법


char name[10];

char sex;

int age;

fscanf(fp, "%s %c %d", name, &sex, &age);


첫 번째 인자로 전달된 포인터가 지징하는 파일로부터 데이터를 읽어들인다. 그리고 fscanf 함수는 파일의 끝에 도달하거나 오류가 발생하면 EOF를 반환한다.


ex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<stdio.h>
 
int main()
{
    char name[10];
    char sex;
    int age;
    
    FILE * fp = fopen("/Users/gimtaehyeon/Desktop/test.txt","rt");
    int ret;
    
    while(1)
    {
        ret = fscanf(fp, "%s %c %d", name, &sex, &age);
        if(ret==EOF)
            break;
        printf("%s %c %d \n", name, sex, age);
    }
        
    fclose(fp);
 
    return 0;
}
 

cs

출력결과

taehyun M 26 

heeeun F 26 

ok M 25 


구조체 변수의 입출력


typedef struct

{

char name[10];

char sex;

int age;

}Friend;


구조체 변수를 통째로 저장하고 통째로 읽어들일 수 있는 방법은 구조체 변수를 하나의 바이너리 데이터로 인식하고 처리하면 가능하다. 그러면 fwrite 함수를  통해 통째로 저장하고, fread 함수를 통해 통째로 복원할 수 있다.


ex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<stdio.h>
 
typedef struct
{
    char name[10];
    char sex;
    int age;
}Friend;
 
int main()
{
    FILE * fp;
    Friend myfren1;
    Friend myfren2;
    
    /** file write **/
    fp = fopen("/Users/gimtaehyeon/Desktop/friend.bin","wb");
    printf("이름, 성별, 나이 순 입력: ");
    scanf("%s %c %d", myfren1.name, &(myfren1.sex), &(myfren1.age));
    fwrite((void*)&myfren1, sizeof(myfren1), 1, fp);
    
    fclose(fp);
    
    /** file read **/
    fp = fopen("/Users/gimtaehyeon/Desktop/friend.bin","rb");
    fread((void*)&myfren2, sizeof(myfren2), 1, fp);
    printf("%s %c %d \n", myfren2.name, myfren2.sex, myfren2.age);
    
    fclose(fp);
 
    return 0;
}
 

cs

출력결과

이름, 성별, 나이 입력: taehyun M 26

taehyun M 26 


17행 : 구조체 변수를 바이너리 형태로 저장하기 위해 바이너리 모드로 파일을 개방

20행 : fwrite 함수는 데이터를 바이트 단위로 단순저장하기 때문에 이렇든 구조체 변수를 통째로 저장할 수 있다.

25행 : 바이너리 모드에서 저장된 데이터를 읽어야 하므로 바이너리 모드로 파일을 개방

26행 : 앞서 20행에서 fwrite 함수를 호출했던 것과 유사하게 fread 함수를 호출하여 통째로 구조체 변수를 복원할 수 있다.


파일 위치 지시자

경우에 따라 파일의 중간 또는 ㅁ지막 부분에 저장된 데이터의 일부를 읽어야 하는 경우 사용하는 것


1. FILE 구조체의 멤버 중 하나

2. 파일의 특정 위치를 가리킨다.

3. 어디까지 읽었는지, 어디까지 썼는지의 위치정보 저장

4. read / write 의 정보를 가지고 있다.


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

" stream으로 전달된 파일 위치 지시자를 wherefrom에서부터 offset 바이트 만큼 이동시켜라 "


wherefrom 매개변수에 전달될 수 있는 상수


SEEK_SET(0) -> 파일 맨 앞에서부터 이동

SEEK_CUR(1) -> 파일 현재 위치에서부터 이동

SEEK_END(2) -> 파일 맨 끝에서부터 이동 ( 마지막 문자가 아닌 파일을 끝을 의미하는 EOF를 가리킨다.)


2번째 인자 long offset 매개변수에 양수를 넣으면 오른쪽(앞으로), 음수를 넣으면 왼쪽(뒤로) 이동한다.


ex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<stdio.h>
 
int main()
{
    /* 파일생성 */
    FILE * fp;
    fp = fopen("/Users/gimtaehyeon/Desktop/test2.txt","wt");
    fputs("123456789",fp);
    fclose(fp);
    
    /* 파일개방 */
    fp = fopen("/Users/gimtaehyeon/Desktop/test2.txt","rt");
    int ch;
    /*SEEK_END test*/
    fseek(fp, -2, SEEK_END);
    putchar(fgetc(fp));
    
    /*SEEK_SET test*/
    fseek(fp, 2, SEEK_SET);
    ch = fgetc(fp);
    printf("%c",ch);
    
    /*SEEK_CUR test*/
    fseek(fp, 2, SEEK_CUR);
    ch = fgetc(fp);
    printf("%c",ch);
    
    fclose(fp);
    
    return 0;
}
 

cs

출력결과

836


15행 : 파일의 끝(EOF)에서 앞으로 두 칸 이동하니, 파일 위치 지시자는 8을 가리킨다.

19행 : 파일의 첫 번째 데이터인 1에서부터 두 칸 이동하니, 파일 위치 지시자는 3을 카리킨다. 그후 19행에서 3을 출력 후엔 파일 위치 지시자는 4를 가리키게 된다.

24행 : 파일 취지 지시자는 4를 기리키는데, 현 위치에서 뒤로 2칸 이동하니, 파일 위치 지시자는 6을 가리킨다.


파일 위치 지시자의 위치 : ftell

파일 위치 지시자의 위치를 확인하는 함수


long ftell(FILE * stream);


첫 번째 바이트를 가리킬 경우 0을, 세 번째 바이트를 가리킬 경우 2를 반환한다.


ex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<stdio.h>
 
int main()
{
    long fpos;
    int i;
    
    /* 파일생성 */
    FILE * fp;
    fp = fopen("/Users/gimtaehyeon/Desktop/test2.txt","wt");
    fputs("1234-",fp);
    fclose(fp);
    
    /* 파일개방 */
    fp = fopen("/Users/gimtaehyeon/Desktop/test2.txt","rt");
    
    for(i=0;i<4;i++)
    {
        putchar(fgetc(fp));
        fpos = ftell(fp);
        fseek(fp, -1, SEEK_END);
        putchar(fgetc(fp));
        fseek(fp, fpos, SEEK_SET);
    }
    
    fclose(fp);
    
    return 0;
}
 

cs

출력결과

1-2-3-4-


20행 : 현재의 파일 위치 지시자 정보를 변후 fpos에 저장하고 있으므로, 피일 위치 지시자를 어디로 이동시키건 다시 이전 위치로 되돌릴 수 있게 되었다.

23행 : 20행에서 저장해 놓은 정보를 참조하여 파일 위치 지시자를 이전의 위치로 되돌리고 있다.


+ Recent posts