HDF5에서 **루트 노드, 그룹, 데이터셋, 속성(Attributes)**는 모두 고유한 ID를 가지고 있습니다. 이 ID를 통해 객체를 접근할 수 있으며, 접근 방법은 두 가지입니다:
- 문자열 경로 (예:
/Device1/temperature) - 객체 ID (오픈 연산을 통해 얻은 정수형 ID)
이 두 가지 방법은 HDF5 작업의 핵심입니다. 아래에서 이 방법들의 원리와 사용법을 상세히 설명합니다.
1. HDF5 객체의 ID 본질
HDF5의 모든 객체는 오픈될 때 정수형 ID(부정수)를 받습니다. 이 ID는 현재 세션 중에서 객체를 참조하는 "핸들"이며, 이후의 작업(리드/ライト, 속성 추가, 닫기 등)에 사용됩니다.
- 라이프사이클: ID는 객체가 "오픈될 때" 생성되고, "닫힐 때" 소멸됩니다(수동적으로 닫히지 않으면 메모리릭이 발생합니다).
- 유일성: 같은 객체를 같은 세션에서 여러 번 오픈해도 다른 ID를 받지만, 같은 객체를 참조합니다. 다른 세션의 ID는 상호간섭 없습니다.
2. 경로와 ID를 통해 객체 접근 방법 비교
두 방법의 핵심 차이점은 "시작점"입니다. 두 방법 모두 최종적으로 같은 객체에 도달합니다:
| 접근 방법 | 원리 | 적합한 장면 | 예제 ( /Device1/temperature 데이터셋 접근) |
|---|---|---|---|
| 문자열 경로 | 루트 노드나 특정 부모 객체에서 시작해 완전 경로로 직접 접근 | 객체의 완전 경로가 알려진 경우, 일회성 접근 | H5D.open(fileId, "/Device1/temperature", H5P.DEFAULT) |
| 객체 ID | 부모 객체 ID를 먼저 획득한 후 상대 경로나 ID 체인을 통해 자식 객체에 접근 | 같은 객체를 여러 번 접근할 때(경로 해석을 피하기 위해) | 1. 그룹 오픈: groupId = H5G.open(fileId, "/Device1")2. 그룹 ID를 통해 데이터셋 오픈: datasetId = H5D.open(groupId, "temperature") |
3. 실전 예제: 두 가지 방법으로 객체 접근
아래 코드는 같은 데이터셋을 경로와 ID 체인 두 가지 방법으로 접근하고 데이터를 읽어오는 방법을 보여줍니다:
using System;
using HDF.PInvoke;
namespace HDF5PathVsIdDemo
{
class Program
{
static void Main(string[] args)
{
string hdf5Path = "path_vs_id_demo.h5";
CreateTestFile(hdf5Path); // 테스트 파일 생성
// 방법 1: 완전 경로를 통해 데이터셋 접근
Console.WriteLine("=== 방법 1: 완전 경로를 통해 접근 ===");
using (var file = new HDF5File(hdf5Path, H5F.ACC_RDONLY))
{
string datasetPath = "/Device1/temperature";
int datasetId = H5D_Open(file.ID, datasetPath, H5P.DEFAULT);
ReadDatasetData(datasetId);
H5D_Close(datasetId);
}
// 방법 2: ID 체인(부모 ID + 상대 경로)을 통해 데이터셋 접근
Console.WriteLine("\n=== 방법 2: ID 체인을 통해 접근 ===");
using (var file = new HDF5File(hdf5Path, H5F.ACC_RDONLY))
{
// 1. 먼저 그룹 오픈(그룹 ID 획득)
string groupPath = "/Device1";
int groupID = H5G_Open(file.ID, groupPath, H5P.DEFAULT);
// 2. 그룹 ID를 통해 상대 경로로 데이터셋 오픈
string datasetName = "temperature"; // 상대 경로(그룹 내에서 절대 경로)
int datasetId = H5D_Open(groupID, datasetName, H5P.DEFAULT);
ReadDatasetData(datasetId);
// 닫기 순서: 자식부터 부모 순으로
H5D_Close(datasetId);
H5G_Close(groupID);
}
}
// 테스트 파일 생성: /Device1/temperature에 温度 데이터 저장
static void CreateTestFile(string path)
{
int fileID = H5F_Create(path, H5F.ACC_TRUNC, H5P.DEFAULT, H5P.DEFAULT);
int groupID = H5G_Create(fileID, "/Device1", H5P.DEFAULT, H5P.DEFAULT, H5P.DEFAULT);
float[] data = { 23.5f, 24.1f, 23.9f };
long[] dims = { data.Length };
int spaceID = H5S_CreateSimple(1, dims, null);
int datasetID = H5D_Create(groupID, "temperature", H5T.IEEE_F32LE, spaceID, H5P.DEFAULT, H5P.DEFAULT, H5P.DEFAULT);
H5D_Write(datasetID, H5T.IEEE_F32LE, H5S.ALL, H5S.ALL, H5P.DEFAULT, data);
// 리소스 닫기
H5D_Close(datasetID);
H5S_Close(spaceID);
H5G_Close(groupID);
H5F_Close(fileID);
}
// 데이터셋 데이터 읽기 및 출력
static void ReadDatasetData(int datasetID)
{
int spaceID = H5D_GetSpace(datasetID);
long[] dims = new long[1];
H5S_GetSimpleExtentDims(spaceID, dims, null);
float[] data = new float[dims[0]];
H5D_Read(datasetID, H5T.IEEE_F32LE, H5S.ALL, H5S.ALL, H5P.DEFAULT, data);
Console.Write("데이터: ");
foreach (var value in data)
{
Console.Write($"{value} ");
}
Console.WriteLine();
H5S_Close(spaceID);
}
}
// 간단히 HDF5 파일 작업을 封裝한 클래스, 자동으로 닫기 수행
class HDF5File : IDisposable
{
public int ID { get; private set; }
public HDF5File(string path, H5F.accesstype access)
{
ID = H5F_Open(path, access, H5P.DEFAULT);
}
public void Dispose()
{
if (ID >= 0)
H5F_Close(ID);
}
}
}
4. 실행 결과
=== 방법 1: 완전 경로를 통해 접근 ===
데이터: 23.5 24.1 23.9
=== 방법 2: ID 체인을 통해 접근 ===
데이터: 23.5 24.1 23.9
두 방법 모두 같은 데이터를 읽어내며, 경로와 ID가 객체 접근에 동등하게 유효하다는 것을 입증합니다.
5. 중요 세부사항 및 최선의实践
- 루트 노드의 ID는 파일 ID와 같음
루트 노드(
/)는 별도의 오픈 메서드가 없으며, ID는 파일 ID와 같습니다. 예를 들어 루트 노드 ID를 통해 그룹을 오픈할 수 있습니다:
// 파일 ID(루트 노드 ID)를 통해 그룹 오픈
int groupID = H5G_Open(fileID, "/Device1", H5P.DEFAULT);
- 속성(Attributes)의 접근도 두 가지 방법 지원 속성은 반드시某个 객체(루트/그룹/데이터셋)에 기반해야 하며, 접근 시 해당 객체의 ID를 먼저 획득해야 합니다:
// 데이터셋 ID를 통해 속성 오픈
int attrID = H5A_Open(datasetID, "Unit");
- ID의 라이프사이클 관리가 핵심
- 모든 ID는 수동적으로 닫아야 하며, "자식 객체부터 부모 객체 순으로" 닫는 것이 중요합니다(예: 데이터셋 → 그룹 → 파일).
try-finally나IDisposable을 활용하여 닫기 보장(예제 중의HDF5File클래스 참조).
- 접근 방법의 선택
- 단일 접근: 경로 사용이 더 간편합니다(한 줄의 코드로 바로的目的에 도달).
- 같은 객체나 그 자식 객체를 여러 번 접근할 때: ID 체인 사용이 효율적입니다(경로 문자열을 반복적으로 해석하는 부담을 없애기 위해).
6. 요약
- ID는 HDF5 객체의 "작업 핸들": 루트 노드, 그룹, 데이터셋, 속성 모두 ID를 가지고 있습니다. 이 ID를 통해 모든 작업을 수행할 수 있습니다.
- 경로는 객체의 "위치 주소": 경로를 통해 ID를 획득한 후 작업을 수행할 수 있습니다.
- 두 방법은 동등한 접근 방법: 어떤 방법을 선택하느냐는 사용 상황에 따라 달라집니다(단일 접근은 경로, 반복적 접근은 ID 체인이 유리).
HDF5 작업을 이해하려면 경로와 ID의 관계를 명확히 이해하는 것이 핵심입니다. 앞으로 더 복잡한 구조를 다룰 때에도 이 두 가지 방법은 기본이 됩니다.