linux编程学习6-文件操作之用open、read、write实现文件复制拷贝功能

一、基本概念和常识

1.linux系统中,几乎一切都是文件,所以程序可以像使用文件那样使用打印机,磁盘文件,串行口和其它设备

2.linux系统中,比较重要的文件设备有三个:

/dev/console(系统控制台),错误信息或诊断信息通常会发送到这个设备

/dev/tty(进程的控制终端的别名(逻辑设备))

/dev/null(空设备),所有写向这个设备的输出都将被丢弃,读这个设备将立刻返回一个文件尾标志

3.设备分为字符设备和块设备,两者的区别在于访问设备时是否需要一次读写一整块


二、系统调用和设备驱动程序

系统调用:通过少量函数达到对文件和设备的访问和控制,这些函数被称为系统调用

设备驱动程序:系统的核心部分,即内核,为一组设备驱动程序,是一组对系统硬件进行控制的底层接口

下面是访问设备驱动程序的底层函数,即系统调用

open:打开文件或设备

read:从打开的文件或设备中读取数据

write:向打开的文件或设备写数据

close:关闭打开的文件或设备

ioctl:把控制信息传递给驱动程序


三、库函数

输入输出的操作直接使用底层系统调用的效率比较低的原因:

1.linux系统中,执行系统调用,必须从用户模式切换到内核模式执行系统调用,执行完毕后,再从内核模式切换到用户模式,用户模式与内核模式的来回频繁切换非常影响系统的性能,减少这种开销的一个方法是,在程序中尽量减少系统调用的次数,并让每次系统调用尽量完成可能多的工作

2.硬件会限制底层系统调用一次能够读写的数据大小



四、底层文件访问

1.一个程序开始运行时,一般会有3个已经打开的文件描述符

0:标准输入

1:标准输出

2:标准错误


2.open系统调用

头文件:

#include <fcntl.h>

#include <sys/types.h>

#include <sys/stat.h>

函数:

int open(const char *pathname, int flags);

int open(const char *pathname, int flags, mode_t mode);

成功返回一个文件描述符,失败返回-1

pathname参数:文件路径名

flags参数:打开方式

O_RDONLY 只读

O_WDONLY 只写

O_RDWD 读写

O_APPEND 把写入数据追加在文件的末尾

O_TRUNC 把文件长度置为0,丢弃已有的内容

O_CREAT 按照参数mode中给出的访问模式创建文件

O_EXCL 与O_CREAT一起使用,确保创建出文件,使open为一个原子操作,防止两个程序同时创建同一个文件,如果文件已经存在,open调用将失败

mode参数:权限标志

S_IRUSR 文件拥有者可读

S_IWUSR 文件拥有者可

S_I XUSR 文件拥有者可执行

S_IRGRP 文件组成员可读

S_IWGRP 文件组成员可写

S_IXGRP 文件组成员可执行

S_IROTH 其他用户可读

S_IWOTH 其他用户可写

S_IXOTH 其他用户可执行


3.read系统调用

头文件:

#include<unistd.h>

函数:

ssize_t read(int fd, void *buf, size_t count);

从文件描述符fd相关联的文件里读入count个字节的数据,并把它们放到数据区buf中


4.write系统调用

头文件

#include <unistd.h>

函数:

ssize_t write(int fd, void *buf, size_t count)

把缓冲区buf的前count字节写入文件描述符fd相关联的文件中


5.close系统调用

头文件

#include <unistd.h>

函数:

int close(int fd); //关闭文件描述符fd

成功返回0,失败返回-1


6、实现复制文件功能

版本1源码:

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

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("input param error\n");
        return -1; 
    }   

    int s_fd = open(argv[1], O_RDONLY);
    if (s_fd == -1) {
        printf("open %s error\n", argv[1]);
        return -1; 
    }   

    int d_fd = open(argv[2], O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
    if (d_fd == -1) {
        printf("open %s error\n", argv[2]);
        return -1; 
    }   

    char ch; <span style="white-space:pre">	</span>//一次读写一个字节
    while (true) {
        int rdRes = read(s_fd, &ch, 1); 
        if (rdRes == -1) {
            printf("read %s error\n", argv[1]);
            return -1; 
        } else if (rdRes == 0) {
            printf("copy %s success\n", argv[1]);
            break;
        } else if (rdRes == 1) {
            int wrRes = write(d_fd, &ch, 1); 
            if (wrRes != 1) {
                printf("write %s error\n", argv[2]);
                return -1; 
            }   
        } else {
            printf("unknow error\n");
            return -1; 
        }   
    }   

    return 0;
}

编译,链接,执行程序



版本2源码:

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

#define BUFF_SIZE 1024

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("input param error\n");
        return -1; 
    }   

    int s_fd = open(argv[1], O_RDONLY);
    if (s_fd == -1) {
        printf("open %s error\n", argv[1]);
        return -1; 
    }   

    int d_fd = open(argv[2], O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
    if (d_fd == -1) {
        printf("open %s error\n", argv[2]);
        return -1; 
    }   

    char buf[BUFF_SIZE]; <span style="white-space:pre">	</span>//一次读写BUFF_SIZE个字节
    while (true) {
        int rdRes = read(s_fd, buf, sizeof(buf));
        if (rdRes == -1) {
            printf("read %s error\n", argv[1]);
            return -1; 
        } else if (rdRes == 0) {
            printf("copy %s success\n", argv[1]);
            break;
        } else if (rdRes > 1) {
            int wrRes = write(d_fd, buf, rdRes);
            if (wrRes != rdRes) {
                printf("write %s error\n", argv[2]);
                return -1; 
            }   
        } else {
            printf("unknow error\n");
            return -1; 
        }   
    }   

    return 0;
}

编译,链接,执行程序


结论:

拷贝同一个文件,处理1消耗了4s多时间,处理2消耗了低于10毫秒时间,这是因为处理1每次只读写1个字节,处理2每次读写1024个字节,处理1来回切换用户模式和内核模式的次数比处理2多得多,而来回切换模式是需要消耗时间和cpu的,所以我们应该每次调用系统调用时,每次应尽量多的处理多的数据,从而减少来回地切换用户模式和内核模式的次数,提高系统性能。

  • 5
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用C语言的readwrite函数来实现两个文件拷贝。具体的实现步骤如下: 1. 打开源文件和目标文件。可以使用fopen函数来打开文件,如果文件不存在则会创建新文件。 2. 读取源文件的内容,并将内容写入到目标文件中。可以使用read函数来读取源文件write函数来将读取的内容写入到目标文件中。 3. 关闭源文件和目标文件。可以使用fclose函数来关闭打开的文件。 下面是一个简单的代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #define BUF_SIZE 1024 int main(int argc, char *argv[]) { int src_fd, dest_fd, rd_size, wt_size; char buf[BUF_SIZE]; if (argc != 3) { fprintf(stderr, "Usage: %s <src_file> <dest_file>\n", argv[0]); exit(EXIT_FAILURE); } src_fd = open(argv[1], O_RDONLY); if (src_fd == -1) { perror("open"); exit(EXIT_FAILURE); } dest_fd = open(argv[2], O_CREAT | O_WRONLY | O_TRUNC, 0644); if (dest_fd == -1) { perror("open"); exit(EXIT_FAILURE); } while ((rd_size = read(src_fd, buf, BUF_SIZE)) > 0) { wt_size = write(dest_fd, buf, rd_size); if (wt_size != rd_size) { perror("write"); exit(EXIT_FAILURE); } } if (rd_size == -1) { perror("read"); exit(EXIT_FAILURE); } if (close(src_fd) == -1) { perror("close"); exit(EXIT_FAILURE); } if (close(dest_fd) == -1) { perror("close"); exit(EXIT_FAILURE); } return EXIT_SUCCESS; } ``` 在运行程序时,需要传入两个参数,第一个参数是源文件的路径,第二个参数是目标文件的路径。程序会将源文件的内容复制到目标文件中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值