[C] opendir로 파일 읽을때 유니코드, 한글 경로 읽기 및 파일 타입 체크 방법


#include <stdio.h>
#include <dirent.h> //dirent 구조체를 위해 dirent.h 참조 
#include <string.h>


int main(void) {
	int length = 0;
	
	char file_path[100];
	printf("폴더 경로를 입력해주세요. : ");
	gets(file_path);

	DIR *d;
	struct dirent *dir;
	d = opendir(file_path);
	if (d) {
		while ((dir = readdir(d)) != NULL) {
				printf("%s\n", dir->d_name);
				length++;
			
		}
		closedir(d);
		printf("총 발견한 파일수 : %d개", length);
		//열린 디렉토리를 닫는다.
	}
	return 0;
}

해당 프로그램을 실행해서 디렉토리 경로를 입력값으로 제공하면 그 디렉토리에 있는 파일을 전부 가져오게 됩니다.

근데 opendir 함수로 열면 한글 경로를 읽지 못하는 문제가 있습니다.

이게 골때리는게 어떤 환경에선 실행이 잘 되다가도 제 컴퓨터에서 실행하면 안되고 환경에 따라서 파일을 못가져오는 경우가 많았습니다.

 

온라인 컴파일러에서 공동작업을 하고 제 컴퓨터에서 빌드해보니 한글이 아예 깨져버리는군요??

 

특히 경로에 띄어쓰기가 있다던가, 유니코드 문자가 포함되어 있다던가, 한글이 포함되어있으면 아예 파일을 못가져왔고 경로가 띄어쓰기 없이 전부 영어인경우엔 파일을 가져올 수 있으나 파일 이름들을 출력하면 한글이 깨져버리는 문제가 발생했습니다.

 

if (dir->d_type == DT_REG) { //파일인것만 가져온다. dirent.h 변경 필수
	printf("%s\n", dir->d_name);
	length++;
}

또 다음과 같은 구문으로 d_type을 체크해서 파일만 걸러서 읽어내려 했는데 구조체 멤버에 d_type이 없다고 뜨네요. 

확인해보니 파일을 가져올때 dirent란 구조체를 활용하는데 dirent.h에 그것이 정의되어있습니다.

그런데 윈도우 C 컴파일러에선 기본적으로 제공되는 dirent.h에 d_type이 따로 정의되어 있지 않다고 합니다.

 

맥북이나 리눅스에선 또 되구요. 

 

"이 C언어스러움" 을 오랜만에 겪고나니 머리가 아파졌습니다.

파이썬이면 좀 느리긴해도 코드 몇줄이면 파일 촥촥 불러오고 알아서 다 해줄탠데요 ㅠ

 

그래도 지금 진행하는 프로젝트가 C로 진행하고 있기에 해당기능을 꼭 사용해야 해서 해결방법을 찾아보았습니다.

결론적으론 위에 해당하는 모든 문제를 해결했습니다.

 

Dirent.h 헤더 파일 교체

dirent.h
0.03MB

윈도우에서도 d_type을 사용할 수 있도록 만들어진 dirent.h 파일이 있습니다.

기존에 dirent.h는 백업해두거나 지우시고 해당 파일로 교체하셔야 합니다.

 

파일 출처 : https://github.com/tronkko/dirent

 

GitHub - tronkko/dirent: C/C++ library for retrieving information on files and directories

C/C++ library for retrieving information on files and directories - GitHub - tronkko/dirent: C/C++ library for retrieving information on files and directories

github.com

 

저의 경우 dev c++을 쓰는데 컴파일러가 헤더 파일을 include 하는 위치에 들어가서 dirent.h 파일을 교체했습니다.

 

경로는 제 기준으로 C:\Program Files (x86)\Dev-Cpp\MinGW64\x86_64-w64-mingw32\include 였는데

컴파일러, IDE마다 상이하니깐 잘 찾아보세요

 

Search Everything 같은 파일 찾아주는 유틸리티를 사용하면 빠르게 찾으실 수 있습니다.

 

한글 지원

#include <locale.h>

int main(int argc, char *argv[])
{
    setlocale(LC_ALL, "");

    /*...*/
}

이게 제일 문제였는데 dirent.h를 배포하고 있는 github 사이트에서 해결책을 제시해주었습니다.

위처럼 하시면 됩니다. main 함수 맨위에 setlocale 함수를 실행해주시면 저것에 영향을 받는 모든것들의 로케일이 맞춰지게 됩니다.

 

2번째 인자값에 아무것도 안적어놔야 해당 컴퓨터 로케일을 따라서 연결됩니다.

 

#include <stdio.h>
#include <dirent.h> //dirent 구조체를 위해 dirent.h 참조 
#include <string.h>
#include <locale.h>


int main(void) {
	
	setlocale(LC_ALL, "");
	
	int length = 0;
	
	char file_path[100];
	printf("폴더 경로를 입력해주세요. : ");
	gets(file_path);

	DIR *d;
	struct dirent *dir;
	d = opendir(file_path);
	if (d) {
		while ((dir = readdir(d)) != NULL) {
			if (dir->d_type == DT_REG) { //파일인것만 가져온다. dirent.h 변경 필수
				printf("%s\n", dir->d_name);
				length++;
			}
		}
		closedir(d);
		printf("총 발견한 파일수 : %d개", length);
		//열린 디렉토리를 닫는다.
	}
	return 0;
}

그래서 완성된 코드입니다. 잘 작동되는지 확인해볼까요?

 

경로에 띄어쓰기, 한글이 포함되어 있는데도 잘 읽고 한글 출력도 잘 됩니다.

파일만 걸렀는데 폴더는 무시하고 파일만 딱딱 잘 나오구요.

 

완벽하게 해결되었습니다.

 

COMMENT WRITE