본문으로 이동

미디어위키 1.45 안정화가 거의 끝났습니다. 다만 Flow 확장 기능 관련 이슈가 있어서 대체하는 작업을 수행할 계획입니다.

  1. 큰숲백과:청사진에서 위키 발전의 대략적인 방향성을 제시했습니다. 의견이 있으신 분은 큰숲백과토론:청사진에서 의견을 남겨주시면 좋겠습니다.
  2. 기능상의 오류로 지원하지 않고 있는 기능에 대해서는 큰숲백과토론:이슈 트래커에 요약했습니다. 참고하시기 바랍니다.
  3. 데이터베이스 덤프 받고싶으신 분은 큰숲백과 가입 후에 사용자토론:Bigforest에 의견 남겨주시면 ftp 주소, 계정, 비밀번호를 특수:EmailUser를 통해서 공개할 예정입니다.

작은숲:위키노트/초보자를 위한 C 언어 강의/이진 파일

큰숲백과, 나무를 보지 말고 큰 숲을 보라.

파일(File)에는 크게 텍스트(Text) 파일과 이진(Binary) 파일, 두 가지 종류가 있다. 이 두 종류의 파일을 구분하는 방법은 간단하다. '메모장'과 같은 텍스트 편집기에서 그 내용을 확인할 수 있는 파일이 텍스트 파일이고, 그렇지 않고 이상한 글이 나오며 그 내용을 확인할 수 없는 파일들이 이진 파일이다. 텍스트 파일은 우리가 지금까지 사용했던 파일 형태이고, 이진 파일은 좀 특별한 형태의 파일이다. 텍스트 파일의 대표적인 예가 확장자가 'txt'로 붙는 파일들이다. 이런 파일들은 얼마든지 텍스트 편집기에서 그 내용을 확인할 수 있습니다. 하지만, 실행 파일(exe, com, dll)이나 특수한 목적의 파일, 예를 들어 아래아 한글의 파일(hwp) 같은 경우는 텍스트 에디터 상에서는 그 내용을 확인할 수 없다. 이러한 파일들은 특정한 편집기를 이용하던지 아니면, 편집할 수 없는 파일들이다. C 언어에서 이러한 이진 파일을 다루기 위해서는 파일을 열 때, 즉 fopen() 함수를 사용할 때 모드를 지정해줘야 한다. 파일을 열 때 설정할 수 있는 모드에는 "w", "r", 그리고 "a" 모드가 있다. 이것들과 텍스트 파일인 경우 "t", 이진 파일인 경우 "b"를 조합해서 모드를 설정할 수 있다. 즉, 텍스트 파일을 읽기 모드로 열 때는 모드를 "rt" 라고 하면 된다. 혹은 이진 파일을 쓰기 모드로 열 때는 "wb" 라고 하면 된다.

fopen("data.dat", "wb");

이진 파일은 일반적으로 텍스트 파일과는 분명히 구분된다. 따라서 이런 파일을 다루는 방법도 달라진다. 우선 파일을 열 때, 즉 fopen() 함수를 사용할 때 반드시 "b" 모드를 지정해야 한다. 텍스트 파일인 경우 "t" 모드를 생략할 수 있지만, 이진 파일은 반드시 지정해야 한다. 만약 생략하면 텍스트 파일로 간주하게 된다. 그리고, 이진 파일에서는 텍스트 모드에서 사용하던 fprintf(), fscanf(), fgets(), fputs() 함수들을 사용할 수 없다. 정확하게 말해서, 사용하지 못하는 것은 아니지만 이진 파일에서는 문자를 다루는 것이 아니기 때문에 텍스트 파일에서처럼 이러한 함수를 통해 값을 읽고 쓰는 것은 불가능하다. 이진 파일은 텍스트와는 다르게 파일 내용에 문자가 없다. 에디터 상에서 문자로 보이기는 하지만, 이는 문자가 아니라 이진(Binary) 값이다. 쉽게 이야기하면 이진 파일은 메모리 상에 저장된 내용을 그대로 파일로 옮겨놓은 것이라고 생각할 수 있다. 'a'라는 글자가 메모리에 저장될 때는 어떻게 저장될까? 'a'라는 글자로 저장되지는 않는다. 'a'라는 글자의 ASCII 코드의 이진수 값이 메모리에 저장된다. 'a'의 ASCII 코드가 십진수 '97'이니, 이진수로는 '1100001'이다. 바로 이 이진수 값이 메모리에 저장되어 있다. 이진 파일에 저장되는 내용도 마찬가지이다. 모든 내용이 이진수의 값으로 저장된다. 그래서 텍스트 에디터 상에서 이상한 글자들이 나오게 되는 것이다. 사실 텍스트 파일도 자세히 들여다보면 이진수의 값들이 저장된 것이다. 하지만 이진 파일과는 달리 텍스트 파일은 일정한 규칙이 있다. 하나의 문자를 저장하기 위해 1바이트, 혹은 2바이트, 혹은 3바이트를 사용한다. 이것은 문자의 인코딩 방식에 따라 달라진다. 어쨋든, 일정한 규칙을 가지고 문자들을 나열했기 때문에 텍스트 편집기 등에서는 이 규칙성에 따라 이진수를 읽어들여 문자로 표현한다. 하지만 이진 파일의 경우에는 텍스트 파일에서 사용하는 일정한 규칙을 따르지 않는다. 그렇기 때문에 텍스트 편집기로 이진 파일을 열면 알 수 없는 문자들이 보이는 것이다. 그래서 이진 파일에서는 텍스트 기반의 입출력 함수들을 사용할 수 없다. 이진 파일의 경우는 fgetc() 함수를 이용해 한 바이트씩 읽어들이거나 혹은 블럭 단위로 읽어들인다. 여기서 블럭이란 데이터 형의 크기라고 볼 수 있다. 만약 32비트 컴퓨터의 int 형이라면 4 바이트가 될 것이고, 이 int 형 값을 이진 파일에 기록한다는 것은 4 바이트만큼을 기록한다는 것이다. 이진 파일에 어떤 값을 쓰고자 할 때는 아래와 같이 할 수 있다.

int i = 4;
FILE *fp;
fp = fopen("data.dat", "wb");
fwrite(&i, sizeof(int), 1, fp);
fclose(fp);

위에서 쓰인 fwrite() 함수의 첫번째 인자는 쓰고자 하는 값이 저장된 메모리의 주소이다. 그리고 두번째 매개변수는 쓰고자 하는 값의 크기, 세번째 매개변수는 몇 번 쓸 것인가, 네번째는 어느 스트림으로 쓸 것인가를 나타낸다. 만약 int 형 배열을 텍스트 파일에 기록한다면 아래와 같이 할 수 있다.

int i;
int array[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
FILE *fp;
fp = fopen("data.dat", "wt");
for (i = 0; i < 10; i++)
    fprintf(fp, "%d ", array[i]);
fclose(fp);

비슷하게, 이진 파일에 기록한다면 아래와 같이 한다.

int i;
int array[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
FILE *fp;
fp = fopen("data.dat", "wb");
for (i = 0; i < 10; i++)
    fwrite(&array[i], sizeof(int), 1, fp);
fclose(fp);

하지만 뭔가 부족하다. fwrite() 함수를 쓴다면 더 간편한 방법이 있지 않을까?

int i;
int array[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
FILE *fp;
fp = fopen("data.dat", "wb");
fwrite(array, sizeof(int), 10, fp);
fclose(fp);

위의 fwrite() 함수가 의미하는 것은 'array 번지에서부터 int 형 크기만큼 10번 fp 스트림에 써라'라는 말이다. 다른 예를 들자면, 구조체의 값을 텍스트 파일에 쓰려고 하면 아래와 같이 할 수 있다.

struct _data {
    int a;
    int b;
    int c;
};
FILE *fp;
struct _data data = { 10, 20, 30 };
fp = fopen("data.dat", "wt");
fprintf(fp, "%d ", data.a);
fprintf(fp, "%d ", data.b);
fprintf(fp, "%d ", data.c);
fclose(fp);

반면에 이진 파일에 기록을 한다면,

struct _data {
    int a;
    int b;
    int c;
};
FILE *fp;
struct _data data = { 10, 20, 30 };
fp = fopen("data.dat", "wb");
fwrite(&data, sizeof(struct _data), 1, fp);
fclose(fp);

이런 식이 될 것이다. 실제로 이진 파일이 사용되는 경우는 상당히 많다. 특별한 형태의 데이터 파일은 이진 파일이라고 볼 수 있다. 아래아 한글 파일, 이미지 파일 등이 좋은 예이다.

이 작은숲 문서의 출처는 위키노트의 위키노트: 문서입니다.