FILE pointer from HANDLE
윈도우 프로그래밍에서 파일을 처리하는데 있어 Win32 API와 C 런타임 라이브러리를 동시에 사용해야 할 때가 있습니다.
Win32 API에서 생성한 File Handle을 C 런타임의 FILE* 로 변경해보겠습니다.
CreateFile
함수를 사용해 File Handle을 구하고, _open_osfhandle
함수를 사용해 File Descriptor를 구하고, _fdopen
함수를 이용해 FILE*에 스트림을 연결합니다.
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#include <iostream>
#include <string>
int main()
{
std::wstring file_path = L"C:\\Test\\Test.txt";
HANDLE file_handle = CreateFileW(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, nullptr);
if ( file_handle == INVALID_HANDLE_VALUE )
{
std::cout << "CreateFileW Failed : " << GetLastError() << "\n";
return -1;
}
int fd = _open_osfhandle((long)file_handle, _O_BINARY);
if ( fd == -1 )
{
std::cout << "_open_osfhandle Failed : \n";
CloseHandle(file_handle);
return -1;
}
FILE* fp = _fdopen(fd, "wb");
if ( nullptr == fp )
{
std::cout << "_fdopen Failed : " << errno << "\n";
_close(fd);
return -1;
}
fwrite("whalec.io", 9, 1, fp);
fclose(fp);
return 0;
}
Code language: C++ (cpp)
12번째 라인 : CreateFile
함수를 통해서 File Handle을 생성합니다.
22번째 라인 : _open_osfhandle
함수를 통해서 File Descriptor를 생성합니다.
31번째 라인 : _fdopen
함수를 통해서 FILE*를 생성합니다.
주의 사항
파일 객체를 닫는 함수를 호출할 때 파일 객체를 변경한 시점에 따라 주의를 기울여야 합니다.
파일 생성 함수 | 객체 유형 | 종료 함수 |
CreateFile | File Handle | CloseHandle |
_open_osfhandle | File Descriptor | _close |
_fdopen | FILE* | fclose |
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#include <iostream>
#include <string>
int main()
{
for ( int i = 0; i < 1000; i++ )
{
std::cout << "Loop #" << i << "\n";
std::wstring file_path = L"C:\\Test\\Test" + std::to_wstring(i) + L".txt";
HANDLE file_handle = CreateFileW(file_path.c_str(),
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if ( file_handle == INVALID_HANDLE_VALUE )
{
std::cout << "CreateFileW Failed : " << GetLastError() << "\n";
return -1;
}
int fd = _open_osfhandle((long)file_handle, _O_BINARY);
if ( fd == -1 )
{
std::cout << "_open_osfhandle Failed : \n";
CloseHandle(file_handle);
return -1;
}
FILE* fp = _fdopen(fd, "wb");
if ( NULL == fp )
{
std::cout << "_fdopen Failed : " << errno << "\n";
_close(fd);
return -1;
}
fwrite("whalec.io", 9, 1, fp);
_close(fd); // 오류
std::cout << "Loop #" << i << " Success \n";
}
return 0;
}
Code language: C++ (cpp)
결과
Loop #507
Loop #507 Success
Loop #508
Loop #508 Success
Loop #509
_fdopen Failed : 24
Code language: TeX (tex)
50번째 라인에서 fclose
함수 대신 _close
함수를 사용할 경우 파일 객체가 정상적으로 닫히지 않아서 errno 24 ( Too many open files ) 오류가 발생함을 확인할 수 있습니다.
50번째 라인을 fclose(fp);
으로 변경 시 정상적으로 동작함을 확인할 수 있습니다.