【问题标题】:C File descriptor duplication without sharing offset or flags不共享偏移量或标志的 C 文件描述符复制
【发布时间】:2017-07-14 12:53:39
【问题描述】:

我需要使用 C 同时从不同偏移量的文件中读取。 dup 不幸地创建了一个与原始文件共享偏移量和标志的文件描述符。

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

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

编辑这个程序是为 windows 编译的,除了 mac 和许多风格的 linux

解决方案 我们可以在posix系统上使用pread,我为windows写了一个pread函数来解决这个问题 https://github.com/Storj/libstorj/blob/master/src/utils.c#L227

【问题讨论】:

  • open() 文件两次?
  • 我只能访问文件指针。

标签: c linux windows file descriptor


【解决方案1】:

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

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

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

如果文件被重命名或删除,你可能会倒霉。

但是为什么你需要另一个文件描述符?您可以在原始文件描述符上使用pread() 和/或pwrite() 来读取/写入文件而不影响当前偏移量。 (警告:在 Linux 上,pwrite() 以追加模式打开的文件是错误的 - POSIX 声明 pwrite() 以追加模式打开的文件将写入 pwrite() 调用中指定的偏移量,但 Linux @987654332 @实现被破坏,将忽略偏移量并将数据追加到文件末尾 - see the BUGS section of the Linux man page)

【讨论】:

  • 是否也有相应的 Windows 版本?我为许多不同的操作系统编译程序
  • @AlexanderLeitner 这可能是相关的(我没有足够深入的 Windows 编程经验来确定):GetFinalPathNameByHandle
【解决方案2】:

不,C 和 POSIX(因为您提到 dup())都没有基于现有文件句柄打开新的独立文件句柄的功能。正如您所观察到的,您可以dup() 一个文件描述符,但结果引用相同的底层打开文件描述。

要获得一个独立的句柄,你需要open()fopen() 相同的路径(这只有当FILE 引用一个可通过文件系统访问的对象时才有可能)。如果您不知道那是什么路径,或者一开始就没有,那么您将需要一种不同的方法。

需要考虑的一些替代方案:

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

【讨论】:

  • 一个临时的 linux only 解决方案似乎也类似于 sprintf(path, "/proc/self/fd/%d", fileno(state->original_file)); 我这样做的主要原因是因为我停止将任何文件写入磁盘这些是高达数 GB 数据的文件,所以我看来必须查看内存映射文件。
【解决方案3】:

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

这仅适用于 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;
}

【讨论】:

    【解决方案4】:

    我能够在 POSIX 系统上使用 pread 和 pwrite,并将 Windows 系统上的 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 : %d\n", 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 :%d\n", GetLastError());
            return -1;
        }
    
        return written_bytes;
    }
    #endif
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-11
      • 2012-07-15
      • 1970-01-01
      • 2023-03-17
      • 2013-01-03
      • 2011-05-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多