热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Linux编程入门(3)文件读写操作(cp指令实现)

学习目标通过分析cp指令,来学习Linux编程读写文件操作。代码实验环境操作系统:Ubuntu18.04LTS编译器gcc版本:gcc(Ubuntu7.5.0-3ubuntu1~1

学习目标

通过分析 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 指令的复制文件功能有两个关键点:首先,需要能够创建一个新文件或者清空已有文件。其次,能够把原文件的内容写入到目标文件中。



  1. 创建文件

Linux 有一个系统函数 creat() 既能新创建一个文件,也能清空已有文件。其函数原型如下:

#include
#include
#include
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 参数的值。



  1. 写文件

写文件系统调用函数为 write(),函数原型如下

#include
ssize_t write(int fd, const void *buf, size_t count);

参数 fd,为文件描述符。

参数 buf,存储写入数据的内存指针(地址)。

参数 count,为要写入数据的字节个数。

这个系统调用函数告诉内核将内存中指定的数据写入文件。如果内核不能写入或者写入失败,wirte 返回 -1。如果写入成功,则返回实际写入的字节数。

有时候会出现,写入的字节数少于要求的数目。原因有二:(1)有的系统对文件的最大尺寸有限制;(2)磁盘空间接近满了。

内核会尽量把数据写入文件,并将实际写入的字节数返回。


编写 cp 代码

程序的执行流程:

编写程序代码 cp1.c :

#include
#include
#include
#include
#include
#include
/* 定义缓冲区大小的宏 */
#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 关闭打开的文件



关注公众号【一起学嵌入式】,获取更多技术干货。


原文链接:https://www.cnblogs.com/zppsky16/p/15726205.html



推荐阅读
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • Python如何调用类里面的方法
    本文介绍了在Python中调用同一个类中的方法需要加上self参数,并且规范写法要求每个函数的第一个参数都为self。同时还介绍了如何调用另一个类中的方法。详细内容请阅读剩余部分。 ... [详细]
  • 本文介绍了一个程序,可以输出1000内能被3整除且个位数为6的所有整数。程序使用了循环和条件判断语句来筛选符合条件的整数,并将其输出。 ... [详细]
  • PHPMailer邮件类邮件发送功能的使用教学及注意事项
    本文介绍了使用国外开源码PHPMailer邮件类实现邮件发送功能的简单教学,同时提供了一些注意事项。文章涵盖了字符集设置、发送HTML格式邮件、群发邮件以及避免类的重定义等方面的内容。此外,还提供了一些与PHP相关的资源和服务,如传奇手游游戏源码下载、vscode字体调整、数据恢复、Ubuntu实验环境搭建、北京爬虫市场、进阶PHP和SEO人员需注意的内容。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • 本文介绍了在多平台下进行条件编译的必要性,以及具体的实现方法。通过示例代码展示了如何使用条件编译来实现不同平台的功能。最后总结了只要接口相同,不同平台下的编译运行结果也会相同。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
author-avatar
木_妍_595
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有