삽질의 현장/- C

곱씹어보자 C!_#028_삽잡이의 두서없이 막말하는 파일 입출력 (2)

shovelman 2015. 7. 1. 00:31

파일 입출력을 할 때에는 2가지의 파일 입출력을 제공합니다.


1. Text File 입출력


이때 C언어에서 많이 사용하는 함수는 fprintf(), fscanf() 입니다.


2. Binary File 입출력


fwrite(), fread() 함수를 사용하는데요, 

fwrite() 함수 같은 경우, 바이너리로 파일을 출력하는 기능을 가지고 있으며,

fread는 반대로 복원하고자 할 때 사용합니다.

바이너리 0과 1의 집합으로 된 기계어 파일... 아시죠? 하하..


2번, Binary File 입출력의 경우에는 사람이 읽기위한 목적이 아닌, 

데이터를 보관하고 다음에 실행할 때 원상태로 복구하기 위해 사용합니다.

음... 다시 말씀드리자면, 

Binary 입출력은 쓰는 것을 목적으로 하지 않는 다는 것입니다. 

읽어들일 수 있어야됩니다. 

데이터를 써놨는데 읽어서 원상태로 복원을 하지 못한다면 

의미가 있나요?

그리하여 데이터를 쓸 때는 읽고 복원할 수 있도록 써야합니다.


아무튼...

예제들을 살펴보도록 하겠습니다.


첫번째, Text File 입출력입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
void main()
{
    FILE *fp = NULL;
    int n = 10234;
 
    fp = fopen("Sapzape.txt""w");
 
    fprintf(fp, "%d", n);
    fprintf(fp, "%d", n);
    fprintf(fp, "%d", n);
    fclose(fp);
}
cs


(자세한 문법은 구글링을 통해 확인해보세요 ㅎㅎ)


Sapzape.txt 파일을 만들었군요... 

해당 파일에 정수형 n의 값을 3번 출력했습니다...

현재는 경로를 지정해주지 않았기 때문에 해당 프로젝트 파일에 가서 .exe 파일을 

실행시키신다면 Sapzape.txt 파일이 생성되고, 

그 안에 데이터가 저장되는 것을 확인하실 수 있습니다.


Text파일은 모두 다 문자열로 출력되는 것입니다...

정수값을 아무리 출력해도 문자열로 보는 것이죠...

문자열로 쓰니 크기가 정해져있지 않습니다.


여기서, Text 문서의 장단점을 파악할 수 있습니다.

우선 장점으로는, 사람이 읽을 수 있다는 것입니다. 

이것이 바로 생성하는 이유가 되죠... 일반적으로 텍스트 파일을 생성하는 것은

써놓고 복원하는 목적이 아닌, 읽는 것이 주된 목적입니다.


반면에 단점으로는 ,정수들의 구분 및 길이를 알 수 가 없게 된다는 것입니다.

데이터를 복원한다고 생각해보시죠... 복원을 제대로 할 수 있을까요?




두번째로 Binary 입출력입니다.


1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
void main()
{
    FILE* fp = NULL;
    int n = 10234;
    
    fp = fopen("Sapzape.txt""wb");
 
    fwrite(&n, sizeof(int), 1, fp);
    fclose(fp);
}
 
cs


"wb" 라는 것 자체가 write binary를 뜻합니다... (Text는 t 생략이 가능해요!)


아무튼... 바이너리로 출력하게 된다면... 

내가 원하는 크기대로 정확하게 쓸 수 있습니다. 

하지만, 열어봤자 못알아본다는 점.



데이터를 만든다는 것은,

적어도 해당 파일 종류의 형식이 있어야지 종류에 따라 복원할 수 있게 되겠죠?

읽어들일때 어떻게 읽어들어야 할지에 대해 알아야될거 아닙니까? ㅎㅎ


파일 안에 어떤 데이터가 있는지 모른다고 생각해보세요...

읽어낼 수 있겠습니까? 없겠죠? 원 데이터를 복원할 수 없다 이겁니다...


생각해보세요... 

한글 파일이 포토샵에서 열립니까? ppt 파일이 한글에서 열립니까?
파일의 형식이 어떻게 보관되냐에 따라서 

그 형식을 알고 있는 해당 어플리케이션 만이 파일을 열고 복원할 수 있는 것인데...


따라서 제가 하고 싶은 말은...

파일들은 반드시 각자의 Data 형식(구조)를 가지고 있다는 것입니다.

즉 파일 포멧이 있다....

포멧을 알지 못한다면 데이터를 읽어들이지 못하게 된다는 것이죠.


파일 포멧에는 파일에 대한 헤더 정보 및 실제 데이터 정보가 포함되어야 합니다.

포멧을 아는 어플리케이션만이 그 파일을 열 수 있다!


즉 그말은 우리가 우리만의 파일 포멧을 만든다면 우리만의 파일을 복원시킬 수도 있다는...

우선 우리 만의 파일 포멧을 만들어 보도록 하죠...


아래 두 예시는 파일 포멧을 만들어 본 뒤 출력 및 복원을 하는 기능을 가진 코드입니다.


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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// 파일 포멧 형식 작성 및 쓰기
#include <stdio.h>
#include <string.h>
void main()
{
    FILE* fp = NULL;
    fp = fopen("Sapzape.mff""wb");
 
    //헤더 작성
    {
        char markup[4= "WIN";
        int extra = 0;
        int dCount = 5;
        fwrite(markup, strlen(markup) + 11, fp);
        fwrite(&extra, sizeof(int+ 11, fp);
        fwrite(&dCount, sizeof(int+ 11, fp);
    }
    //정수형 write
    {
        int n = 100;
        char type = 'I';
        fwrite(&type, sizeof(char), 1, fp);
        fwrite(&n, sizeof(int), 1, fp);
    }
    //문자열 write
    {
        char* s = "SAPZAPE";
        short slen = strlen(s) + 1;
        char type = 'S';
        fwrite(&type, sizeof(char), 1, fp);
        fwrite(&slen, sizeof(short), 1, fp);
        fwrite(s, slen, 1, fp);
    }
    //실수형 write
    {
        double d = 5.5678;
        char type = 'D';
        fwrite(&type, sizeof(char), 1, fp);
        fwrite(&d, sizeof(double), 1, fp);
    }
    //문자열 write
    {
        char* s = "ABC";
        short slen = strlen(s) + 1;
        char type = 'S';
        fwrite(&type, sizeof(char), 1, fp);
        fwrite(&slen, sizeof(short), 1, fp);
        fwrite(s, slen, 1, fp);
    }
    // 정수형 write
    {
        int n = 6500;
        char type = 'I';
        fwrite(&type, sizeof(char), 1, fp);
        fwrite(&n, sizeof(int), 1, fp);
    }
 
    fclose(fp);
}
cs



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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// 읽기
#pragma warning (disable:4996)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main()
{
    FILE* fp = NULL;
    int dCount = 0, i;
    fp = fopen("test.mff""rb");
    
    {
        char markup[4];
        int extra;
        fread(markup, sizeof(markup),1, fp);
        fread(&extra, sizeof(int), 1, fp);
        fread(&dCount, sizeof(int), 1, fp);
    }
    for(i = 0 ; i <dCount; ++i)
    {
        char type;
        //type 읽어
        fread(&type, sizeof(char), 1, fp);
        switch(type)
        {
        case 'I':
            {
                int data;
 
                fread(&data, sizeof(int), 1, fp);
 
                printf("정수 %d\n", data);
            }
            break;
        case 'D':
            {
                double data;
 
                fread(&data, sizeof(double), 1, fp);
 
                printf("double: %g\n", data);
            }
            break;
        case 'S':
            {
                char* s;
                short slen;
 
                fread(&slen, sizeof(short), 1, fp);
 
                s = (char*)malloc(sizeof(char)*slen);
                fread(s, slen, 1, fp);
                
                printf("string: %s\n", s);
                
                free(s);
            }
            break;
        }
    }
    fclose(fp);
}
 
cs