【问题标题】:how to copy a file in c byte by byte如何逐字节复制c中的文件
【发布时间】:2021-11-26 07:04:15
【问题描述】:

好的,所以我正在学习 C 并且在一本教科书中,有一个练习留给读者,这本书解释了一个文件(或至少是一个常规文件)只是一个字节数组。据我了解,在 linux 中,每个块都是 512 字节,但是当您将文件读入文件描述符时,程序会自动加载整个文件,这可能是正确的吗? 这本书回顾了 Linux 系统调用read, write, and lseek(一些基本的低级调用)。

现在的目标就像我说的将文件逐字节复制到一些随机的新文件中。伪代码将是完全可以接受的。无论如何,我的理解是您需要

我的理解是构建会是这样的:

#include <all of the req'd headers>

int main(int argc,char** argv) {
    char buff[1]; // byte by byte buffer 
    inf fd = open("filename", O_RDONLY);
    
    int fdp[2]; // for the pipe's fd's
    pipe(fdp);
    
    if( fork() == 0 ) {
        close(fdp[0]);
        
    }

    else {
        write("newfile", buff, 1);
    }

}

至少在现阶段对我来说,这确实是一个相当复杂的问题。我的想法是将文件的全部内容读入文件描述符,然后使用管道逐字节写入新文件,将前一个文件的全部内容复制到新文件中。 我也不确定 lseek 在这种情况下如何帮助我们。或者我是否过于复杂化并且方向完全错误?

【问题讨论】:

  • 不,管道帮不了你。您在循环中读/写或使用copy_file_range linux 系统调用
  • 你在错误的方向迷路了。这里根本不需要pipe,也不需要文件描述符。你需要一个简单的循环。 完整的解决方案是您的工作,而不是我们的工作。如果我们做所有的工作,它就违背了练习的目的。
  • @KenWhite 好吧,我很抱歉,你被冒犯了,但循环的伪代码会是什么样子
  • 'open' 更像是一个 'C++' 的东西。您是否考虑过使用 C 系列函数 fopenfreadfwrite?打开两个文件(有一些函数可以获取“随机文件名”),一个用于读取,另一个用于写入,将源文件读入数组并将字节写入目标文件。最后,关闭这两个文件就完成了。
  • 就像'一次一个字节'?好吧,那就使用fgetcfputc。这是非常低效的,但它应该仍然有效。

标签: c pipe fork lseek


【解决方案1】:

正如 cmets 中所述,您根本不需要管道。遵守“一次一个字节”的要求,您的代码可能如下所示:

FILE *in = fopen("sourceFile", "rb");
    
if (in)
{
    FILE *out = tmpfile();
    if (out)
    {
        int c;
        while ((c = fgetc(in)) != EOF)
            fputc(c, out);
        fclose(out);
    }
    fclose(in);
}

你就完成了。 请记住,一旦你关闭它,tmpfile 就会被删除,所以你可能想在关闭它之前对它的内容做一些事情。或者打开一个更永久的文件。

【讨论】:

  • 感谢您的回复,我的朋友,但这并没有使用读/写限制
  • 哪个?你一次只读/写一个字符?确实如此。我从文件中读取了一个字符(c)并将其放入文件中。一次一个字节。如果int 让您失望,我们需要它来检测文件结束 (EOF),以便我们知道何时停止阅读。
  • 对不起,如果我所说的混淆了英语是我的第二语言,请查看我对我所指的解决方案的回答,我们都发布了工作并解决了这种情况!
  • @yesitsme 是的,您的解决方案与我的解决方案基本相同,只是您使用的是缓冲读取(如:缓冲区可以是任何大小),而我的解决方案使用 '一个字符一次”,如果不更改使用的功能,则无法更改。但是,是的,两者都有效。
  • 正确,但我的 char "oneByte" 完全限制为一个字节,因为它只包含 1 个字符或 "byte"
【解决方案2】:

好的,我发现解决方案实际上非常简单!这里只有大约 10 行代码:

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>



int main(int argc, char ** argv) { 
    
    char oneByte;
    
    int n;
    int source;
    int destination;
    
    source = open("notes.txt", O_RDONLY);
    destination = open("copiedFile.txt", O_RDWR | O_CREAT, 0644);
    
    while ((n = read(source, &oneByte, 1)) > 0) {
        write(destination, &oneByte, 1);
    }
    
    close(source);
    close(destination);
    
    return 0;
}

【讨论】:

  • 是的,这也有效。尝试仅包含所需的标题。你不需要,例如stdio.hstdbool.h。此外,由于您不使用argcargv(您应该将要读取的文件名作为第一个参数传递,将要写入的文件名作为第二个参数传递)。如果没有,您的调用应该是int main (void) 请参阅:C11 Standard - §5.1.2.2.1 Program startup(p1)。另见:What should main() return in C and C++?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-15
  • 2010-11-22
  • 2015-08-05
  • 2013-12-06
相关资源
最近更新 更多