¿Existe un equivalente de Windows a fdopen para HANDLE?

3 minutos de lectura

En Unix, si tiene un descriptor de archivo (por ejemplo, de un socket, tubería o heredado de su proceso principal), puede abrir una E/S almacenada en búfer FILE* transmitirlo con fdopen(3).

¿Hay un equivalente en Windows para HANDLE¿s? Si tienes un HANDLE que se heredó de su proceso principal (diferente de stdin, stdout o stderr) o una canalización de CreatePipe¿es posible obtener un búfer FILE* corriente de él? MSDN documenta _fdopenpero eso funciona con descriptores de archivos enteros devueltos por _openno genérico HANDLEs.

avatar de usuario
en silico

Desafortunadamente, HANDLEs son bestias completamente diferentes de FILE*s y descriptores de archivo. El CRT finalmente maneja los archivos en términos de HANDLEs y asociados aquellos HANDLEs a un descriptor de archivo. Esos descriptores de archivo, a su vez, respaldan el puntero de estructura por FILE*.

Afortunadamente, hay una sección sobre esta página de MSDN que describe funciones que “proporcionan una manera de cambiar la representación del archivo entre un EXPEDIENTE estructura, un descriptor de archivo y un identificador de archivo Win32″:

  • _fdopen, _wfdopen: asocia una secuencia con un archivo que se abrió previamente para E/S de bajo nivel y devuelve un puntero a la secuencia abierta.
  • _fileno: Obtiene el descriptor de archivo asociado con una secuencia.
  • _get_osfhandle: devuelve el identificador de archivo del sistema operativo asociado con el descriptor de archivo de tiempo de ejecución de C existente
  • _open_osfhandle: Asocia el descriptor de archivo en tiempo de ejecución de C con un identificador de archivo del sistema operativo existente.

Parece que lo que necesitas es _open_osfhandle seguido por _fdopen para obtener un FILE* a partir de una HANDLE.

He aquí un ejemplo que implica HANDLEse obtiene de CreateFile(). Cuando lo probé, muestra los primeros 255 caracteres del archivo “test.txt” y agrega “— ¡Hola mundo! —” al final del archivo:

#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);
        }
    }
}

Esto también debería funcionar para las tuberías.

Aquí hay una forma más elegante de hacer esto en lugar de CreateFile: especifique “N” en fopen(). Es una extensión específica de Microsoft para fopen, pero dado que este código es específico de la plataforma de todos modos, está bien. Cuando se llama con “N”, fopen agrega el indicador _O_NOINHERIT cuando se llama a _open internamente.

Basado en esto: Windows C Run-Time _close (fd) no cierra el archivo

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad