通过文件描述符(fd)来比较两个文件,而不是文件名

有没有什么办法可以在Linux中用c来生成一个存储在内存中的两个文件的diff / patch,使用一个通用的格式(比如统一的diff,就像命令行diff工具一样)?

我正在一个系统中,我在内存中生成两个文本文件,并没有外部存储可用,或期望的。 我需要创build两个文件的逐行比较,因为他们是mmap ,他们没有文件名,阻止我简单地调用system("diff file1.txt file2.txt")

我有文件描述符( fd s)可供使用,这是我唯一的数据入口点。 有什么办法通过比较两个打开的文件来生成差异/补丁? 如果实施是MIT / BSD许可的(即:非GPL),则更好。

谢谢。

Solutions Collecting From Web of "通过文件描述符(fd)来比较两个文件,而不是文件名"

考虑到这些要求,最好的选择是实现你自己的内存diff -au 。 你也许可以根据你的需要来调整OpenBSD diff的相关部分。


下面概述一个如何通过管道使用/usr/bin/diff命令来获得存储在内存中的两个字符串之间的统一差异:

  1. 创建三个管道: I1I2O.

  2. 分叉一个孩子的过程。

  3. 在子进程中:

    1. 将管道I1I2的读取端移到描述符3和4,管道O的写入端移到描述符1。

    2. 在子进程中关闭这些管道的另一端。 打开描述符0从/ dev / null读取,描述符2写入/ dev / null。

    3. 执行execl("/usr/bin/diff", "diff", "-au", "/proc/self/fd/3", "/proc/self/fd/4", NULL);

      这将在子进程中执行diff二进制。 它将读取来自两个管道的输入I1I2 ,并将差值输出到管道O.

  4. 父进程关闭I1I2管道的读取结束,以及O管道的写入结束。

  5. 父进程将比较数据写入I1I2管道的写入端,并从O管道的读取端读取差异。

    请注意,父进程必须使用select()poll()或类似的方法(最好使用非阻塞描述符)来避免死锁。 (如果父母和孩子同时尝试读取或同时写入,则发生死锁。)通常,父进程必须避免不惜一切代价阻塞,因为这可能导致死锁。

    当输入数据已被完全写入时,父进程必须关闭管道的相应写端,以便子进程检测到输入结束。 (除非发生错误,写入结束必须在子进程关闭O管道结束之前关闭。)

    当父进程注意到O管道中没有更多数据可用时( read()返回0 ),它可能已经关闭了I1I2管道的写端,或者出现错误。 如果没有错误,数据传输完成,子进程可以收割。

  6. 父进程使用例如waitpid()来收缩子进程。 请注意,如果有差异, diff返回退出状态1。

您可以使用第四个管道从子进程接收标准错误流; diff通常不会输出任何内容到标准错误。

您可以使用第五个管道,在子O_CLOEXEC使用fcntl()将结尾标记为O_CLOEXEC ,以检测execl()错误。 O_CLOEXEC标志表示描述符在执行另一个二进制文件时是关闭的,所以父进程可以通过检测读结束的数据结束( read()返回0 )来检测diff命令是否成功启动。 如果execl()失败,孩子可以例如将errno值(作为一个十进制数字,或作为一个int )写入到这个管道,以便父进程可以读取失败的确切原因。

总之,完整的方法(既记录标准错误,又检测执行错误)使用10个描述符。 这在正常的应用程序中不应该是个问题,但可能很重要 – 例如,考虑面向Internet的服务器,并使用传入连接使用的描述符。

在Linux上,您可以使用/ dev / fd / pseudo文件系统(到/ proc / self / fd的符号链接)。 使用snprintf()为snprintf(path1, PATH_MAX, "/dev/fd/%d", fd1);这两个文件描述符构建路径snprintf(path1, PATH_MAX, "/dev/fd/%d", fd1); 同上fd2并在其上运行diff