하이퍼텍스트 데이터 포맷(HDF5)는 복잡한 데이터를 계층적으로 관리하는 데 사용됩니다. HDF5의 C API와 이를 C#에서 사용할 수 있도록 래핑한 HDF.PInvoke.NETStandard 패키지를 통해 데이터 파일을 생성하고 조작할 수 있습니다.
1. HDF5 계층 구조 이해
HDF5에서는 모든 데이터가 계층적인 구조로 조직되며, 이는 일반적인 파일 시스템과 유사합니다:
/ <-- 루트 그룹
/GroupA
/Dataset1
/SubGroup
/Dataset2
C 언어 기반의 HDF5 API는 여러 모듈로 구성되어 있으며, 각각은 특정 작업을 담당합니다:
| 모듈명 | 설명 | 주요 함수 예시 |
|---|---|---|
| H5F | 파일 관리 | H5F.create, H5F.open |
| H5G | 그룹 관리 | H5G.create, H5G.open |
| H5D | 데이터셋 관리 | H5D.create, H5D.write |
| H5S | 데이터 공간 정의 | H5S.create_simple |
| H5T | 데이터 타입 정의 | H5T.copy, H5T.commit |
| H5A | 속성 관리 | H5A.create, H5A.read |
| H5L | 링크 관리 | H5L.create_hard, H5L.exists |
| H5O | 객체 관리 | H5O.open, H5O.get_info |
2. 주요 모듈 분석
2.1 H5G - 그룹 관리
그룹은 데이터셋과 하위 그룹을 포함하는 컨테이너입니다. 주요 작업에는 그룹 생성, 열기, 닫기가 포함됩니다.
예제 코드:
long groupId = H5G.create(fileId, "GroupA");
H5G.close(groupId);
2.2 H5L - 링크 관리
링크는 파일 시스템의 경로 또는 심볼릭 링크에 해당합니다. 링크를 통해 객체가 특정 위치에 연결됩니다.
예제 코드:
H5L.create_hard(sourceLocId, "GroupA/Dataset1", destLocId, "CopiedDataset");
bool exists = H5L.exists(fileId, "GroupA/Dataset1") > 0;
특징:
- 하드 링크: 동일한 물리적 객체를 여러 경로에서 참조.
- 소프트 링크: 경로 문자열 참조.
2.3 H5O - 객체 관리
모든 명명 가능한 요소(그룹, 데이터셋 등)는 객체로 간주됩니다. 이 모듈은 이러한 객체들을 제어하는 일반 인터페이스를 제공합니다.
예제 코드:
long objectId = H5O.open(fileId, "GroupA/Dataset1");
H5O.info_t info = new H5O.info_t();
H5O.get_info(objectId, ref info);
H5O.close(objectId);
3. 모듈 간 상호작용
각 모듈은 독립적이지만 상호 연관되어 작동합니다:
| 계층 | 모듈 | 비유 |
|---|---|---|
| 파일 | H5F | 파일 열기/닫기 |
| 그룹 | H5G | 폴더 관리 |
| 링크 | H5L | 경로 및 링크 처리 |
| 객체 | H5O | 명명 가능한 모든 요소 처리 |
예를 들어, 데이터셋을 복사하려면 다음과 같은 과정이 필요합니다:
- H5L: 원본 경로 확인.
- H5O: 실제 객체 정보 가져오기.
- H5G: 대상 그룹 확인 및 위치 지정.
4. 실습 예제
아래는 HDF5 파일을 생성하고, 그룹과 데이터셋을 만든 후, 데이터셋을 복사하고 링크 존재 여부를 확인하는 C# 코드입니다.
using System;
using HDF.PInvoke;
class Program
{
static void Main()
{
const string fileName = "test.h5";
// 1. 새로운 HDF5 파일 생성
long fileHandle = H5F.create(fileName, H5F.ACC_TRUNC);
Console.WriteLine($"파일 생성: {fileName}");
// 2. 그룹 생성
long groupHandle = H5G.create(fileHandle, "MainGroup");
Console.WriteLine("그룹 'MainGroup' 생성");
// 3. 데이터셋 생성
ulong[] dimensions = { 4 };
long spaceHandle = H5S.create_simple(1, dimensions, null);
long typeHandle = H5T.copy(H5T.NATIVE_INT);
double[] datasetData = { 10, 20, 30, 40 };
GCHandle dataPin = GCHandle.Alloc(datasetData, GCHandleType.Pinned);
long datasetHandle = H5D.create(groupHandle, "SampleData", typeHandle, spaceHandle);
H5D.write(datasetHandle, H5T.NATIVE_DOUBLE, H5S.ALL, H5S.ALL, H5P.DEFAULT, dataPin.AddrOfPinnedObject());
dataPin.Free();
H5D.close(datasetHandle);
H5S.close(spaceHandle);
H5T.close(typeHandle);
H5G.close(groupHandle);
// 4. 다른 그룹 생성
long anotherGroup = H5G.create(fileHandle, "SecondaryGroup");
H5G.close(anotherGroup);
// 5. 데이터셋 복사
H5O.copy(fileHandle, "/MainGroup/SampleData", fileHandle, "/SecondaryGroup/CopiedData", 0, 0);
Console.WriteLine("데이터셋 복사 완료");
// 6. 링크 존재 확인
bool linkExists = H5L.exists(fileHandle, "/SecondaryGroup/CopiedData") > 0;
Console.WriteLine($"링크 존재 여부: {linkExists}");
// 7. 파일 닫기
H5F.close(fileHandle);
Console.WriteLine("작업 완료 및 파일 닫힘");
}
}
5. 실행 결과
위 코드를 실행하면 다음과 같은 출력이 생성됩니다:
파일 생성: test.h5
그룹 'MainGroup' 생성
데이터셋 복사 완료
링크 존재 여부: True
작업 완료 및 파일 닫힘
최종 HDF5 파일 구조는 다음과 같습니다:
/
├── MainGroup
│ └── SampleData
└── SecondaryGroup
└── CopiedData
6. 주요 모듈 요약
| 모듈명 | 역할 | 주요 함수 |
|---|---|---|
| H5G | 그룹 생성 및 관리 | create, open |
| H5L | 링크 생성 및 검증 | create_hard, exists |
| H5O | 객체 복사 및 정보 조회 | open, get_info |