Linux系统编程笔记--系统(文件)I/O操作

目录

1--文件描述符

2--系统I/O常用函数

3--标准I/O和系统I/O的区别

4--原子操作

5--dup()和dup2()

6--fcntl()和ioctl()


1--文件描述符

文件描述符的实质:一个整型数,一个数组下标(数组的元素指向文件结构体);

文件描述符优先使用可用范围内最小的;

标准输入(stdin)的文件描述符为 0;标准输出(stdout)的文件描述符为 1;标准错误(stderr)的文件描述符为 2;因此其余文件描述符肯定 >= 3;

2--系统I/O常用函数

以下常用函数可通过 man 手册查看其用法;

open():

close():

read();

write();

cpp 复制代码
int open(const char *pathname, int flags);
int close(int fd);
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
cpp 复制代码
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

#define BUF_SIZE 1024

int main(int argc, char* argv[]){

    int sfd, dfd;
    char* buf[BUF_SIZE];
    int len, ret, pos;

    if(argc < 3){
        fprintf(stderr, "Usage...\n");
        exit(1);
    }
    sfd = open(argv[1], O_RDONLY);
    if(sfd < 0){
        perror("open()");
        exit(1);
    }

    dfd = open(argv[2], O_WRONLY|O_CREAT, O_TRUNC, 0600);
    if(dfd < 0){
        close(sfd);
        perror("open()");
        exit(1);
    }
    printf("%d %d\n", sfd, dfd); // 3 4
    while(1){
        len = read(sfd, buf, BUF_SIZE);
        if(len < 0 ){
            perror("read()");
            break;
        }
        if(len == 0) break;

        pos = 0;
        while(len > 0){
            ret = write(dfd, buf+pos, len);  
            if(ret < 0){
                perror("write()");
                exit(1);
            }
            pos += ret;
            len -= ret;
        }
    }
    close(dfd);
    close(sfd);
    exit(0);
}

3--标准I/O和系统I/O的区别

标准I/O的吞吐量大(会先把数据放到缓冲区,刷新缓冲区之后才会完成数据的存取),系统I/O的响应速度快(不会把数据放到缓冲区,一次调用就完成一次操作);

标准I/O和系统I/O最好不要混用;

标准I/O和系统I/O的转换函数:fileno()fdopen()

cpp 复制代码
int mian(){
    putchar('a');
    write(1, "b", 1);
    putchar('a');
    write(1, "b", 1);
    putchar('a');
    write(1, "b", 1);
}

// 程序会打印:bbbaaa
// 因为标准I/O打印的 a 会先放到缓冲区中,后面一次完成输出;

4--原子操作

原子操作:不可分割的操作;

原子操作的作用:解决竞争与冲突;

5--dup()和dup2()

cpp 复制代码
#include <unistd.h>

int dup(int oldfd);
int dup2(int oldfd, int newfd); // 原子操作

// dup 复制(准确来说,将当前文件描述符对于文件的权限共享过来给新的文件描述符了)当前的文件描述符
// dup 返回一个新的文件描述符,新旧文件描述符共享访问同一个文件
// dup 返回的新文件描述符一定是当前可用文件描述中的最小数值

// dup2是原子操作,不能被打断,它会关闭旧的文件描述符
cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define FNAME "./out"

int main(){
    int fd = open(FNAME, O_WRONLY|O_CREAT|O_TRUNC, 0600);
    if(fd < 0){
        perror("open()");
        exit(1);
    }
    // close(1); // 关闭标准输出
    // dup(fd); // 关闭标准输出后,1成了最小的可用文件描述符,因此dup(fd)后,1和最初的fd共享打开的文件
    dup2(fd, 1); // 原子操作,功能等同于上面两句
    if(fd != 1){
        close(fd);
    }
    // 上面语句的功能相当于是将文件描述符1映射到打开的文件,即打开文件的文件描述符 fd = 1
    // puts默认打印到标准输出,但此时标准输出被关闭了
    // 文件描述符1其实指向的是打开的文件,因此puts打印到了打开的文件里
    puts("hello!"); 
    exit(0);
}

6--fcntl()和ioctl()

cpp 复制代码
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );

// fcntl() performs one of the operations described below on the open file descriptor fd.  
// The operation is determined by cmd.

// fcntl() 根据提供的 cmd 来对输入的 fd 进行相关操作
cpp 复制代码
#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);

// ioctl 是设备驱动程序中设备控制接口函数
// 一个字符设备驱动通常会实现设备打开、关闭、读、写等功能
// 在一些需要细分的情境下,如果需要扩展新的功能,通常以增设 ioctl() 命令的方式实现。
相关推荐
郝亚军10 小时前
ubuntu-18.04.6-desktop-amd64安装步骤
linux·运维·ubuntu
Konwledging11 小时前
kernel-devel_kernel-headers_libmodules
linux
Web极客码11 小时前
CentOS 7.x如何快速升级到CentOS 7.9
linux·运维·centos
一位赵11 小时前
小练2 选择题
linux·运维·windows
代码游侠11 小时前
学习笔记——Linux字符设备驱动开发
linux·arm开发·驱动开发·单片机·嵌入式硬件·学习·算法
Lw老王要学习12 小时前
CentOS 7.9达梦数据库安装全流程解析
linux·运维·数据库·centos·达梦
CRUD酱12 小时前
CentOS的yum仓库失效问题解决(换镜像源)
linux·运维·服务器·centos
zly350013 小时前
VMware vCenter Converter Standalone 转换Linux系统,出现两个磁盘的处理
linux·运维·服务器
Albert Edison13 小时前
【Python】函数
java·linux·python·pip
General_G13 小时前
Linux中的信号
linux·运维·服务器