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() 命令的方式实现。
相关推荐
做运维的阿瑞12 分钟前
Python 标准库汇总:分类速览与常用模块清单
linux·运维·python
百万蹄蹄向前冲38 分钟前
密码都对Node.js却连不上Linux数据库
linux·mysql
彧azz39 分钟前
Linux 网络编程学习总结
linux·网络·笔记·学习·面试
susplus2 小时前
【ARM 裸机开发 (IMX6ULL-mini)】GNU工具、Makefile 工程构建、链接脚本详解|C 语言点灯 + 蜂鸣器驱动
linux·arm·makefile·imx6ull
Shadow(⊙o⊙)2 小时前
Linux进阶知识1.0
linux·运维·服务器
>Andre<2 小时前
UFS5.0标准中文全译·卷一:范围、术语与架构
android·linux·嵌入式硬件
用户0510122572962 小时前
Linux下有关QT显示环境变量设置
linux·嵌入式
闲云自留地2 小时前
告别命令恐惧症,openEuler 基础操作 + 文本 + 网络管理实战
linux·运维·云计算
剑指offer.2 小时前
ARM裸机开发-点亮LED灯
linux·服务器·嵌入式硬件
GeW3 小时前
工作忙.基础弱,也能快速拿RHCE?这套方法亲测有效
linux