如何在Linux中使用C语言编写文件?

10

我想重写Linux的"cp"命令。所以这个程序将工作如下:#./a.out originalfile copiedfile。我可以打开文件,创建新文件但无法写入新文件。没有任何内容被写入。可能是什么原因?

当前的C代码如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char *aa[]){
    int fd,fd1;
    char buffer[100];

    if(argc!=3){
        printf("Usage : ./a.out <original> <copy> \n");
        return -1;
    }

    fd=open(aa[1],O_RDONLY,S_IRUSR);
    if(fd==-1){
        printf("file not found.\n");
        return -1;
    }
    fd1=open(aa[2],O_CREAT | O_WRONLY,S_IRUSR);
    if(fd1!=-1){
        printf("file is created.\n");
    }
    ssize_t n;
    while(n=read(fd,buffer,50)){
        write(fd1,buffer,n);
        printf("..writing..\n");
    }
    close(fd);
    close(fd1);
}

2
未使用的变量fd2;不要忘记检查write是否写入了您预期的所有内容;不要将赋值用作条件(使用GCC -Wall);尽管C99(错误地)允许您在main()中省略返回,但最好还是从main()返回一个值。fd1的错误消息不正确;当fd1失败时,您不会退出。您可以在读取中使用sizeof(buffer)而不是50,后者是缓冲区大小的一半。错误经典地写入stderr,而不是stdout。如果读取失败(返回负值),则您的循环会遇到问题,而不是返回空值。 - Jonathan Leffler
我只是将你的代码复制粘贴到我的电脑上,使用gcc编译,它可以正常工作。 - Dipstick
1
哦,神奇的事情发生了。因为你的评论,我尝试将文件移动到另一个位置并再次测试。它成功了!!!非常感谢你。 - Devyn
也许如果您在目标文件打开后更改条件检查,以便如果失败,则打印errno和错误消息(当然是到stderr),那么您将更好地了解为什么没有写入任何内容。良好的C编程实践是始终检查系统调用的错误返回。 - mpez0
4个回答

15

你需要将read()方法获取到的数据使用write()方法写入到新文件中:

ssize_t nrd;
int fd;
int fd1;

fd = open(aa[1], O_RDONLY);
fd1 = open(aa[2], O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
while (nrd = read(fd,buffer,50)) {
    write(fd1,buffer,nrd);
}

close(fd);
close(fd1);

更新:添加了正确的打开方式…

顺便说一句,可以使用 OR 运算符将 O_CREAT(O_CREAT | O_WRONLY)合并起来。您实际上正在打开过多的文件句柄。只需执行一次打开操作即可。


嗨,谢谢回复。我用新代码编辑了我的帖子。我按照你说的尝试了,但仍然不起作用。没有任何内容被写入新文件。请帮帮我! - Devyn
抱歉,但仍然无法工作。我在while循环中放了一些字符串,结果显示while循环只执行了一次。:( - Devyn
1
是的,我的代码并不完美,但它可以给你一个正确方向的推动。继续尝试吧。就像乔纳森在你的帖子中所说的那样,你的代码有很多问题。你需要检查read()返回值是否为0。此外,你可能需要使用sizeof(buffer)而不是50。但我只是想给你一个有用的提示,而不是剥夺你自己找答案的乐趣/挫败感。 - dlamotte
我同意你的观点,但有时候我们没有足够的时间自己找出答案。实际上,我总是自己找到解决方案,但对于这个问题,我明天要考试了。我已经为这个问题花费了几个小时。无论如何,还是谢谢你的帮助! - Devyn
1
@Devyn 通常当有人没有时间完成一个任务时,他们会付钱请别人来完成。我希望在我工作过多的时候可以得到免费编程帮助。 :) - William

12

首先,即使您让它能够工作,您编写的代码也不具备可移植性。为什么要使用特定于操作系统的函数,而不是使用完全与平台无关的方法呢?这里有一个版本仅使用单个标头文件,并且在实现C标准库的任何平台上都可以使用。

#include <stdio.h>

int main(int argc, char **argv)
{
    FILE* sourceFile;
    FILE* destFile;
    char buf[50];
    int numBytes;

    if(argc!=3)
    {
        printf("Usage: fcopy source destination\n");
        return 1;
    }

    sourceFile = fopen(argv[1], "rb");
    destFile = fopen(argv[2], "wb");

    if(sourceFile==NULL)
    {
        printf("Could not open source file\n");
        return 2;
    }
    if(destFile==NULL)
    {
        printf("Could not open destination file\n");
        return 3;
    }

    while(numBytes=fread(buf, 1, 50, sourceFile))
    {
        fwrite(buf, 1, numBytes, destFile);
    }

    fclose(sourceFile);
    fclose(destFile);

    return 0;
}

编辑: glibc参考文献如下所述:

一般来说,除非有特定的操作只能在文件描述符上进行,否则您应该坚持使用流而不是文件描述符。如果您是一位初学者程序员,并且不确定要使用哪些函数,我们建议您集中精力处理格式化输入函数(请参见格式化输入)和格式化输出函数(请参见格式化输出)。

如果您担心将您的程序移植到GNU以外的系统时可移植性问题,您还应该知道文件描述符并不像流那样具有可移植性。您可以期望任何运行ISO C的系统支持流,但非GNU系统可能根本不支持文件描述符,或者仅实现对文件描述符进行操作的GNU函数的子集。然而,GNU库中的大多数文件描述符函数都包含在POSIX.1标准中。


我认为你提到使用流很有道理...(我没有给你点踩),但我会给你点赞让你回到零分。 - dlamotte
我并不介意被踩,我更关心的是为什么会被踩。无论是正面还是负面的反馈,都可以帮助我提高自己。如果我在帮助别人的同时也能做到这一点,那就再好不过了。 - Chinmay Kanchi
我也没有给你的回答点踩。你的解决方案并不是“完美”的 - 你可能知道 - 但我会点赞。只是为了促使那个点踩者解释原因。 - anon
是的,我知道这个解决方案并不完美。这只是我在休息期间匆忙编写的东西,旨在说明问题,而不是用于生产环境... - Chinmay Kanchi

3

你需要在同一循环中进行操作。


2

您需要使用malloc函数来分配缓冲区,并将读写指针指向它。

#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(){
    ssize_t nrd;
    int fd; 
    int fd1;

    char* buffer = malloc(100*sizeof(char));
    fd = open("bli.txt", O_RDONLY);
    fd1 = open("bla.txt", O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
    while (nrd = read(fd,buffer,sizeof(buffer))) {
        write(fd1,buffer,nrd);
    }   

    close(fd);
    close(fd1);
    free(buffer);
    return 0;
}

确保rad文件存在并且包含内容。虽然不完美,但它能够正常工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接