Is there a Windows equivalent to fdopen for HANDLEs?

前端 未结 2 1787
滥情空心
滥情空心 2020-11-27 18:01

In Unix, if you have a file descriptor (e.g. from a socket, pipe, or inherited from your parent process), you can open a buffered I/O FILE* stream on it with fd

相关标签:
2条回答
  • 2020-11-27 18:32

    Unfortunately, HANDLEs are completely different beasts from FILE*s and file descriptors. The CRT ultimately handles files in terms of HANDLEs and associates those HANDLEs to a file descriptor. Those file descriptors in turn backs the structure pointer by FILE*.

    Fortunately, there is a section on this MSDN page that describes functions that "provide a way to change the representation of the file between a FILE structure, a file descriptor, and a Win32 file handle":

    • _fdopen, _wfdopen: Associates a stream with a file that was previously opened for low-level I/O and returns a pointer to the open stream.
    • _fileno: Gets the file descriptor associated with a stream.
    • _get_osfhandle: Return operating-system file handle associated with existing C run-time file descriptor
    • _open_osfhandle: Associates C run-time file descriptor with an existing operating-system file handle.

    Looks like what you need is _open_osfhandle followed by _fdopen to obtain a FILE* from a HANDLE.

    Here's an example involving HANDLEs obtained from CreateFile(). When I tested it, it shows the first 255 characters of the file "test.txt" and appends " --- Hello World! --- " at the end of the file:

    #include <windows.h>
    #include <io.h>
    #include <fcntl.h>
    #include <cstdio>
    
    int main()
    {
        HANDLE h = CreateFile("test.txt", GENERIC_READ | GENERIC_WRITE, 0, 0,
            OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
        if(h != INVALID_HANDLE_VALUE)
        {
            int fd = _open_osfhandle((intptr_t)h, _O_APPEND | _O_RDONLY);
            if(fd != -1)
            {
                FILE* f = _fdopen(fd, "a+");
                if(f != 0)
                {
                    char rbuffer[256];
                    memset(rbuffer, 0, 256);
                    fread(rbuffer, 1, 255, f);
                    printf("read: %s\n", rbuffer);
                    fseek(f, 0, SEEK_CUR); // Switch from read to write
                    const char* wbuffer = " --- Hello World! --- \n";
                    fwrite(wbuffer, 1, strlen(wbuffer), f);
                    fclose(f); // Also calls _close()
                }
                else
                {
                    _close(fd); // Also calls CloseHandle()
                }
            }
            else
            {
                CloseHandle(h);
            }
        }
    }
    

    This should work for pipes as well.

    0 讨论(0)
  • 2020-11-27 18:44

    Here is a more elegant way of doing this instead of CreateFile: specify "N" in fopen(). It's a Microsoft-specific extension to fopen, but since this code is platform-specific anyway, it's ok. When called with "N", fopen adds _O_NOINHERIT flag when calling _open internally.

    Based on this: Windows C Run-Time _close(fd) not closing file

    0 讨论(0)
提交回复
热议问题