C文件描述符重复,而无需共享偏移或标志



我需要使用C的不同偏移中的文件同时阅读。 dup不正确地创建了一个文件描述符,该文件描述符与原件共享偏移和标志。

是否有像dup这样的函数不共享偏移和标志?

编辑我只能访问文件指针FILE* fp;我没有文件路径

编辑此程序除了Mac和Linux的许多口味外,还为Windows编译了此程序

解决方案我们可以在POSIX系统上使用PREAD,我为Windows编写了一个PREAD功能,该功能解决了此问题https://github.com/storj/libstorj/blob/master/src/src/utils.c#l227

在Linux上,您可以从/proc/self/fd/N恢复文件名,其中N是文件描述符的积分值:

sprintf( linkname, "/proc/self/fd/%d", fd );

然后在生成的链接名称上使用readlink()

如果文件已重命名或删除,您可能会不幸。

但是为什么您需要另一个文件描述符?您可以在原始文件描述符上使用pread()和/或pwrite()在不影响当前偏移的情况下从/写入/写入/写入/写入。(警告:在Linux上,pwrite()到以附加模式打开的文件是错误的-POSIX指出,在附加模式下打开的pwrite()将写入pwrite()调用中指定的偏移量,但Linux pwrite()实现已损坏,并且会忽略该文件。偏移并将数据附加到文件的末尾 - 请参阅Linux Man页面的错误部分)

no,c和posix(因为您提到的dup())都具有基于现有文件句柄打开新的独立文件句柄的功能。如您所观察到的,您可以dup()文件描述符,但结果指的是基础的开放文件描述。

要获得独立的手柄,您需要open()fopen()相同的路径(仅当FILE涉及通过文件系统访问的对象时,才有可能。如果您不知道那是什么路径,或者首先没有任何路径,那么您将需要其他方法。

一些考虑的选择:

  • 缓冲器中的某些或全部文件内容,并根据需要从缓冲区读取以满足您对独立文件偏移的需求;
  • 构建tee命令的内部等效;这可能需要第二个线程,并且您可能无法读取一个文件超过另一个文件,或者在任何一个文件中读取;
  • 将文件内容复制到带有已知名称的临时文件,并根据需要打开多次;
  • 如果文件对应于常规文件,请将其映射到内存中并在那里访问其内容。POSIX函数fmemopen()在这种情况下可能很有用,可以使内存映射适应您现有的基于流的用法。

在Windows上(假设VisualStudio),您可以从STDIO文件句柄中访问OS文件句柄。从那里重新打开并将其转换回新的文件句柄。

这仅是Windows,但我认为Andrews的答案也适用于Linux,可能还可以使用Mac-不幸的是,没有便携式方法可以使其在所有系统上使用。

#include <Windows.h>
#include <fcntl.h>
#include <io.h>  
#include <stdio.h>
FILE *jreopen(FILE* f)
{
    int n = _fileno(f);
    HANDLE h = (HANDLE)_get_osfhandle(n);
    HANDLE h2 = ReOpenFile(h, GENERIC_READ, FILE_SHARE_READ, 0);
    int n2 = _open_osfhandle((intptr_t)h2, _O_RDONLY);
    FILE* g = _fdopen(n2, "r");
    return g;
}

我能够在POSIX系统上使用PREAD和PWRITE,并且我将Windows Systems上的ReadFile/WriteFile包装到PREAD和PWRITE功能

#ifdef _WIN32
ssize_t pread(int fd, void *buf, size_t count, uint64_t offset)
{
    long unsigned int read_bytes = 0;
    OVERLAPPED overlapped;
    memset(&overlapped, 0, sizeof(OVERLAPPED));
    overlapped.OffsetHigh = (uint32_t)((offset & 0xFFFFFFFF00000000LL) >> 32);
    overlapped.Offset = (uint32_t)(offset & 0xFFFFFFFFLL);
    HANDLE file = (HANDLE)_get_osfhandle(fd);
    SetLastError(0);
    bool RF = ReadFile(file, buf, count, &read_bytes, &overlapped);
     // For some reason it errors when it hits end of file so we don't want to check that
    if ((RF == 0) && GetLastError() != ERROR_HANDLE_EOF) {
        errno = GetLastError();
        // printf ("Error reading file : %dn", GetLastError());
        return -1;
    }
    return read_bytes;
}
ssize_t pwrite(int fd, const void *buf, size_t count, uint64_t offset)
{
    long unsigned int written_bytes = 0;
    OVERLAPPED overlapped;
    memset(&overlapped, 0, sizeof(OVERLAPPED));
    overlapped.OffsetHigh = (uint32_t)((offset & 0xFFFFFFFF00000000LL) >> 32);
    overlapped.Offset = (uint32_t)(offset & 0xFFFFFFFFLL);
    HANDLE file = (HANDLE)_get_osfhandle(fd);
    SetLastError(0);
    bool RF = WriteFile(file, buf, count, &written_bytes, &overlapped);
    if ((RF == 0)) {
        errno = GetLastError();
        // printf ("Error reading file :%dn", GetLastError());
        return -1;
    }
    return written_bytes;
}
#endif

最新更新