티스토리 뷰

스포츠 관련 글을 제외하고는 경어체를 사용하지 않습니다. 작성 편의 및 작성 시간 단축이 가장 큰 이유이기도 하고, 저의 삽질기를 정리하는 것이 가장 큰 목표이기 때문에 양해 부탁드립니다.



윈도우는 파일 확장명을 기준으로 파일을 분류한다. 확장명이 zip이면 압축, 확장명이 py면 Python 파일과 같이 말이다.


파일 확장명을 한번 바꿔보면 전혀 다른 포맷으로 인식하는 것을 확인할 수 있다.


결국 윈도우 운영체제에서 제공해주는 파일 포맷은 정확하다고 하기 어렵다. 리눅스(또는 유닉스)에서는 file 명령어를 이용하여 쉽게 파일 포맷을 확인 할 수 있지만, 윈도우는 그렇지 못하다. 따라서 파일의 정확한 포맷을 확인하기 위해서는 해당 파일을 직접 확인해야 한다. 아래는 유닉스를 기반으로 만들어진 MacOS에서 file 명령어를 사용한 결과이다.

바이너리 파일의 경우 일반적으로 바이너리 파일은 파일헤더 + 페이로드 형태로 구성된다. 프로그램은 파일 헤더에 기록 된 정보(속성)들을 이용하여 프로그램에서 인식하고 읽을 수 있도록 한다. 파일 헤더에는 파일시그니처 (매직코드)라는 값이 있는데, 이 값을 기준으로 파일의 형태를 분류한다. 프로그램에서 파일 헤더 값이 자신이 열고자 하는 파일포맷과 일치하지 않으면 아래와 같이 오류 메시지를 발생시킨다.


즉, 이러한 파일 시그니처를 확인하면 정확한 파일 포맷을 확인할 수 있다는 결론에 도달한다. 각종 파일 시그니처에 대한 정보는 아래는 블로그에서 확인 가능하다. 

외부블로그 

파일 시그니처 모음 (Common File Signatures)



문제는 파일의 종류가 너무 많다는 것이다. 국제표준에 의해 정리 된 파일 포맷도 있지만, 각 프로그램 제작사에서 자체적으로 정의한 포맷도 있기 때문이다. 그런데 이러한 파일 포맷을 확인하기 쉽도록 파이썬 라이브러리로 제작해서 배포하는 오픈소스 프로젝트가 있다. Python-magic이라는 파이썬에서 활용 가능한 라이브러리로, 파이썬 코드를 이용하여 파일포맷을 확인하는 스크립트 작성시 사용 가능하다.

Python magic에 대한 자세한 설명은 아래 링크 참고.

정리하면 리눅스(유닉스)에서 제공하는 file 프로그램 같은 기능을 파이썬을 통해 윈도우에서도 이용할 수 있도록 한다는 것이다. 파이썬은 운영체제가 어떤 것이든 상관없이 파이썬만 설치되어 있으면 동작 가능하기 때문이다. 물론 리눅스나 유닉스에서도 file 프로그램이 제공해주는 기능을 파이썬 함수로 사용할 수 있기 때문에 유용하게 사용할 수 있다.

해당 라이브러리를 사용하려면 파일 시그니처들을 정의해놓은 magic이라는 파일이 필요하다. 문제는 유닉스나 리눅스의 경우 해당 파일이 기본적으로 존재하기 때문에 별도의 셋팅 없이 해당 라이브러리만 설치하면 바로 활용 가능하다.


리눅스에서 python 실행 후 import magic으로 python-magic 라이브러리를 로드한 다음, 라이브러리에서 제공하는 magic.from_file 함수를 이용해 파일경로를 입력해주면 파일 포맷을 확인해주는 것을 확인할 수 있다. 


리눅스가 라이브러리 맞춰주느라 쓰기 불편한 편인데, python-magic 라이브러리의 경우에는 리눅스가 윈도우보다 더 사용하기 편하다. 윈도우에서 사용하기 위해서는 사전에 설정해줘야 할 것들이 많이 있다. https://github.com/ahupp/python-magic 사이트에서 언급 된 Dependencies 항목에 언급 된, magic1.dll, regex2.dll, zlib1.dll, magic, magic.mgc 파일들의 설정을 먼저 진행해야 한다.

Dependencies 항목을 읽어보면 File for Windows 에서 다운로드 가능하다고 되어 있다. 해당 프로젝트는 GNUWin32 프로젝트로, GNU 에서 제작한 오픈소스 툴들을 윈도우 버전으로 변환하는 프로젝트이다. 현재 버전은 5.03으로 2009년 5월을 마지막으로 업데이트가 되지 않고 있는 것으로 확인된다. 참고로 리눅스 운영체제도 GNU의 오픈소스 라이센스 정책에 따라 배포되고 있는 오픈소스 운영체제이다.


해당 페이지의 Binaries 항목의 Zip을 클릭하여 파일을 다운로드 한다.


Dependencies 파일에는 regex2.dll, zlib1.dll 파일이 들어있고, Binaries 파일에는 file.exe, magic1.dll, magic, magic.mgc 파일이 들어있다. 이 파일 중 regex2.dll, zlib1.dll, magic1.dll, magic, magic.mgc 파일을 윈도우 운영체제의 PATH 환경변수에 해당하는 경로에 위치시키면 된다. PATH 환경변수 확인 및 설정방법은 아래글의 7번 항목을 참고하면 된다.

이전글 바로가기

우선 bin 폴더를 생성하고, regex2.dll, zlib1.dll, magic1.dll 파일을 위치시킨다.


그리고 share\misc 폴더를 생성하고, magic, magic.mgc 파일을 위치시킨다.


그리고 별도의 폴더를 생성하고 bin 폴더와 share\misc 폴더를 옮겨준다. 이번에는 c:\ 루트경로에 Dep_File 이라는 폴더를 생성했다.


그리고 C:\Dep_File\bin, C:\Dep_File\share\misc 폴더 경로를 PATH 환경변수 값에 추가하고, cmd.exe를 재실행한다. 그리고 file이라고 입력하면 아래와 같이 결과가 출력 되는 것을 확인할 수 있다. 임의로 파일명을 입력해주면 파일 포맷을 확인해주는 것을 확인할 수 있다.


여기서 끝이 아니다. 이제 file.exe 파일이 정상적으로 동작하는 것을 확인했으니, python에서 정상 동작하는지 확인해야 한다.
지금까지 우리가 진행한 것은 pip로 python-magic을 설치하기 전에 Dependencies 셋팅을 해 준 것 뿐이다. pip 명령어를 이용하여 python-magic을 설치하면, 정상적으로 설치 되는 것을 확인할 수 있다.


다시 python을 실행해서 magic을 import하면 아래와 같은 오류를 뿜어낸다. 재부팅을 안해서 그런가 싶어서 재부팅하고 다시 magic을 import 해도 결과는 동일하다. 해당 오류의 정확한 의미는 dll 파일을 찾을 수 없다는 것이다. 즉, Dependencies에서 설정한 DLL 파일의 경로를 인식하지 못해 발생하는 것으로 파악된다.


그러면 DLL 파일들을 제대로 인식하고 있는지 확인이 필요하다. 150 라인 lib magic = ctype.CDLL(dll) 에서 오류가 발생했다. magic.py 파일의 해당부분 소스코드를 보면 다음과 같다.


dll이라는 변수를 받는 부분은 146라인에 나와있다. 먼저 ctypes.util.find_library(‘magic’)과 ctypes.util.fild_library(‘magic1’) 부분의 함수가 정상적으로 동작했는지 확인이 필요하다. 각각의 확인 결과는 다음과 같다.


magic은 share\misc 경로에 존재하는 파일이고, magic1이 bin 경로에 존재하는 dll 파일이다. 그런데 146라인의 dll = 코드상에서는 각각의 함수가 or로 설정되어 있다. or 연산자는 참(True) 조건을 만족하면 뒤에 있는 조건과 관계 없이 연산을 종료한다. 앞에 ctypes.util.find_library(‘magic’) 함수에서 경로 값이 C:\\DepFile\\share\\misc\\magic 경로로 확인되었으므로, None이 아니고 True가 된다. 따라서 뒷 부분의 함수는 확인하지 않고 dll 값은 위의 문자열로 셋팅 된다. 그리고 150라인의 lib magic = ctypes.CDLL(dll) 함수에서 해당 파일을 연결하는데, magic 파일은 파일 시그니처를 정의한 파일이지 DLL 파일이 아니다. 따라서 150라인에서 DLL 파일이 아니기 때문에 오류가 발생하는 것이다.

의외로 해결 방법은 쉽다. ctypes.util.find_library(‘magic’)과 ctypes.util.fild_library(‘magic1’) 부분의 앞 뒤를 아래처럼 바꿔주면 된다.


그리고 나서 다시 python을 실행시키고 magic을 import하면 정상적으로 동작하는 것을 확인할 수 있다.


python-magic 함수에서 제공하는 from_file 함수를 이용하여 파일 포맷을 정상적으로 인식하는지 확인하면, 아래와 같은 오류 메시지가 나타난다.


어디서 본 듯한 오류 메시지가 싶다. “magic.MagicException: could not find any magic files!” 이 오류는 magic 파일의 경로를 인식하지 못하는 것이기 때문에, https://github.com/ahupp/python-magic 페이지의 Trouble Shooting에 언급되어 있듯이 해당 magic 파일의 경로를 설정해준다. 

그냥 magic.Magic(“magic 파일 경로”) 즉, magic.Magic(“C:\\DepFile\\share\\misc\\magic”)만 실행해주면 해당 함수는 메모리 주소 값만 리턴한다.


결국 해당 함수를 리턴 받는 변수를 하나 지정하고, 그 변수를 통해 함수를 호출해야 한다. 아래와 같이 변수를 통해 리턴 값을 저장하고, 변수를 통해 함수를 호출하면 정상적으로 동작하는 것을 확인할 수 있다. 테스트 한 파일은 처음에 확인했던 zip 파일이다. 확장명을 jpg로 변환하고 테스트 했으나, 정상적으로 zip 파일임을 알려 준다.


이로서 윈도우 환경에서 python-magic을 정상적으로 설치하고 사용해보았다. 그러나 문제가 있다. 파이썬 코드를 작성한 다음 exe로 변환해서 배포하는 경우에는 상관없지만, py 파일 자체를 가지고 활용하기에는 magic.py 파일을 수정하고 DLL 파일의 경로를 매번 설정해줘야 하는 번거로움이 있다는 것이다. 

그래서 결국 앞에서 확인한 GNUWin32 프로젝트에서 배포하는 file 패키지(file.exe 파일)를 이용해서 위와 동일한 동작을 하도록 하고, 화면에 출력되는 결과 값을 파이썬 변수에 저장하여 활용하는 것으로 방향을 바꾸었다. subprocess의 check_output 함수를 사용하면 가능하다.

오늘의 무한삽질 답사기 끝!!

ps. 해당 라이브러리는 32비트 운영체제 & 32비트 파이썬에서 정상 동작합니다. 
    삽질 결과 64비트 운영체제 & 32비트 파이썬, 64비트 운영체제 & 64비트 파이썬에서는
    정상적으로 동작하지 않습니다.
    Update (2016.09.13)!! 64비트 & 32비트 파이썬에서도 잘 된다고 합니다. ^^ 호롤룰루님 감사합니다. 

ps2. 파이썬은 2.7.11 버전 사용하였습니다.




댓글
  • 프로필사진 호롤룰루 와.. 정말 많은 도움 되었습니다. 딱 윈도우 환경에서 파일 시그니처 기반으로 탐색방법이 필요했는데 ㅠ 아쉬운 점이 있다면 magic 으로 파일 시그니처가 리턴되는게 아니라 from_file 로 파일 정보가 리턴되는게 좀 아쉽네요 ㅠㅠ 딱 시그니처만 떨어지면 좋을 텐데.. 그래도 덕분에 삽질 줄일 수 있었습니다!!! 64bit OS & 32bit python 환경으로 그대로 따라했는데 잘 돌아갑니다!!! 2016.07.29 00:39
  • 프로필사진 Favicon of https://www.bearpooh.com BlogIcon 곰탱이푸우 안녕하세요 ^^ 댓글이 많~~~이 늦었습니다. 요즘 업무에 치여 블로그는 거의 방치상태라... 죄송합니다. ㅠㅠ
    도움이 되셨다니 다행입니다. 말씀해주신 부분은 저도 아쉬운 부분입니다.ㅎㅎ 출력된 포맷정보에서 필요한 부분만 뽑아주는 스크립트를 간단하게 작성해서 활용하면 되는데... 좀 귀찮지요 ㅎㅎ
    64비트 OS, 32비트 파이썬도 되는군요 ^^ 좋은 정보 감사합니다. ㅎㅎ
    2016.09.13 00:47 신고
댓글쓰기 폼