Diff/compare 两个文件按文件描述符 (fd) 而不是文件名
Diff/compare two files by file descriptor (fd) instead of file name
在 Linux 中有什么方法可以使用 c 生成存储在内存中的两个文件的 diff/patch,使用通用格式(即:统一差异,如命令行 diff
实用程序)?
我正在使用一个系统,在该系统中我在内存中生成了两个文本文件,但没有可用或不需要的外部存储。我需要创建这两个文件的逐行差异,并且由于它们是 mmap
ed,所以它们没有文件名,这使我无法简单地调用 system("diff file1.txt file2.txt")
.
我有可用的文件描述符 (fd
s),这是我访问数据的唯一入口点。有什么方法可以通过比较两个打开的文件来生成 diff/patch 吗?如果实现是 MIT/BSD 许可的(即:非 GPL),那就更好了。
谢谢。
在 Linux 上,您可以使用 /dev/fd/ 伪文件系统(符号 link 到 /proc/self/fd)。使用 snprintf() 为两个文件描述符构造路径,例如 snprintf(path1, PATH_MAX, "/dev/fd/%d", fd1);
同上 fd2 和 运行 diff
考虑到需求,最好的选择是实施您自己的 in-memory diff -au
。您或许可以根据自己的需要调整 OpenBSD diff
的相关部分。
这里概述了如何通过管道使用 /usr/bin/diff
命令来获取存储在内存中的两个字符串之间的统一差异:
创建三个管道:I1、I2和O .
分叉一个 child 进程。
在child进程中:
将管道I1和I2的读端移到描述符3和4,写端管道 O 到描述符 1.
关闭 child 进程中那些管道的另一端。打开描述符 0 以从 /dev/null 读取,并打开描述符 2 以写入 /dev/null.
执行execl("/usr/bin/diff", "diff", "-au", "/proc/self/fd/3", "/proc/self/fd/4", NULL);
这会在 child 进程中执行 diff
二进制文件。它将从两个管道 I1 和 I2 读取输入,并将差异输出到管道 O.
parent进程关闭了I1和I2管道的读端,并且写入 O 管道的末端。
parent进程将比较数据写入I1和I2管道的写端, 并从 O 管道的读取端读取差异。
注意parent进程必须使用select()
or poll()
或类似的方法(最好使用非阻塞描述符)来避免死锁。 (如果 parent 和 child 尝试同时读取或同时写入,则会发生死锁。)通常, parent 进程必须不惜一切代价避免阻塞,因为那很可能会导致死锁。
当输入数据完全写入后,parent进程必须关闭相应的管道写入端,以便child进程检测到end-of-input。 (除非发生错误,否则写结束必须在 child 进程关闭其 O 管道的末端之前关闭。)
当 parent 进程注意到 O 管道中没有更多数据可用时(read()
返回 0
),要么已经关闭了 I1 和 I2 管道的写入端,或者出现错误。如果没有报错,则数据传输完成,可以重新进行child过程。
parent 进程使用例如收获 child waitpid()
。请注意,如果有任何差异,diff
returns 退出状态为 1.
您可以使用第四个管道从 child 进程接收标准错误流; diff
通常不会向标准错误输出任何内容。
您可以使用第五个管道,在 child 中用 fcntl()
写入标记为 O_CLOEXEC
的结尾,以检测 execl()
错误。 O_CLOEXEC
标志表示描述符在执行另一个二进制文件时关闭,因此parent进程可以通过检测读取端的end-of-data来检测diff
命令是否成功启动(read()
返回 0
)。如果 execl()
失败,child 可以,例如将 errno
值(作为十进制数,或作为 int
)写入此管道,以便 parent 进程可以读取失败的确切原因。
整个方法(既记录标准错误又检测执行错误)总共使用了 10 个描述符。这在普通应用程序中应该不是问题,但可能很重要——例如,考虑一个 internet-facing 服务器,其描述符被传入连接使用。
在 Linux 中有什么方法可以使用 c 生成存储在内存中的两个文件的 diff/patch,使用通用格式(即:统一差异,如命令行 diff
实用程序)?
我正在使用一个系统,在该系统中我在内存中生成了两个文本文件,但没有可用或不需要的外部存储。我需要创建这两个文件的逐行差异,并且由于它们是 mmap
ed,所以它们没有文件名,这使我无法简单地调用 system("diff file1.txt file2.txt")
.
我有可用的文件描述符 (fd
s),这是我访问数据的唯一入口点。有什么方法可以通过比较两个打开的文件来生成 diff/patch 吗?如果实现是 MIT/BSD 许可的(即:非 GPL),那就更好了。
谢谢。
在 Linux 上,您可以使用 /dev/fd/ 伪文件系统(符号 link 到 /proc/self/fd)。使用 snprintf() 为两个文件描述符构造路径,例如 snprintf(path1, PATH_MAX, "/dev/fd/%d", fd1);
同上 fd2 和 运行 diff
考虑到需求,最好的选择是实施您自己的 in-memory diff -au
。您或许可以根据自己的需要调整 OpenBSD diff
的相关部分。
这里概述了如何通过管道使用 /usr/bin/diff
命令来获取存储在内存中的两个字符串之间的统一差异:
创建三个管道:I1、I2和O .
分叉一个 child 进程。
在child进程中:
将管道I1和I2的读端移到描述符3和4,写端管道 O 到描述符 1.
关闭 child 进程中那些管道的另一端。打开描述符 0 以从 /dev/null 读取,并打开描述符 2 以写入 /dev/null.
执行
execl("/usr/bin/diff", "diff", "-au", "/proc/self/fd/3", "/proc/self/fd/4", NULL);
这会在 child 进程中执行
diff
二进制文件。它将从两个管道 I1 和 I2 读取输入,并将差异输出到管道 O.
parent进程关闭了I1和I2管道的读端,并且写入 O 管道的末端。
parent进程将比较数据写入I1和I2管道的写端, 并从 O 管道的读取端读取差异。
注意parent进程必须使用
select()
orpoll()
或类似的方法(最好使用非阻塞描述符)来避免死锁。 (如果 parent 和 child 尝试同时读取或同时写入,则会发生死锁。)通常, parent 进程必须不惜一切代价避免阻塞,因为那很可能会导致死锁。当输入数据完全写入后,parent进程必须关闭相应的管道写入端,以便child进程检测到end-of-input。 (除非发生错误,否则写结束必须在 child 进程关闭其 O 管道的末端之前关闭。)
当 parent 进程注意到 O 管道中没有更多数据可用时(
read()
返回0
),要么已经关闭了 I1 和 I2 管道的写入端,或者出现错误。如果没有报错,则数据传输完成,可以重新进行child过程。parent 进程使用例如收获 child
waitpid()
。请注意,如果有任何差异,diff
returns 退出状态为 1.
您可以使用第四个管道从 child 进程接收标准错误流; diff
通常不会向标准错误输出任何内容。
您可以使用第五个管道,在 child 中用 fcntl()
写入标记为 O_CLOEXEC
的结尾,以检测 execl()
错误。 O_CLOEXEC
标志表示描述符在执行另一个二进制文件时关闭,因此parent进程可以通过检测读取端的end-of-data来检测diff
命令是否成功启动(read()
返回 0
)。如果 execl()
失败,child 可以,例如将 errno
值(作为十进制数,或作为 int
)写入此管道,以便 parent 进程可以读取失败的确切原因。
整个方法(既记录标准错误又检测执行错误)总共使用了 10 个描述符。这在普通应用程序中应该不是问题,但可能很重要——例如,考虑一个 internet-facing 服务器,其描述符被传入连接使用。