프로그래밍/Python

[Python] 이진 파일로부터 int array 읽어 들이는 3가지 방법들

채윤아빠 2021. 4. 28. 22:39
728x90
반응형


파일(버퍼)로부터 int array를 읽어 들이는 3가지 방법을 알아 보도록 하겠습니다.

"cam-20220503_1255.mp4.idx"에는 int32 정수값이 18,001 개가 들어 있는 이진파일입니다.

"cam-20220503_1255.mp4.idx" 파일로부터 18,001 개의 정수를 읽어 배열(list, tuple)로 만드는 3가지 방법을 아래와 같이 예제로 작성하였습니다.

# *.idx 파일을 list()로 읽어들이는 예제

import numpy as np
import os
import struct


video_file_name = 'demo/cam-20220503_1255.mp4'

video_index_file = open(f'{video_file_name}.idx', 'rb')

# move file cursor to end
video_index_file.seek(0, os.SEEK_END)

file_size = video_index_file.tell()
total_frame_count = int(file_size / 4)
print(f'video file = {video_file_name}')
print(f'video file_size = {file_size} / total_frame_count = {total_frame_count}')

video_index_file.seek(0, 0)
print(f'video file = {video_file_name}')


# 1) use struct.unpack() and for loop
frame_index_list = list()
frame_count = 0
for index in range(total_frame_count):
    frame_index_bytes = video_index_file.read(4)
    if (frame_index_bytes == None):
        break
    (frame_index, ) = struct.unpack('=i', frame_index_bytes)
    frame_index_list.append(frame_index)
    frame_count += 1

print(f'frame_count = {frame_count}')
print(f'{frame_index_list[:10]}')


# 2) use struct.unpack() only
video_index_file.seek(0, 0)
data_bytes = video_index_file.read()
frame_list = struct.unpack(f'={total_frame_count}i', data_bytes)
print(f'frame_list[:10] = {frame_list[:10]}')
print(f'len(frame_list) = {len(frame_list)}')


# 3) use np.frombuffer()
frame_list2 = np.frombuffer(data_bytes, np.int32)
print(f'frame_list2[:10] = {frame_list2[:10]}')
print(f'len(frame_list2) = {len(frame_list2)}')


video_index_file.close()

당연하게도 첫 번째 방법은 파일로부터 4바이트씩 읽고, 이를 struct.unpack() 함수를 이용하여 int 값으로 변환한 후에 리스트에 추가하는 방법입니다. struct.unpack() 함수 대신에 int.from_bytes()를 이용하여도 동일한 결과를 얻을 수 있습니다.

    int.from_bytes(frame_index_bytes, byteorder='little', signed=False)

두 번째 방법은 동일하게 struct.unpack() 함수를 이용하지만, int 값의 개수를 지정하여 반환받는 방법인데, 첫 번째 방법보다는 매우 간결합니다. 주의할 점은 첫 번째 것과의 차이점이 리스트(list)가 아닌 튜플(tuple)로 주어진다는 점입니다.

마지막 세 번째 방법은 numpy.frombuffer() 함수를 이용하는 방법인데, struct.unpack() 함수와의 차이라면 주어진 bytes에 맞게 전체를 자동으로 배열로 반환해 준다는 점입니다. 물론 'count' 파라미터를 추가로 주어서 배열로 받을 항목의 수를 지정할 수도 있습니다.

위와 예제를 실행한 결과는 다음과 같습니다.

video file = demo/cam-20220503_1255.mp4
video file_size = 72004 / total_frame_count = 18001
video file = demo/cam-20220503_1255.mp4
frame_count = 18001
[71992, 71993, 71994, 71995, 71996, 71997, 71998, 71999, 72000, 72001]
frame_list[:10] = (71992, 71993, 71994, 71995, 71996, 71997, 71998, 71999, 72000, 72001)
len(frame_list) = 18001
frame_list2[:10] = [71992 71993 71994 71995 71996 71997 71998 71999 72000 72001]
len(frame_list2) = 18001

참고자료