IDL/Data Type & Format

IDL에서 바이너리(Binary) 파일 읽기 [2]

이상우_idl 2017. 12. 27. 14:30
728x90
반응형

IDL에서 바이너리 파일을 읽는 방법에 관한 내용을 지난 회에 이어서 계속 진행해 보겠습니다. 지난 회에서는 바이너리 파일을 읽는데 있어서 READ_BINARY라는 내장함수를 사용하는 예제를 소개했는데, 오늘은 조금 다른 접근 방법을 소개할까 합니다. 우선 지난번 예제에서 nyny.dat라는 바이너리 파일을 읽는 과정은 다음과 같았는데요.


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

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


이와 동일한 작업을 다음과 같이 OPENR, READU 등을 사용하여 진행할 수도 있습니다.


data = BYTARR(768, 512)

OPENR, lun, file, /GET_LUN

READU, lun, data

FREE_LUN, lun


사실 앞서 READ_BINARY 함수를 사용한 예제에서는, 바이너리 파일로부터 읽어올 데이터의 형태에 있어서 배열 구조와 자료형을 각각 DATA_DIMS와 DATA_TYPE 키워드로 명시했었습니다. 즉 768x512의 구조를 갖는 바이트형 값들로 구성된 배열의 형태로 데이터를 읽어온다는 것이었는데요. 그 역할이 위의 예제 코드의 맨 윗줄에서 BYTARR 함수를 사용하여 바이트형 배열을 생성하는 부분에 해당된다고 보면 됩니다.


이와 같이 우리가 읽어올 데이터의 형태에 부합되는 배열 또는 변수를 미리 생성한 후에 OPENR과 READU를 연이어 사용하는 방식입니다. OPENR 명령은 IDL에서 특정 파일로 접근할 수 있는 교신 채널을 만드는 역할을 합니다. 그 채널 번호를 1, 2, 3 등과 같은 숫자로 직접 지정할 수도 있지만, 여기서는 /GET_LUN 키워드를 사용함으로써 IDL이 알아서 그런 번호를 챙기도록 하였습니다. 그 번호의 값은 lun이란 변수에 담습니다. 이어서 READU라는 명령을 사용하여 이 채널 값을 통하여 파일로부터 데이터를 읽어오고 그 내용을 data라는 배열에 저장합니다. 데이터를 읽어오는 작업이 다 완료된 후에는 FREE_LUN 명령을 사용하여 교신 채널의 번호를 닫아주면 됩니다. 이후에 data 배열을 사용하여 이미지 형태로 표출하는 과정은 지난번과 동일합니다.


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

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


참고로 READU 명령은 READF 명령과는 다릅니다. READF 명령의 경우 "F"는 "Formatted"의 의미로서, 아스키(ASCII)문자들로 구성된 텍스트 파일의 내용을 읽어들일 때 사용됩니다. 반면 READU 명령의 경우 "U"는 "Unformatted"의 의미로서, 바이너리 파일의 내용을 읽어들일 때 사용됩니다. 어쨌든 정리해보면 바이너리 파일에 수록된 데이터를 읽어오는 방법은 크게 두가지로 나눌 수 있습니다. 첫번째는 READ_BINARY 함수를 사용하는 방법이고, 두번째는 방금 전에 본 것처럼 OPENR과 READU를 사용하는 방법입니다. 둘 중 어느 방법을 사용해도 상관이 없습니다. 다만 방법 자체의 유연성 또는 융통성(Flexibility)이란 측면에 있어서는 후자의 방법이 좀 더 낫다고 볼 수도 있습니다. 이러한 차이는 하나의 바이너리 파일 안에 특성이 다른 여러 종류의 데이터들이 섞여있을 경우 더 극명하게 나타납니다.


두 방법 사이의 이와 같은 차이점을 설명하기 위하여 이번에는 약간 다른 시도를 해보겠습니다. 대상 파일은 같습니다. 다만 이번에는 읽어오는 과정을 두 단계로 쪼개보려고 합니다. 즉 절반을 먼저 읽고 그 뒤에 나머지 절반을 마저 읽는 방식으로 작업을 진행해보고자 합니다. 이 과정은 앞서 언급한 두가지 방법들 중 후자에 해당되는 방법 즉 OPENR/READU 방법을 사용하여 다음과 같은 방식으로 구현해 보았습니다.


data1 = BYTARR(768, 256)

data2 = BYTARR(768, 256)

OPENR, lun, file, /GET_LUN

READU, lun, data1

READU, lun, data2

FREE_LUN, lun


여기서는 전체 데이터를 앞부분과 뒷부분으로 양분하여 data1, data2 두 개의 배열로 설정하고, 각 배열은 768x256의 크기를 갖도록 하였습니다. 원래 데이터의 전체 크기가 768x512였는데, 위와 아래로 균등하게 분할한 것입니다. 그리고 READU 명령이 두번에 걸쳐 사용된 것을 볼 수 있는데, 첫번째 READU는 data1을 읽었고 두번째 READU는 data2를 읽었습니다. 따라서 data1은 이미지의 하단부 절반에 해당되며 data2는 상단부 절반에 해당됩니다. 여기서 전체 데이터를 배열의 형태로 보면 data1이 전반부에 해당되지만, 이미지의 형태로 보면 하단부에 해당된다는 점을 유의하시기 바랍니다. 어쨌든 이렇게 분할하여 읽어온 data1, data2를 다음과 같이 서로 다른 컬러테이블을 사용하여 표출해 봅시다.


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

im1 = IMAGE(data1, MARGIN=0, /CURRENT, LAYOUT=[1, 2, 2])

im2 = IMAGE(data2, MARGIN=0, /CURRENT, LAYOUT=[1, 2, 1], RGB_TABLE=3)


이렇게 하면 다음 그림과 같이 전체 이미지의 하단 절반과 상단 절반을 구분해서 볼 수 있게 됩니다.



이번 예제에서 두번에 걸쳐 연이어 사용된 두 READU 명령의 역할을 짚어보면, 첫번째 READU가 데이터의 처음 절반 부분을 읽은 후 두번째 READU는 그 뒷부분 절반을 이어서 읽어온 셈이 됩니다. 이러한 점을 잘 이용하면, 여러 종류의 데이터들이 합쳐져 생성된 바이너리 파일로부터 순차적으로 각 데이터를 읽어오는 것이 가능합니다. 이러한 예제는 다음 회차 게시물에서 좀 더 구체적으로 소개하기로 하겠습니다.


이제 여기서 하나 또 생각해 볼 만한 또 다른 이슈는, 위와 같이 데이터를 분할하여 읽는 방식이 READ_BINARY 함수로는 가능한가 여부입니다. 물론 가능합니다. 다만 주의해야 할 점이 있습니다. 일단 다음과 같이 READ_BINARY 함수를 연이어 사용하는 방식을 먼저 시도해 봅시다.


data1 = READ_BINARY(file, DATA_DIMS=[768, 256])

data2 = READ_BINARY(file, DATA_DIMS=[768, 256])


이렇게 읽어온 data1, data2를 앞서와 같은 방식으로 함께 표출해보면 그 결과는 다음 그림과 같습니다.


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

im1 = IMAGE(data1, MARGIN=0, /CURRENT, LAYOUT=[122])

im2 = IMAGE(data2, MARGIN=0, /CURRENT, LAYOUT=[121], RGB_TABLE=3)



이 그림을 보면 뭔가 이상한 점이 보이실 겁니다. 즉 data1, data2 모두 바이너리 파일로부터 같은 부분을 읽어온 상태라는 것을 알 수 있습니다. 다시 말하면, READ_BINARY를 연달아 사용한다고 해도, 첫번째 명령에서 읽은 부분에 이어서 두번째 명령이 읽어오는 것이 아니란 얘기입니다. 두 개의 READ_BINARY가 각각 독립적으로 전체 데이터의 처음 부분부터 접근한다는 의미입니다. 물론 이러한 맹점을 극복할 방법은 있습니다. 바로 DATA_START라는 키워드를 사용하는 것입니다. 이 키워드는 READ_BINARY 함수로 바이너리 파일을읽을 때 어느 부분부터 읽기 시작할 것인지를 바이트 단위로 명시하는 역할을 합니다. 디폴트 값은 0입니다. 처음부터 시작하는 것이 디폴트라는 얘기입니다. 앞서 확인했던 문제의 원인은 바로 이 부분 때문이라는 것을 알 수 있습니다. 따라서 두번째 READ_BINARY가 첫번째 READ_BINARY가 읽은 바로 뒷부분부터 이어서 읽게 하려면 다음과 같이 해줘야 합니다.


data1 = READ_BINARY(file, DATA_DIMS=[768, 256])

data2 = READ_BINARY(file, DATA_DIMS=[768, 256], DATA_START=768L*256)


여기서는 두번째 READ_BINARY가 데이터를 읽기 시작하는 위치를 DATA_START 키워드를 사용하여 바이트(Byte) 단위로 명시하였습니다. 이렇게 하면 첫번째 READ_BINARY는 0부터 시작하여 768x256-1까지의 바이트 위치를 읽게 되고 두번째 READ_BINARY는 그 뒤부터 나머지를 읽게 됩니다. 이렇게 읽은 후 역시 마찬가지로 data1, data2를 함께 표출해보면 그 결과는 다음과 같습니다.



따라서 하나의 바이너리 파일안에 여러 종류의 데이터들이 존재할 경우에 READ_BINARY 함수를 사용하여 순차적으로 읽어오는 것이 가능하다는 것을 알 수 있습니다. 다만 이를 위해서는 DATA_START 키워드에 시작 바이트 위치를 항상 체크해서 명시해줘야 하는데, 이것은 상당히 번거롭습니다. 그 위치를 사용자가 직접 계산해서 명시해줘야 하기 때문입니다. 이러한 번거로움을 고려한다면 차라리 앞서 언급했던 OPENR, READU를 사용하는 방법이 더 효율적이라고 볼 수 있습니다.


그래서 오늘 언급된 내용을 다시 한번 정리해보면 다음과 같습니다.


1) 바이너리 파일 내에 수록된 데이터가 일관된 성격의 갑들로 구성된 하나의 덩어리의 형태로 존재할 경우에는 READ_BINARY 함수를 사용하는 것이 효율적이다.

2) 바이너리 파일 내에 수록된 데이터가 그 종류도 여럿이고 그 성격도 서로 다른 상태로 존재할 경우에는 OPENR, READU 방법을 사용하는 것이 더 효율적이다.


그러면 다음 회차에서는 여러 종류의 서로 다른 형태의 데이터들이 공존하는 바이너리 파일을 읽는 방법을 예제와 함께 소개해보기로 하겠습니다.

반응형