콘텐츠로 건너뛰기

FILE* from Handle

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*를 생성합니다.

주의 사항

파일 객체를 닫는 함수를 호출할 때 파일 객체를 변경한 시점에 따라 주의를 기울여야 합니다.

파일 생성 함수객체 유형종료 함수
CreateFileFile HandleCloseHandle
_open_osfhandleFile Descriptor_close
_fdopenFILE*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 : 24Code language: TeX (tex)

50번째 라인에서 fclose 함수 대신 _close 함수를 사용할 경우 파일 객체가 정상적으로 닫히지 않아서 errno 24 ( Too many open files ) 오류가 발생함을 확인할 수 있습니다.

50번째 라인을 fclose(fp); 으로 변경 시 정상적으로 동작함을 확인할 수 있습니다.

관련 함수

🚩_open_osfhandle function ( MSDN )

🚩_fdopen function ( MSDN )

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다