Linux第四天

C语言面向对象基础

面向过程:

  1. 把问题分解成一系列的步骤

  2. 在函数里面一步步实现步骤

  3. 根据需求调用函数

面向对象:

  1. 把构成问题的事务分解成各个对象

  2. 调用对象里面的方法属性解决问题

面向对象三大特性:

  1. 封装性(父类、子类)

  2. 继承(将父类结构体放在子类结构体第一个位置即可)

  3. 多态:指针

文件IO

Linux内核

虚拟文件系统

抽象层,对文件的访问实际上对抽象层的访问。

抽象对象:封装了底层读写细节,使用C语言的多态来实现具体文件系统的操作

普通文件系统

  1. ext4

  2. fat32

  3. ubifs

特殊文件系统

  1. 进程文件系统:procfs,挂载在/proc,存放进程相关信息

  2. 设备文件系统:devfs,挂载在/dev,存放外设设备

总结:指定普通文件系统多态到虚拟文件系统,app再调用虚拟文件系统中的函数,app也可以调用glibc,glibc再调用虚拟文件函数

文件描述符和打开模式

系统IO编程

  • 直接调用Linux文件系统中函数

  • open
    write
    read
    lseek
    close
    • 进程控制:如 fork、clone、exit 、setpriority 等创建、中止、设置进程优先级的操作。
    • 文件系统控制:如 open、read、write 等对文件的打开、读取、写入操作。
    • 系统控制:如 reboot、stime、init_module 等重启、调整系统时间、初始化模块的系统操作。
    • 内存管理:如 mlock、mremap 等内存页上锁重、映射虚拟内存操作。
    • 网络管理:如 sethostname、gethostname 设置或获取本主机名操作。
    • socket 控制:如 socket、bind、send 等进行 TCP、UDP 的网络通讯操作。
    • 用户管理:如 setuid、getuid 等设置或获取用户 ID 的操作。
    • 进程间通信:包含信号量、管道、共享内存等操作。
  • int fd;
    fd = open(filename,flags,mode);
    lseek(fd,offset,whence);
    write(fd,buf,len);
    read(fd,buf,len);
    close(fd);
    ​
    文件描述符:fd,特殊的索引,file_struct结构体成员fd_array的数组下标
    进程:每个程序
        就是个进程
OPEN_close
//头文件
#include <sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
​
fd = open("./b.txt",O_RDONLY|O_CREAT,0666);
​
标志位 含义
O_RDONLY 以只读的方式打开文件,该参数与 O_WRONLY 和 O_RDWR 只能三选一
O_WRONLY 以只写的方式打开文件
O_RDWR 以读写的方式打开文件
O_CREAT 创建一个新文件
O_APPEND 将数据写入到当前文件的结尾处
O_TRUNC 如果 pathname 文件存在,则清除文件内容

CLOSE

#include <unistd.h>
int closh(int fd)

open_close.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
    int fd;
    fd = open("./b.txt",O_RDONLY|O_CREAT,0666);
    if(fd < 0)
    {
        printf("OPEN erro\n");
    }
    printf("fd:%d\n",fd);
    close(fd);
    return 0;
}

Makefile

ARCH ?= x86
​
ifeq ($(ARCH),x86)
        CC=gcc
else
        CC=arm-linux-gnueabihf-gcc
endif
​
TARGET=open_close
BUILD_DIR=build
SRC_DIR=.
INC_DIR=.
CFLAGS=$(patsubst %,-I%,$(INC_DIR))
INCLUDES=$(foreach dir,$(INC_DIR),$(wildcard $(patsubst)/*.h))
​
SOURCES=$(foreach dir,$(SRC_DIR),$(wildcard $(dir)/*.c))
OBJS=$(patsubst %.c,$(BUILD_DIR)/%.o,$(notdir $(SOURCES)))
VPATH=$(SRC_DIR)
​
$(BUILD_DIR)/$(TARGET):$(OBJS)
        $(CC) $^ -o $@
​
​
$(BUILD_DIR)/%.o:%.c $(INCLUDES) | create_build
        $(CC) -c $< -o $@ $(CFLAGS)
​
.PHONY:clean create_build
​
clean:
    rm -r $(BUILD_DIR)
​
create_build:
    mkdir -p $(BUILD_DIR)
read_write函数

read

返回值:count(读取全部字节)、0-count、-1

#include <unistd.h>
read(fd,*buff,size_count)

write

返回值:count(写入全部字节)、0-count、-1

#include <unistd.h>
write(fd,*buff,size_count)

复制普通文件小实验

  1. 打开要复制的文件

  2. 创建新的文件

  3. 把源文件内容读到缓冲区,缓冲区内容写入新文件

  4. 循环第三步,直到读取字节为0,退出循环

  5. 关闭打开的文件

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
​
int main(int argc,char** argv)
{
    int fd1,fd2; //定义源文件,新建文件
    char buf[512]; //缓冲区
    int read_size; //读取字节
​
    if(argc != 3)  //这里可以判断文件是否有源文件
    {
        printf("argc erro\n");
        return 1;
    }
​
    fd1 = open(argv[1],O_RDONLY); //只读源文件
    fd2 = open(argv[2],O_WRONLY|O_CREAT,0666);//写+新建
​
    if(fd1 < 0 || fd2 < 0) //判断源文件是否成功打开
    {
        printf("open erro\n");
        return -1;
    }
    while(1) //不断读取字节直到为0
    {
        read_size = read(fd1,buf,521);
        if(read_size == 0)
        {
            break;
        }
        write(fd2,buf,read_size);
    }
​
    close(fd1|fd2);
    return 0;
}
​
Iseek和sync函数

lseek:设置文件读写位置

#include <unistd.h>
​
off_t lseek(int fd, off_t offset, int whence);

• SEEK_SET:offset 是一个绝对位置。

• SEEK_END:offset 是以文件尾为参考点的相对位置。

• SEEK_CUR:offset 是以当前位置为参考点的相对位置。

返回值偏移量、-1

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
​
int main()
{
    int fd;
    fd = open("file",O_WRONLY|O_CREAT,0666);
    write(fd,"123",3);
    lseek(fd,100,SEEK_CUR);
    write(fd,"abc",3);
    close(fd);
    return 0;
}

sync:

页缓存和回写

buff——页缓冲区——磁盘

功能;将页缓冲区强行写入磁盘中

#include <unistd.h>
​
​
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
​
int main()
{
    int fd;
    fd = open("file",O_WRONLY|O_CREAT,0666);
    write(fd,"123",3);
    lseek(fd,100,SEEK_CUR);
    write(fd,"abc",3);
    sync();
    close(fd);
    return 0;
}

标准IO编程

C标准库实现了一个IO缓存区

  • 调用glibc封装的函数

  • fopen()
    fclose()
    fwrite()
    fread()
    fseek()
    fflush()
        
    #include <stdio.h>
    FILE *fopen(const char *pathname, const char *mode);
    size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
    size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);
    int close(int fd);//关闭文件
    int fflush(FILE *stream);//fflush 函数用于把尚未写到文件的内容立即写出。
    int fseek(FILE *stream, long offset, int whence); //fseek 函数用于设置下一次读写函数操作的位置

文件打开

• mode 参数用于指定文件的打开方式,注意该参数是一个字符串,输入时需要带双引号:
•“r”:以只读方式打开,文件指针位于文件的开头。
•“r+”:以读和写的方式打开,文件指针位于文件的开头。
•“w”:以写的方式打开,不管原文件是否有内容都把原内容清空掉,文件指针位于文件的开
头。
•“w+”:同上,不过当文件不存在时,前面的“w”模式会返回错误,而此处的“w+”则会
创建新文件。
•“a”:以追加内容的方式打开,若文件不存在会创建新文件,文件指针位于文件的末尾。与
“w+”的区别是它不会清空原文件的内容而是追加。
•“a+”:以读和追加的方式打开,其它同上。

总结;

如库函数写入数据的文件操作 fwrite 最后也是执行了 write 系统调用,如果是写少量数据的话,直接执行 write 可能会更高效,但如果是频繁的写入操作,由于 f write 的缓冲区可以减少调用 write 的次数,这种情况下使用 fwrite 能更节省时间

文件IO五大模式

  • 阻塞模式

  • 非阻塞模式

  • IO多路复用

  • 异步IO

  • 信号驱动IO

控制LED灯设备

在 Linux 系统中,绝大多数硬件设备都有非常成熟的驱动框架,驱动工程师使用这些框架添加与

板子相关的硬件支持,建立硬件与 Linux 内核的联系,内核再通过统一文件系统接口呈现给用户,

用户通过对应的设备文件控制硬件。

对 于 LED 设 备,Linux 提 供 了 LED 子 系 统 驱 动 框 架, 在 Linux 内 核 源 码 中 的

“Documentation/leds/leds-class.txt”有相关的描述,它实现了一个 leds 类,用户层通过 sysfs

文件系统对 LED 进行控制。

控制硬件设备步骤

1、找出硬件设备所对应的设备节点文件

两个地方:

  • /dev目录下

    对驱动程序熟悉的工程师可以使用,一个设备节点文件控制硬件全部特性

  • /sys目录下

    业余工程师使用,一个设备节点文件只控制硬件的一个特性

    严格来说,它下面的文件是Linux内核导出到用户空间的硬件操作接口

2、找出驱动程序规定的设备文件使用方式

LED灯程序

设备节点文件:/sys/class/leds

往brightness文件写入一个数值,就能控制led灯的亮度

led亮度值:0~255

echo 255 > /sys/class/leds/blue/brightness 
echo 0 > /sys/class/leds/blue/brightness 

在开发板里面编译程序之前,需要提前安装gcc和make工具

sudo apt install gcc/make
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
​
//ARM 开发板 LED 设备的路径
#define RLED_DEV_PATH "/sys/class/leds/red/brightness"
#define GLED_DEV_PATH "/sys/class/leds/green/brightness"
#define BLED_DEV_PATH "/sys/class/leds/blue/brightness"
​
​
int main(int argc, char *argv[])
{
    FILE *r_fd, *g_fd, *b_fd;
​
    printf("This is the led demo\n");
    //获取红灯的设备文件描述符
    r_fd = fopen(RLED_DEV_PATH, "w");
    if(r_fd < 0){
    printf("Fail to Open %s device\n", RLED_DEV_PATH);
    exit(1);
    }
​
     //获取绿灯的设备文件描述符
    g_fd = fopen(GLED_DEV_PATH, "w");
    if(g_fd < 0){
    printf("Fail to Open %s device\n", GLED_DEV_PATH);
    exit(1);
    }
​
    //获取蓝灯的设备文件描述符
    b_fd = fopen(BLED_DEV_PATH, "w");
    if(b_fd < 0){
    printf("Fail to Open %s device\n", BLED_DEV_PATH);
    exit(1);
     }
​
    while(1){
        //红灯亮
        fwrite("255",3,1,r_fd);
        fflush(r_fd);
        //延时 1s
        sleep(1);
        //红灯灭
        fwrite("0",1,1,r_fd);
        fflush(r_fd);
​
        //绿灯亮
        fwrite("255",3,1,g_fd);
        fflush(g_fd);
        //延时 1s
        sleep(1);
        //绿灯灭
        fwrite("0",1,1,g_fd);
        fflush(g_fd);
​
        //蓝灯亮
        fwrite("255",3,1,b_fd);
        fflush(b_fd);
        //延时 1s
        sleep(1);
        //蓝灯亮
        fwrite("0",1,1,b_fd);
         fflush(b_fd);
        }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值