C 언어로 한글 파일 출력하기

 

콘솔화면에 printf함수를 사용하면 우리가 원하는 텍스트를 출력할 수 있다.

 

하지만, 점점 표현하고 싶은 것들이 많아지고 다양해질수록, 한 소스코드에서 관리하기 어려워진다.

 

객체지향적인 프로그래밍을 하기 위해 지켜야할 SOLID, 5가지 원칙 첫번째 SRP가 있다.

 

Single Responsibility Principle

 

이것이 의미하는 것은 한 소스코드엔 하나의 책임만 존재해야하는 것이다.

 

만들기는 어렵지만, 객체지향적인 코드를 작성하면, 소스 코드의 재활용성이 올라가고, 읽기 쉬워지니 유지보수성이 올라가, 생산성이 올라간다.

 

그래서 나는 소스코드에 매번 텍스트를 넣게 하는 것보다, txt file로 저장한 것을 불러올 수 있도록 하고 싶었다.

 

찾아보니 다음과 같이 쓸 수 있었다.

 

#include <stdlib.h>
.... 중략 ...
void paint_old()
{
    FILE *ptr;
    char ch;

    ptr = fopen("rabbit.txt", "r");

    if (NULL == ptr)
    {
        printf("cannot read the file. error! \n");
    }
    do
    {
        ch = fgetc(ptr);
        printf("%c", ch);
    } while (ch != EOF);
    printf("\n");
    fclose(ptr);
    return 0;
}
.... 중략 ...
 

old버전의 내가 만든 paint함수이다.

소스코드를 간략히 소개하자면, FILE 구조체의 포인터를 이용해 fopen으로 주소를 받고,

읽지 못하면 에러 메세지를, 읽을 수 있으면 한 글자씩 char로 받아 화면에 출력한다.

EOF를 읽으면 fclose로 포인터를 반환하도록 했다.

 

     / \
    / _ \
   | / \ |
   ||   || _______
   ||   || |\     \
   ||   || ||\     \
   ||   || || \    |
   ||   || ||  \__/
   ||   || ||   ||
    \\_/ \_/ \_//
   /   _     _   \
  /               \
  |    O     O    |
  |   \  ___  /   |
 /     \ \_/ /     \
/  -----  |  -----  \
|     \__/|\__/     |
\       |_|_|       /
 \_____       _____/
       \     /
       |     |
 

그러면 이런 아스키 이미지를 그려넣을 수 있었다.

 

하지만, 여기서 부족했다. 나는 함수 하나로 여러가지 파일을 접근하고 싶은데??

 

// main function
int main(){
    ...
    paint_old_add_path("src/rabbit.txt");
    paint_old_add_path("src/two-birds.txt");
    ...
    return 0;
}
// 함수 정의
void paint_old_add_path(char* path)
{
    FILE *ptr;
    char ch;

    ptr = fopen(path, "r");

    if (NULL == ptr)
    {
        printf("cannot read the file. error! \n");
    }
    do
    {
        ch = fgetc(ptr);
        printf("%c", ch);
    } while (ch != EOF);
    printf("\n");
    fclose(ptr);
    return 0;
}
 
     / \
    / _ \
   | / \ |
   ||   || _______
   ||   || |\     \
   ||   || ||\     \
   ||   || || \    |
   ||   || ||  \__/
   ||   || ||   ||
    \\_/ \_/ \_//
   /   _     _   \
  /               \
  |    O     O    |
  |   \  ___  /   |
 /     \ \_/ /     \
/  -----  |  -----  \
|     \__/|\__/     |
\       |_|_|       /
 \_____       _____/
       \     /
       |     |
  (o o)   (o o)
 (  V  ) (  V  )
/--m-m- /--m-m-
 

함수에 경로를 인자로 전달했더니, 부엉이가 생겼다!

 

 

그럼 배너 텍스트도 따로 관리하고 싶어졌다.!

    // main 함수 내
    paint_old_add_path("src/intro.txt");
 
??꽑 泥쒖옣?대떎.

"?ш릿 ?대뵒?멸?.."
 

이런.. 한글이 다 깨져버렸다. txt 는 UTF-8 로 인코딩을 했는데, fopen 의 기본 디코딩 방식이 ANSI이다.

 

그리하여 찾아본 바로,

    FILE *fp = fopen(file_name, "r, ccs=UTF-8");
    wchar_t c;
 

ccs의 정확한 의미는 구글링해도 찾을 수 없었다. 유력한 건 "const char set(?)" 하지만 다음과 같은 추가 설정으로 UTF-8 인코딩 방식의 파일을 읽을 수 있었고,

r
읽기 모드
w
쓰기 모드
a
append 모드
b
binary 모드
t
text 모드 (binary로 된 것을 읽을 때)
+
update 모드 (read + write 둘 다 가능)

 

모드 설정을 다음과 같이 할 수 있는 걸 알게 되었다.

 

또한, UTF-8은 다양한 언어를 표현할 수 있어, 용량이 더 커야했다. 그래서 사용하는 자료형이

wchar_t 를 사용한다.

 

그렇게 ch를 담았더니..

 

낯선 천장이다.

여긴 어디인가.................................................................. (무한 반복 됨)
 

EOF를 인식하지 못하고 while문 밖으로 나오지 못하고 있었다.

 

그래서 찾아봤지만, wchar_t로 명확히 EOF를 인식할 수 있는 방법을 못찾았고, @를 읽으면 내가 정의한 EOF다.

 

라고 코드를 수정했다. 또한 <Windows.h> 의 Sleep함수를 사용해서 마치 텍스트가 타이핑 되는 것처럼 만들어보았다.

void paint(char *file_name, int ms)
{
    FILE *fp = fopen(file_name, "r, ccs=UTF-8");
    wchar_t c;
    wchar_t end = '@';
    setlocale(LC_CTYPE, "");
    while (c != end)
    {
        fwscanf(fp, L"%lc", &c);
        if (c != end)
        {
            Sleep(ms);
            wprintf(L"%lc", c);
        }
    }
    printf("\n");
    fclose(fp);
    return;
}
 
 

 감사합니다.

 

+ Recent posts