【问题标题】:How to combine two files into a third using only linux system calls?如何仅使用 linux 系统调用将两个文件组合成第三个文件?
【发布时间】:2023-03-13 02:15:01
【问题描述】:

对于与 c 代码交互的 linux 系统调用,我完全是个菜鸟。 到目前为止,我已经能够打开一个文件,但仅此而已。我不确定如何获取第二个文件并将这两个文件合并到第三个文件中。

例如,我的 file1 包含简单的文本内容,而 file2 具有相同的内容,如何仅使用 linux 系统调用将这两个内容合并到 file3 中?我知道我必须使用lseek 来更改指针,但不确定如何使用它。

这是我到目前为止所拥有的……我为稀缺道歉:

这需要 file1 并将其复制到 file2,我相信

#include <fcntl.h>
#include <unistd.h>

int copyfile(const char *file1, const char *file2)
{
    int infile, outfile;
    ssize_t nread;
    char buffer[BUFSIZE]

    if( (infile = open(file1, O_RDONLY)) == -1 )
        return (-1);

    if( (infile = open(file2, O_WRONLY|O_CREATE|O_TRUNC, PERM)) == -1 )
    {
        close (infile);
        return (-2);
    }

    /*read from file1 BUFSIZE chars at a time*/
    while ( nread = read (infile, buffer, BUFSIZE) )
    {
        // write buffer to output file
        if (write (outfile, buffer, nread) < nread)
        {
            close(infile);
            close(outfile);
            return (-3);
        }
    }
    close (infile)
    close (outfile)

    if (nread == -1)
        return (-4);
    else
        return(0);
}

文件将在终端中输入:

lastnameCat.c file1 file2 file3

这样file1和file2相加,发送到file3中。

【问题讨论】:

  • 仅供参考,您可以作弊并做system("cat file1 file2 &gt; file3");。或者只是从 linux shell 中完成,而不是编写 C 程序。
  • 注意:read() 可以返回-1。处理它!
  • @Gillespie 我很乐意这样做,但不幸的是,他们想要一个可以每天为不知道如何运行终端的人执行多次的程序
  • 请始终尝试正确缩进您的代码,这样更容易跟踪和查找错误。
  • @Graeme 很抱歉,感谢 John Kugelman 为我正确缩进

标签: c linux


【解决方案1】:

您可以为此使用copy_file_range 系统调用。它比使用readwrite 调用更快,因为复制是在内核内部完成的。来自man 页面:

copy_file_range() 系统调用在两个文件描述符之间执行内核内复制,而无需将数据从内核传输到用户空间然后再返回内核的额外成本。

这是一个使用它的例子:

#define _GNU_SOURCE
#include <fcntl.h>
#include <limits.h>
#include <stdint.h>
#include <unistd.h>

int do_copy(int infd, int outfd)
{
    ssize_t bytes = 0;
    do
    {
        bytes = copy_file_range(infd, NULL, outfd, NULL, SSIZE_MAX, 0);
    }
    while(SSIZE_MAX == bytes);

    return bytes;
}

int concatenate(const char *inpath1, const char *inpath2, const char *outpath)
{
    int infd1 = -1;
    int infd2 = -1;
    int outfd = -1;
    int res = -1;

    infd1 = open(inpath1, O_RDONLY);
    if(infd1 < 0)
        goto close;

    infd2 = open(inpath2, O_RDONLY);
    if(infd2 < 0)
        goto close;

    outfd = open(outpath, O_WRONLY|O_CREAT|O_TRUNC);
    if(outfd < 0)
        goto close;

    res = do_copy(infd1, outfd);
    if(res < 0)
        goto close;

    res = do_copy(infd2, outfd);

close:
    if(infd1 >= 0)
        close(infd1);

    if(infd2 >= 0)
        close(infd2);

    if(outfd >= 0)
        close(outfd);

    return res;
}

do_copy 中的循环允许非常大的文件,这可能超过一次调用中可能的最大副本数。

【讨论】:

  • 谢谢@Graeme,但在尝试编译gcc lastnameCAT.c -o lastnameCAT /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o: In function _start'时出现此错误:(.text+0x20): undefined reference to main' collect2: error: ld returned 1 exit status
  • @user7823016,这不是一个完整的程序。您收到错误的原因是它没有 main 函数。你必须自己写。这只是如何进行实际复制部分的示例。
  • 哦,当然,你认为我提交的内容是否足够(有足够的调整)作为主要功能?
  • @user7823016,好吧,我在任何地方都没有看到任何实际的文件名......它们来自哪里?命令行参数? scanf?硬编码?
  • 命令行参数。所以它看起来像这样:lastnameCAT.c file1 file2 file3我只是一个实习生,但他们要求它现在是这种格式,我稍后会改变它
【解决方案2】:

根据您的 cmets,这听起来并不必须是一个 C 程序,只要它是用户友好的。只要你能保证它会在 linux 中运行,只需创建一个 shell 脚本并命名为你想要的任何名称。您甚至可以为 shell 脚本命名为与您的 c 程序可执行文件相同的名称,而用户将无法区分:

#!/bin/bash

cat $1 $2 > $3

假设您将此脚本命名为lastnameCat,并使用chmod +x ./lastnameCat 使其可执行。从那时起,您可以这样做:

$ ./lastnameCat file1 file2 file3

也可以将此脚本命名为lastnameCat.c,但我认为这有点欺骗性,因为它不是C 文件,而是bash 脚本。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-22
    • 2012-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-12
    • 2015-12-10
    相关资源
    最近更新 更多