基础IO(文件输入输出、标准IO接口、文件描述符和文件流指针)

2023-10-28

 

目录

基础IO(文件的输入输出操作)

 FILE *fopen(char* filename,char* mode);(文件名称,打开方式)

size_t fread(char* buf,size_t block_size,size_t block_count,FILE* fp);(缓冲区,块大小,块个数,文件流指针);

size_t fwrite(char*data,size_t block_size,size_t block_count,FILE* fp);(数据首地址,块大小,块个数,文件流指针);

int fseek(FILE* fp,long offset,int whence);(将文件的读写指针从whence位置偏移offset个字节)- - - - -跳转文件读写位置

int fclose(FILE* fp);- - - - - 关闭文件流指针,释放资源

标准的IO接口(都是库函数,而库函数就是对系统调用接口的一层封装)

 int open(char* filename,int flag,mode_t mode);

ssize_t write(int fd,char* buf,size_t count);

ssize_t read(int fd,char* buf,size_t len);

off_t lseek(int fd,off_t offset,int whence);

int close(int fd);通过文件描述符关闭文件,释放资源;

int dup2(int oldfd,int newfd);- - - - -描述重定向函数

在minishell中实现>/>>标准输出重定向 

文件描述符与文件流指针的关系:



基础IO(文件的输入输出操作)

例:fopen/fwrite/fread/fseek/fclose        stdin/stdout/stderr

 FILE *fopen(char* filename,char* mode);(文件名称,打开方式)

打开方式:*r(只读); r+(读写);w(只写);w+(读写);a(追加写);a+(追加读写);b(二进制操作)。

追加写:每次写入数据总是写入到文件末尾

r+的读写和w+的读写的区别:r+读写打开文件,若文件不存在则报错;w+读写打开文件,若不存在则创建,若存在则清空原有内容。

a:不仅是追加写,并且文件不存在会创建新文件

b:默认清空如果不指定b,则认为文件是文本操作,加上b则认为是二进制操作;区别在于:有时候一个特殊字符,只是一个字符但是占据两个字节的内存(例:读取一个100字节大小的文件,文本操作最终读取出来的数据,不一定是100个字节)

返回值:返回实际一个FILE*的文件流指针作为文件的操作句柄;失败则返回NULL;

size_t fread(char* buf,size_t block_size,size_t block_count,FILE* fp);(缓冲区,块大小,块个数,文件流指针);

size_t fwrite(char*data,size_t block_size,size_t block_count,FILE* fp);(数据首地址,块大小,块个数,文件流指针);

  • 注意:fread/fwrite操作的数据实际大小=块大小*块个数;(例:块大小为10,块个数为2,则需要写入/读取20个字节的数据);
  • 返回值:返回实际操作的块个数;(例:读取一个文件size为10,count为2,如果文件大小足够则返回2,但是若文件大小只有16个字节,则返回1,因为第二块没有读满;fread如果读到了文件末尾则会返回0)
  • 如果读取1000个字节,块个数为1,文件大小只有512字节,虽然读取了512个数据但是也会返回0

int fseek(FILE* fp,long offset,int whence);(将文件的读写指针从whence位置偏移offset个字节)- - - - -跳转文件读写位置

int fclose(FILE* fp);- - - - - 关闭文件流指针,释放资源

fread/fwrite的块大小一般设定为1,块个数设为想要操作的数据长度

fseek:文件没有数据也可以跳转到读写位置;

对文件数据进行字符串操作是时候要注意文件数据中\0这种数据

#include <stdio.h>
#include <string.h>

int main()
{
    FILE *fp = NULL;

    fp = fopen("./test.txt", "r+");
    if (fp == NULL) {
        perror("fopen error");//打印上一个系统调用接口的使用错误原因
        return -1;
    }

    //fseek跳转读写位置 SEEK_SET-从文件起始偏移 SEEK_CUR-从当前读写位置开偏移
    //SEEK_END-从文件末尾偏移
    fseek(fp, 10, SEEK_END); //将文件的读写位置偏移到末尾

    //sizeof获取的是一块空间的大小 / strlen获取的是字符串的长度遇到\0截止
    char buf[] = "It's a fine day\0 today~~\n";
    int ret = fwrite(buf, strlen(buf), 1, fp);//(数据,块大小,块个数,流指针);
    if (ret == 0) {
        perror("fwrite error");
        return -1;
    }
    printf("write ret:%d\n", ret);

    fseek(fp, 0, SEEK_SET);

    char tmp[1024] = {0};
    ret = fread(tmp, 1, 1023, fp);//在块大小为1情况下不会出现读取到数据依然返回0的情况
    if (ret == 0) {
        printf("have no data or error\n");
    }
    printf("ret:%d-[%s]\n", ret, tmp);

    fclose(fp);
    return 0;
}

标准的IO接口(都是库函数,而库函数就是对系统调用接口的一层封装)

系统调用IO接口的学习:open\read\write\seek\close

 int open(char* filename,int flag,mode_t mode);

filename:要打开的文件名称;

flag:选项参数,文件的打开方式,必选项/可选项

  • 必选项(只能选择其一):O_WRONLY(只写);O_RDWR(读写);O_TRUNC(打开文件的同时清空原有内容);O_APPEND(追加写,总是将数据写入到文件末尾)。
  • mode:权限,如果使用了O_CREAT有可能创建新文件,就一定要指定文件权限,八进制数字形式。
  • 返回值:一个非负数,文件描述符,文件的操作句柄;失败返回-1;

ssize_t write(int fd,char* buf,size_t count);

fd:open返回的文件描述符,文件操作句柄,通过这个fd指定要往那个文件写入数据

buf:要写入文件的数据的空间首地址

count:要写入的数据大小

返回值:返回实际写入文件的数据字节长度;失败则返回-1

ssize_t read(int fd,char* buf,size_t len);

fd:open返回的文件描述符,文件的操作句柄;

buf:从文件中读取数据放到哪个缓冲区中的首地址;

len:想要读取的数据长度,注意这个len不能大于缓冲区的大小;

返回值:返回的是实际读取到的数据字节长度,错误返回-1;

off_t lseek(int fd,off_t offset,int whence);

fd:open返回的文件描述符;

offset:偏移量;

whence:从哪开始偏移;SEEK_SET(文件起始位置),SEEK_CUR(文件当前读写位置),SEEK_END(文件末尾);

返回值:成功返回当前位置相对于起始位置的偏移量;失败返回-1;

#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

int main()
{
    int fd = -1;
    umask(0);//将当前进程的文件创建权限掩码设置位0-仅当前进程有效
    fd = open("./test.txt", O_RDWR|O_CREAT, 0777);
    if (fd < 0) {
        perror("open error");
        return -1;
    }
    lseek(fd, 10, SEEK_END);// 目的读写位置跳转到文件末尾
    char ptr[1024] = "hello world~\n";
    int ret = write(fd, ptr, strlen(ptr));
    if (ret < 0) {
        perror("write error");
        return -1;
    }
    printf("ret:%d\n", ret);

    lseek(fd, 0, SEEK_SET);// 跳转到文件的起始位置
    char buf[1024] = {0};
    ret = read(fd, buf, 1024);
    if (ret < 0) {
        perror("read error");
        return -1;
    }
    printf("ret:%d-[%s]\n", ret, buf);

    close(fd);
    return 0;
}

int close(int fd);通过文件描述符关闭文件,释放资源;

为什么打开一个文件,如果不操作一定要关闭,释放资源?

答:因为文件描述符实际上是有限的,若不关闭文件,文件描述符用光,则在进程中就打不开新文件了。

一个进程运行起来,进程会默认打开三个文件:标准输入 0-stdin/标准输出 1-stdout/标准错误 2-stderr;

文件描述符的分配原则:最小未使用;

print打印数据到标准输出,close(1)是把标准输出关闭了;打开新文件后,printf并没有把数据打印出来,而是在刷新缓冲区之后,两数据写入到了文件中。

printf并非帧的一定要把数据写入标准输出文件,而是因为printf函数中操作文件的时候操作的描述符是1。原本向1中写入数据就是向标准输出写入,然后当1指向了新的文件后,这个printf就会将数据写入到新的文件中重定向:将数据不再写入原本的文件,而是写入新的指定的文件中,实现方式就是替换这个描述符对应的文件描述信息。实际上是描述符的重定向,改变描述符所指向的文件,就是改变了数据的流向。

int dup2(int oldfd,int newfd);- - - - -描述重定向函数

功能:让newfd这个描述符也指向oldfd所指向的文件,这时候oldfd和newfd都能够操作oldfd所指向的文件。

**重定向实现原理**:每个文件描述符都是一个内核中文件描述信息数组的下标,对应有一个文件的描述信息用于操作文件,而重定向就是在不改变所操作的文件描述符的情况下,通过改变描述符对应的文件描述信息进而实现改变所操作的文件。

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main()
{
    //close(1);//关闭0号描述符-就是关闭了标准输入
    /*
    umask(0);
    int fd = open("./test.txt", O_RDWR|O_CREAT, 0664);
    if (fd < 0) {
        perror("open error");
        return -1;
    }
    dup2(fd, 1);//将1重定向到test.txt这个文件
    printf("fd=%d\n", fd);
    fflush(stdout);//刷新标准输出缓冲区
    close(fd);
    */
    FILE *fp = fopen("./test.txt", "r+");
    fp->_fileno = 1;//将文件流指针中的文件描述符改成标准输出的描述符了
    fwrite("hello world\n", 1, 12, fp);
    fclose(fp);
}

在minishell中实现>/>>标准输出重定向

 

>清空重定向open(O_CREAT|O_TRUNC);

>>追加重定向opend(O_CREAT|O_APPEND);

a.txt  fd = open(a.txt);
dup2(fd,1);   //子进程在运行指令的时候,ls本身要将数据写入标准输出
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

int main()
{
    while(1) {
        //增加一个shell提示
        printf("[san@minishell]$ ");
        fflush(stdout);//刷新标准输出缓冲区
        //1. 等待标准输入
        char buf[1024] = {0};
        fgets(buf, 1023, stdin);
        buf[strlen(buf)-1] = '\0'; //buf[...]='\n'
        //1.5 解析重定向
        //ls -l  > a.txt
        char *ptr = buf;
        int redirect_flag = 0;
        char *redirect_file = NULL;
        while(*ptr != '\0') {
            if (*ptr == '>') {
                redirect_flag = 1;//这是清空重定向
                *ptr = '\0';//将>替换成结尾标志,则命令的解析到此位置就完毕了
                ptr++;
                if (*ptr == '>') {//有第二个>则是追加重定向
                    redirect_flag = 2;
                    *ptr = '\0';
                    ptr++;
                }
                while(*ptr == ' ' && *ptr != '\0') ptr++;//将a.txt之前的空格走完
                redirect_file = ptr;//redirect_file这个指针指向了a.txt中a的位置
                while(*ptr != ' ' && *ptr != '\0') ptr++; // 将a.txt字符走完
                *ptr = '\0';
            }
            ptr++;
        }
        //2. 对输入命令数据进行解析
        char *argv[32] = {NULL};
        int argc = 0;
        ptr = buf;
        // [    ls    -a    -l    ]
        while(*ptr != '\0') {
            if (*ptr != ' ') {
                argv[argc] = ptr;
                argc++;
                while(*ptr != ' ' && *ptr != '\0') {
                    ptr++;               
                }
                *ptr = '\0';
            }
            ptr++;
        }
        argv[argc] = NULL;//最后一个参数的下一个位置置NULL
        //3. 创建子进程 4. 在子进程中程序替换
        pid_t pid = fork();
        if (pid == 0) {
            if (redirect_flag == 1) {//清空重定向
                int fd = open(redirect_file, O_WRONLY|O_CREAT|O_TRUNC, 0664);
                dup2(fd, 1);//将标准输入重定向到redirect_file;原本要打印的数据就会被写入文件
            }else if (redirect_flag == 2){ // 追加重定向
                int fd = open(redirect_file, O_WRONLY|O_CREAT|O_APPEND, 0664);
                dup2(fd, 1);//将标准输入重定向到redirect_file;原本要打印的数据就会被写入文件
            }
            //execvp(char *file, char *argv[])  file--新程序名称 
            execvp(argv[0], (char**)argv);//程序替换成功就去运行新程序了,32行以后就不会运行了
            //能够走到第33行,那么肯定程序替换失败了
            perror("execvp error");//打印上一次系统调用接口使用的错误原因
            exit(0);
        }
        //5. 进程等待
        wait(NULL);
    }
    return 0;
}

文件描述符与文件流指针的关系:

文件描述符:是一个非负整数,系统调用的IO接口;在进程中每打开一个文件,都会创建有相应的文件描述信息struct file,这个描述信息被添加在pcb的struct files_struct中,以数组的形式进行管理,随即向用户返回数组的下标作为文件描述符,用于操作文件。

文件流指针:FILE结构体,typedef struct _IO_FILE FILE - - - - -库函数IO接口的操作句柄

通过文件流指针进行最终文件操作的时候,依然还要能够找到文件对应的文件描述符才可以,文件流指针是一个结构体,结构体中有很多的成员变量,其中有一个叫做_fileno- - -这就是文件描述符;

向文件写入数据,并不会直接写入文件,而是先写入缓冲区中,刷新缓冲区的时候才会写入文件;(只有库函数才存在这个缓冲区)

系统调用接口是直接将数据写入文件的,系统调用接口是没有这个缓冲区的。

exit( )退出会刷新缓冲区,而_exit( )退出时不会刷新缓冲区。

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基础IO(文件输入输出、标准IO接口、文件描述符和文件流指针) 的相关文章

  • 在 vimrc 中切换匹配

    我的 vimrc 文件中有以下几行 hi ExtraWhitespace cterm NONE ctermbg green ctermfg green guibg green guifg green match ExtraWhitespac
  • Linux >2.6.33:可以使用 sendfile() 来实现更快的“猫”吗?

    必须将大量大文件连接成一个更大的单个文件 我们目前使用 cat file1 file2 output file but are wondering whether it could be done faster than with that
  • 用于 e NetworkManager VPN 连接的 dbus 信号处理程序

    我需要开发一些在建立 VPN 连接时执行的 python 代码 VPN 由 NetworkManager 控制 我试图弄清楚如何为此使用 NM DBUS 事件 使用 dbus monitor system 我能够识别连接信号 signal
  • 在 MacOS 上构建需要 net461 的 dotnet SDK 项目的最简单方法

    我有一个 dotnet SDK sln and a build proj with
  • 虚拟内存澄清——大连续内存的分配

    我有一个应用程序 我必须在 Windows 上分配 使用运算符 new 相当大的内存空间 数百 MB 该应用程序是 32 位 我们现在不使用 64 位 即使在 64 位系统上也是如此 我启用了 LARGEADDRESSAWARE 链接器选项
  • Linux 上的“软/硬 nofile”是什么意思

    当我尝试在RedHat EL5上安装软件时 我得到了错误 软 硬nofile的期望值是4096 而默认值是1024 我设法增加了这个数字 但我不知道参数是什么 他们指的是软链接和硬链接吗 我改变的方法是 a 修改 etc security
  • 重新链接匿名(未链接但打开)文件

    在 Unix 中 可以创建匿名文件的句柄 例如 使用 creat 创建并打开它 然后使用 unlink 删除目录链接 留下一个带有 inode 和存储的文件 但没有可能的方法重新打开它 此类文件通常用作临时文件 通常这就是 tmpfile
  • 删除 Python 中某些操作的 root 权限

    在我的 Python 脚本中 我执行了一些需要 root 权限的操作 我还创建并写入文件 我不想由 root 独占所有 而是由运行我的脚本的用户独占所有 通常 我使用以下命令运行脚本sudo 有办法做到上述吗 您可以使用以下方式在 uid
  • “./somescript.sh”和“. ./somescript.sh”有什么区别

    今天我按照一些说明在 Linux 中安装软件 有一个需要首先运行的脚本 它设置一些环境变量 指令告诉我执行 setup sh 但是我执行时犯了一个错误 setup sh 所以环境没有设置 最后我注意到了这一点并继续进行 我想知道这两种调用脚
  • 使用 hcitool 扫描低功耗蓝牙?

    当我运行此命令时 BLE 设备扫描仅持续 5 秒 sudo timeout 5s hcitool i hci0 lescan 输出显示在终端屏幕中 但是 当我将输出重定向到文件以保存广告设备的地址时 每次运行该命令时 我都会发现该文件是空的
  • 在 MacO 和 Linux 上安装 win32com [重复]

    这个问题在这里已经有答案了 我的问题很简单 我可以安装吗win32com蟒蛇API pywin32特别是 在非 Windows 操作系统上 我一直在Mac上尝试多个版本pip install pywin32 都失败了 下面是一个例子 如果你
  • 在Linux中创建可执行文件

    我计划做的一件事是编写 非常简单的 Perl 脚本 并且我希望能够在不从终端显式调用 Perl 的情况下运行它们 我明白 要做到这一点 我需要授予他们执行权限 使用 chmod 执行此操作非常简单 但它似乎也是一个稍微费力的额外步骤 我想要
  • 在Linux中使用C/C++获取机器序列号和CPU ID

    在Linux系统中如何获取机器序列号和CPU ID 示例代码受到高度赞赏 Here http lxr linux no linux v2 6 39 arch x86 include asm processor h L173Linux 内核似
  • Linux Shellcode“你好,世界!”

    我有以下可用的 NASM 代码 global start section text start mov eax 0x4 mov ebx 0x1 mov ecx message mov edx 0xF int 0x80 mov eax 0x1
  • Linux mremap 不释放旧映射?

    我需要一种方法将页面从一个虚拟地址范围复制到另一个虚拟地址范围 而无需实际复制数据 范围很大 延迟很重要 mremap 可以做到这一点 但问题是它也会删除旧的映射 由于我需要在多线程环境中执行此操作 因此我需要旧映射能够同时使用 因此稍后当
  • VSCODE 在 Linux 上不适用于我

    刚刚了解 VSCODE 很高兴尝试一下 我下载 解压并运行可执行文件 我得到 Code 2183 0429 201254 ERROR browser main loop cc 170 Running without the SUID san
  • SVN 不断提示我输入密码并拒绝缓存我的凭据

    环境 Eclipse Indigo Ubuntu 11 04 Subclipse 1 6 SVN 客户端 Subclipse RabbitVCS 我通过 svn ssh 连接 我的网址如下所示 svn ssh 我的名字 我的域名 路径 我可
  • Laravel 内存问题?

    各位 我在 DO 服务器上遇到这样的问题 我已经尝试了一切 整个网站在使用 Homestead 的 Linux 服务器上 100 正常工作 但上传后 它只能工作一次 在重新加载或刷新页面后会多次下降 我尝试增加 apache 服务器的内存
  • 如何防止 CMake 在构建时(而不是安装时)为共享库创建符号链接?

    我正在使用 CMake 在 Linux 上使用 Bullet3 构建一个项目 在构建整个解决方案时 它会构建附加了 SOVERSION 的 Bullet 输出库 并创建一个不带版本的符号链接 对于我的特定场景 我不喜欢这种行为 并且我不想编
  • _dl_runtime_resolve -- 共享对象何时加载到内存中?

    我们有一个对性能要求很高的消息处理系统 最近我们注意到第一条消息比后续消息花费的时间要长很多倍 当它通过我们的系统时 会发生大量转换和消息增强 其中大部分是通过外部库完成的 我刚刚描述了这个问题 使用 callgrind 将仅一条消息的 运

随机推荐

  • BugkuWeb:game1

    进去后发现是一款游戏 思路就是直接结束游戏 然后去看信息 发现网络监视器中多了score php 发现了可疑的参数score IP sign 这个sign应该在后台代码中被控制的 去审计代码 发现了sign的算法 这个游戏的得分是25 ba
  • 梦幻模拟战手游服务器维护,梦幻模拟战手游无法登陆游戏 服务器异常登录解决方法_游侠手游...

    梦幻模拟战手游 异常登录怎么办 无法登陆游戏怎么办 还没解决的玩家 下面小编就为玩家带来 梦幻模拟战手游 服务器异常登录无法登录解决方法 一起来看看吧 服务器异常登录无法登录解决方法 各位指挥官 真的非常抱歉 服务器目前不稳定 会有部分指挥
  • oracle 创建数据库 create database,使用create database语句创建数据库的详细操作步骤...

    使用create database语句创建数据库的步骤如下 1 指定一个实例标识符SID 2 确保设置了必要的环境变量 3 选择一个数据库管理员验证方法 4 创建一个初始化参数文件 5 只用于windows平台 创建一个实例 6 连接实例
  • 2022全国大学生数学建模竞赛C题思路模型

    1 比赛报名与思路解析 持续更新750967193 2 比赛时间 2022年9月15日18点到2022年9月18日20点 如下为C题思路 C 题 古代玻璃制品的成分分析与鉴别 丝绸之路是古代中西方文化交流的通道 其中玻璃是早期贸易往来的宝贵
  • Java异常, 性能有多差

    在 Java 中 异常通常被认为是成本昂贵的 不应该用于控制控制 本文将证明这个观点的正确性 并验证导致性能问题的原因 Java微基准测试框架 在编写代码评估Java异常的性能成本之前 我们需要搭建一个基准测试环境 测量异常的成本开销 并不
  • 04C++11多线程编程之创建多个线程和数据共享问题分析

    04C 11多线程编程之创建多个线程和数据共享问题分析 1 thread循环创建多个子线程 思想就是使用容器创建多个线程 推荐 以后工作中会使用到 具有实际意义 方便统一管理线程 include
  • Staple 跟踪: Complementary Learners for Real-Time Tracking

    目标跟踪算法 Staple Complementary Learners for Real Time Tracking 小小菜鸟一只 2017 03 25 09 26 42 15110 收藏 14 分类专栏 目标跟踪 版权 文章下载链接 文
  • 辨析Java与Javascript

    首先 它们是两个公司开发的不同的两个产品 Java是SUN公司推出的新一代面向对象的程序设计语言 特别适合于Internet应用程序开发 而JavaScript是Netscape公司的产品 其目的是为了扩展Netscape Navigato
  • 人才供应链(17年12月)

    库克来中国访问时说 高质量的人才是Apple公司最需要的 而苹果商店的开发者中 中国有200万开发者在支持应用商店 其中大部分是在广州 苹果的供应链也在中国 配套的零部件 面对高要求和近似到极限的品质要求 只有在中国才能满足 IT行业的人才
  • 压缩/减小VirtualBox虚拟硬盘文件占用空间

    文章目录 网上的做法 导出虚拟电脑 再导入 网上的做法 网上有两种压缩空间的做法 1 在虚拟机中 使用 SDelete 例如 sdelete c z 经本人实测 不仅不能压缩 因为SDelete 扫描了整个c 盘 而 VirtualBox
  • 【多模态】7、DINO

    文章目录 一 背景 二 方法 2 1 Contrastive DeNoising Training 2 3 Mixed Query Selection 2 4 Look Forward Twice 三 效果 论文 DINO DETR wit
  • 联想E450c下vmware安装ubuntu " Intel VT-x 处于禁用状态"

    实验环境 lenovo E450c 报错信息 解决办法 按F12进入BIOS 选择Security下的Virtualization 在Intel R 的行 设置Enabled 按F10保存 重新打开虚拟机 参考链接 vmware安装ubun
  • linux 挂载以及初始化硬盘

    linux 挂载以及初始化硬盘 简述 过多的赘述就不说了 一般使用linux完成一些像iscsi服务存储配置啥的 都需要用到硬盘的挂载来扩充服务器的存储空间 这里就简简单单给大家讲一下linux如何挂载初始化新的硬盘 我这里使用的是linu
  • CRC编码计算方法及C语言实现

    CRC编码计算方法及C语言实现 CRC Cyclic Redundancy Check 是一种常用的错误校验码 用于检测和纠正传输过程中的错误 在数据通信和存储中 CRC编码被广泛应用 因为它能够高效地检测错误 并且实现简便 CRC编码计算
  • V神·以太坊上的分片

    译者序 本文是我应以太坊中文社区 Ethfans org 之邀做的翻译稿 原文取自以太坊社区的Github https github com ethereum sharding blob develop docs doc md 原文最后更新
  • Flamingo

    基于已有的图像模型和文本模型构建多模态模型 最终模型的输入是图像 视频和文本 输出是文本 Vision encoder来自预训练的NormalizerFree ResNet NFNet 之后经过图文对比损失进一步学习 图片经过Vision
  • antd中Tabs切换控制其他地方的标签显隐(react)

    antd中Tabs切换控制其他地方的标签的显示与隐藏 过程如下 tab的回调函数 拿到key值之后就离成功不远了 然后在右边的标签下还有内容 也需要根据tab切换去控制显隐 和上面是一个道理 可以直接给里面的每个div类名 根据key值 去
  • Java写一个excel工具类_Java操作Excel工具类(poi)

    1 importorg apache commons lang3 exception ExceptionUtils 2 importorg apache poi hssf usermodel HSSFDataFormat 3 importo
  • STM32传感器外设集 -- 蓝牙(HC-05)+超声波(hc-sr04)

    前言 前言 蓝牙外设还没有给大家安排上 今天我就给大家安排上使用蓝牙传输超声波距离的例程 会给大家附带蓝牙的上位机的测试APP 一 模块介绍 1 连接图 蓝牙模块 引脚 超声波传感器 引脚 GND GND GND GND VCC 3 3 V
  • 基础IO(文件输入输出、标准IO接口、文件描述符和文件流指针)

    目录 基础IO 文件的输入输出操作 FILE fopen char filename char mode 文件名称 打开方式 size t fread char buf size t block size size t block coun