오늘은 IDL에서 바이너리(Binary) 파일을 읽는 방법에 관하여 다뤄보기로 하겠습니다. 이 내용은 분량이 좀 될 것 같으므로 앞으로 약 2~3회에 걸쳐 나누어 소개하게 될 것 같습니다.


바이너리 파일이라고 하는 것은 쉽게 생각하면 텍스트(Text) 파일이 아닌 파일이라고 봐도 무방합니다. 흔히 우리가 메모장과 같은 텍스트 에디터로 바로 열어서 볼 수 있고 그 안의 내용도 우리가 이해할 수 있는 문자들로 구성된 경우 이 파일을 텍스트 파일이라고 하는데, 이는 아스키(ASCII) 코드표에 나와 있는 문자들로 구성된 경우로서 바이너리 파일과는 완벽하게 대비되는 개념이라고 볼 수 있습니다. 바이너리 파일도 텍스트 에디터 프로그램으로는 정상적으로 오픈이 불가능합니다. 물론 억지로오픈해서 볼 수도 있긴 하지만, 이 경우 이상한 암호같은 문자들만 표시될 뿐입니다. 이러한 파일의 내용은 실질적으로는 바이트(Byte)들의 집합체라고 볼 수 있습니다. 즉 8개의 이진수(bit)로 구성된 바이트들로 구성되어 있다고 보면 됩니다.


그런데 굳이 이런 방식의 파일이 사용되는 이유는, OS나 기종 상관없이 어떤 컴퓨터에서든 읽을 수 있는 아주 기본적이고 원시적인 포맷이라는 점이 있고, 또한 파일의 크기가 상대적으로 작다는 장점도 있기 때문입니다. 동일한 내용을 담더라도 아스키 형식의 텍스트 파일로 저장할 경우에 비해 바이너리 파일로 저장할 경우에는 파일 크기가 더 작습니다. 따라서 많은 양의 데이터를 저장해야 할 경우 바이너리 형태로 저장하는 방식이 꽤 많이 애용되고 있습니다. 그래서 과학기술 분야에서도 어떤 데이터를 받을 때 이와 같은 바이너리 파일로 받게 되는 경우들이 자주 있습니다. 물론 IDL에서도 바이너리 파일을 읽을 수 있는 기능들이 엄연히 지원이 되고 있습니다.


그러면 일단 IDL에서 바이너리 파일을 읽는 과정을 예제를 통하여 살펴보기로 합시다. 오늘 예제로 사용할 바이너리 파일은, IDL이 설치된 디렉토리를 보면 그 안에서 examples/data라고 하는 하위 디렉토리 안에 있습니다. 그래서 이 파일의 위치에 대한 디렉토리 경로를 다음과 같이 FILEPATH 함수를 사용하여 받아올 수 있습니다.


file = FILEPATH('nyny.dat', SUBDIRECTORY=['examples', 'data'])


이렇게 얻어진 file이라는 변수를 출력해보면, 지금 사용할 nyny.dat라는 바이너리 파일에 대한 디렉토리 경로를 볼 수 있습니다. 저같은 경우는 Mac OS용 IDL 8.6을 사용중이기 때문에 다음과 같이 출력이 됩니다. 물론 IDL이 설치된 PC의 OS라든지 개인 설정 등에 따라 이 값은 달라질 수 있습니다. 윈도우즈 OS의 경우라면 아마 "C:\Program Files\Harris\~~~"와 같은 내용이 될 겁니다.


/Applications/harris/idl86/examples/data/nyny.dat


이제 이 바이너리 파일을 읽어야 할텐데요. 이를 위하여 간단하게 사용할 수 있는 기능은 READ_BINARY라는 내장함수입니다. 일단 다음과 같이 이 함수를 사용하여 파일의 내용을 읽고 그 내용을 담은 data라는 배열의 정보를 확인해 봅시다.


data = READ_BINARY(file)

HELP, data


HELP문에 의하여 출력된 정보를 보면 다음과 같습니다.


DATA            BYTE      = Array[393216]


즉 data는 393,216개의 바이트형 값들을 담고 있는 1차원 배열이라는 의미입니다. 맞는 얘기이긴 합니다. 하지만 이 바이너리 파일에 담겨진 정보의 원래 형태는 사실 768x512의 구조를 갖고 있습니다. 실제로 768x512=393216이 맞습니다. 그러면 제가 지금 언급하고 있는 "원래의 형태가 768x512"라고 하는 사실은 무엇을 근거로 하고 있을까요? 다름이 아니라 이 바이너리 파일을 제작하여 공급한 원저자가 제공한 정보를 근거로 합니다. 실제로 이 정보는 example/data 디렉토리 안에 있는 data.txt라는 파일에 나와 있습니다. 직접 확인해보시기 바랍니다. 어쨌든 이러한 정보를 근거로 한다면 READ_BINARY 함수를 다음과 같이 사용하는 것이 맞습니다. 아래 예제 코드에서는 DATA_DIMS라는 키워드를 추가로 사용하여, 바이너리 파일로부터 읽고자 하는 데이터의 배열 구조가 768x512가 되어야 함을 명시하고 있습니다.


data = READ_BINARY(file, DATA_DIMS=[768, 512])

HELP, data


그리고 위의 내용은 좀 더 일반화하면 다음과 같이 DATA_TYPE이라는 키워드를 함께 사용한 것과 마찬가지입니다. 이 키워드는 바이너리 파일로부터 읽을 값들의 자료형(Data Type)을 나타내는 고유번호인데, 바이트형일 경우 1이 되며 이 값이 디폴트입니다. 만약 읽게 될 값들의 자료형이 바이트형이 아니라 정수나 실수 등이 될 경우에는 해당 고유번호를 따로 명시해줘야 합니다. 참고로 언급하면 정수형일 경우는 2가 되고 실수형일 경우는 4가 됩니다. 그 외의 경우에 대해서는 IDL 도움말을 참조하시기 바랍니다.


data = READ_BINARY(file, DATA_DIMS=[768, 512], DATA_TYPE=1)

HELP, data


사실 이 부분은 우리가 바이너리 파일을 읽는데 있어서 매우 중요하게 생각해야 하는 사항입니다. 즉 어떤 바이너리 파일을 사용자가 제대로 읽기 위해서는, 그 파일 내부에 수록된 데이터가 어떤 형태를 갖는가에 대한 정보를 파일 공급자측에서 반드시 제공해야 한다는 것입니다. 이러한 정보를 반드시 제작자 또는 공급자가 제공해야 하는 이유는, 바이너리 파일에 수록될 데이터의 형태는 파일을 생성할 때 제작자에 의하여 결정되기 때문입니다. 암호화된 파일이나 마찬가지란 얘기입니다. 만약 이러한 정보가 사용자에게 제공되지 않을 경우에는, 사용자 입장에서는 파일을 제대로 읽는것은 사실상 불가능합니다. 물론 여러가지 추측을 통하여 시행착오를 겪어가며 읽어볼 수도있겠지만, 성공 확률도 낮을 뿐더라 시간을 많이 허비하게 됩니다. 약간 과정일 수도 있겠지만, 마치 요즘 유행하는 가상화폐 생성을 위한 문제를 푸는 것과 마찬가지 맥락이라고 봐도 무방합니다. 아니면 암호 해독을 해야 하는 경우와도 마찬가지겠지요. 바이너리 파일은 어떻게 보면 암호화된 파일이나 마찬가지라고 얘기해도 틀린 말은 아닙니다. 따라서 만약 어디선가 바이너리 파일을 받아서 작업을 해야 할 경우, 그 파일에 수록된 데이터의 형태에 관한 정보를 반드시 함께 받아야 합니다.


갑자기 썰이 길어졌는데, 어쨌든 위와 같이 data라는 배열을 읽게 되면 그 특성에 맞게 IDL에서 처리 또는 표출이 가능합니다. 실제로 이데이터는 위성 이미지이기 때문에 다음과 같이 이미지의 형태로 가시화를 해볼 수 있습니다. 그리고 그 결과는 다음 그림과 같습니다.


win = WINDOW(DIMENSIONS=[768, 512], /NO_TOOLBAR)

im = IMAGE(data, MARGIN=0, /CURRENT)



일단 여기까지의 내용을 정리해보면, IDL에서 바이너리 파일을 읽는데 있어서는 READ_BINARY 함수를 사용하는 것이 가장 간편한 방법이라고 볼 수 있습니다. 물론 이것은 바이너리 파일에 포함된 데이터가 전체적으로 일관성이 있을 때에만 해당됩니다. 사실 실전에서 사용되는 바이너리 파일들을 보면, 어떤 경우에는 다양한 형태의 데이터들이 복잡하게 담겨 있는 경우도 있습니다. 이럴 경우에는 위의 예제에서 사용한 READ_BINARY 함수로는 해결이 힘들 수도 있습니다. 이런 예제에 대해서는 나중에 언급하도록 하겠습니다.


이번에는 같은 디렉토리에 있는 jet.dat라는 바이너리 파일을 읽고 그 데이터를 표출하는 과정을 다음 예제 코드에 한꺼번에 소개하였습니다. 이 파일은 3차원 큐브 형태의 데이터를 담고 있는데, 81x40x101의 구조를 갖는 바이트형 값들로 구성되어 있습니다. 따라서 아래 내용에서 READ_BINARY 함수는 이러한 근거에 의하여 사용되고 있습니다. 물론 이 파일에 수록된 데이터의 배열 구조에 대한 정보는 아까와 마찬가지로 같은 디렉토리 안에 있는 data.txt 파일에 수록되어 있다는 점을 참조하시기 바랍니다.


file = FILEPATH('jet.dat', SUBDIRECTORY=['examples', 'data'])

data = READ_BINARY(file, DATA_DIMS=[81, 40, 101])

win = WINDOW(DIMENSIONS=[500, 500], /NO_TOOLBAR)

vol = VOLUME(data, RGB_TABLE0=73, /CURRENT)


그리고 앞서 언급했듯이 이 데이터는 3차원 큐브형이기 때문에 볼륨(Volume)의 형태로 가시화가 가능합니다. 이를 위하여 VOLUME이라는 그래픽 함수가 사용되었습니다. 그 결과는 다음 그림과 같습니다.



그러면 오늘은 여기까지 하고, 다음 회차 게시물에서 내용을 계속 이어나가기로 하겠습니다.