Linux编程入门(3)-文件读写操作(cp指令实现)
学习目标
通过分析 cp 指令,来学习 Linux 编程读写文件操作。
代码实验环境
操作系统:Ubuntu 18.04 LTS
编译器gcc版本:gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
cp指令介绍
cp 指令主要用于复制文件或者目录。
典型用法:
cp [options] source dest
详细的选项参数说明可以查阅相关资料。此处只介绍 cp 指令复制文件的功能。
如果目标文件 dest 不存在,则 cp 会创建这个文件。如果存在,则用 source 文件的内容覆盖 dest 文件。
cp如何复制文件
实现 cp 指令的复制文件功能有两个关键点:首先,需要能够创建一个新文件或者清空已有文件。其次,能够把原文件的内容写入到目标文件中。
- 创建文件
Linux 有一个系统函数 creat() 既能新创建一个文件,也能清空已有文件。其函数原型如下:
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int creat(const char *pathname, mode_t mode);
参数 pathname,为文件名
参数 mode,文件访问模式。模式定义如下,
S_IRWXU 00700 文件所有者拥有读、写、执行权限 S_IRUSR 00400 文件所有者拥有读权限 S_IWUSR 00200 文件所有者拥有写权限 S_IXUSR 00100 文件所有者拥有执行权限 S_IRWXG 00070 同组用户拥有读、写、执行权限 S_IRGRP 00040 同组用户拥有读权限 S_IWGRP 00020 同组用户拥有写权限 S_IXGRP 00010 同组用户拥有执行权限 S_IRWXO 00007 其他用户拥有读、写、执行权限 S_IROTH 00004 其他用户拥有读权限 S_IWOTH 00002 其他用户拥有写权限 S_IXOTH 00001 其他用户拥有执行权限
此函数等效于,利用 open 函数实现创建新文件或者清空已有文件,并打开此文件:
open(const char * pathname, (O_CREAT | O_WRONLY | O_TRUNC), mode_t mode);
creat() 函数告诉内核创建一个名字为 pathname 的文件,如果不存在,就创建它;如果存在就把它的内容清空,文件长度设置为 0。
创建成功,会返回一个指向此文件的文件描述符。创建失败,则返回 -1 。
文件创建成功后,文件的访问许可位,被设置为 mode 参数的值。
- 写文件
写文件系统调用函数为 write(),函数原型如下
#include <unistd.h> ssize_t write(int fd, const void *buf, size_t count);
参数 fd,为文件描述符。
参数 buf,存储写入数据的内存指针(地址)。
参数 count,为要写入数据的字节个数。
这个系统调用函数告诉内核将内存中指定的数据写入文件。如果内核不能写入或者写入失败,wirte 返回 -1。如果写入成功,则返回实际写入的字节数。
有时候会出现,写入的字节数少于要求的数目。原因有二:(1)有的系统对文件的最大尺寸有限制;(2)磁盘空间接近满了。
内核会尽量把数据写入文件,并将实际写入的字节数返回。
编写 cp 代码
程序的执行流程:
编写程序代码 cp1.c :
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<fcntl.h> #include<sys/types.h> #include<sys/stat.h> /* 定义缓冲区大小的宏 */ #define BUFFSIZE 4096 /* 文件访问模式,文件所有者拥有读写权限,同组用户拥有读权限,其他用户拥有读权限 */ #define COPYMODE 0644 /* 错误信息显示函数 */ void oops(char *s1, char *s2); int main(int ac, char *av[]) { int in_fd, out_fd, n_chars; char buf[BUFFSIZE]; /* 判断参数个数 */ if(ac != 3) { fprintf(stderr, "usage: %s source destination\n", *av); exit(1); } /* 打开原文件 */ if((in_fd = open(av[1], O_RDONLY)) == -1) { oops("Cannot open ", av[1]); } /* 创建目标文件 */ if((out_fd = creat(av[2], COPYMODE)) == -1) { oops("Cannot creat ", av[2]); } /* 读原文件内容,并判断读取的字节数是否大于 0 */ while((n_chars = read(in_fd, buf, BUFFSIZE)) > 0) { /* 将读取的数据写入文件 */ if(write(out_fd, buf, n_chars) != n_chars) { oops("Write error to ", av[2]); } } /* 如果读文件出错,给出错误信息 */ if(n_chars == -1) { oops("Read error from ", av[1]); } /* 关闭原文件和目标文件 */ if((close(in_fd) == -1) || (close(out_fd) == -1)) { oops("Error closing files", ""); } } /* 错误信息输出 */ void oops(char *s1, char *s2) { fprintf(stderr, "Error: %s", s1); perror(s2); exit(1); }
编译,并测试以上代码:
$ gcc cp1.c -o cp1 $ ./cp1 test test_cp1 $ ls test test_cp1 -l -rwxrwxr-x 1 user user 8728 11月 3 00:10 test -rw-r--r-- 1 user user 8728 11月 3 00:12 test_cp1
可以看到我们编写的程序能正常运行,可以完成文件的复制工作。原文件和目标文件的大小和内容相同。
看看程序对错误输入的反应:
$ ./cp1 tes test_cp1 Error: Cannot open tes: No such file or directory $ ./cp1 test usage: ./cp1 source destination $ ./cp1 test /tmp Error: Cannot creat /tmp: Is a directory
总结
通过分析 cp 指令的原理,完成 cp 复制文件的功能代码,学习了 Linux 编程实现对文件的读写操作。
涉及到的系统函数:
- open 打开一个文件
- creat 创建一个文件
- read 读取文件内容
- write 向文件写入数据
- close 关闭打开的文件
关注公众号【一起学嵌入式】,获取更多技术干货。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)