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

一、基本概念和常识

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

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

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

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

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

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


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

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

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

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

open:打开文件或设备

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

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

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

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


三、库函数

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

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

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

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


四、底层文件访问

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

0:标准输入

1:标准输出

2:标准错误


2.open系统调用

头文件:

#include

#include

#include

函数:

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

函数:

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

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


4.write系统调用

头文件

#include

函数:

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

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


5.close系统调用

头文件

#include

函数:

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

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


6、实现复制文件功能

版本1源码:

#include 
#include 
#include 
#include 
#include 

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; 	//一次读写一个字节
    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;
}

编译,链接,执行程序

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


版本2源码:

#include 
#include 
#include 
#include 
#include 

#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]; 	//一次读写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;
}

编译,链接,执行程序

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

结论:

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

你可能感兴趣的:(Linux基础从零开始学起)