《Linux C 智能 IO 矩阵:输入输出的自适应数据流转》
1. 标准库IO简介
标准库IO特点:通过操作系统提供的接口(API)和操作系统进行交互。(接近100个函数)
1.1. IO的过程
操作系统:向上为用户提供操作接口,向下为统筹控制硬件。
操作系统的组成:内核+外壳(shell)。
linux内核的五大功能:进程管理,内存管理,文件管理,网络管理,设备管理。
C语言基础最早接触的IO:
- printf 标准输出
- scanf 标准输入
1.2. IO的种类
- 文件IO (系统调用)
- 标准IO (库函数)
1.3. 文件IO(系统调用)
系统调用是受控的内核入口,我们通过系统调用从用户空间进入内核空间(另外一种说法:从用户空间进入内核空间的过程叫做系统调用),常用于linux系统。
特点:系统调用的可移植性差,效率相对较低,实时性强。
1.4. 标准IO(库函数)
简单可以理解成:库函数 = 系统调用+缓冲区
库函数的可移植性强,效率高,实时性差。
(库函数减少了系统调用的次数,从而提高的内核的工作效率)
1.5. 常用的函数接口
- 文件IO:open,close,read,write,lseek
- 标准IO:fopen,fclose,fread,fwrite,.......
2. 标准IO(库函数)
2.1. FILE指针
FILE是标准库中定义的一个结构体。
在这个结构体中包含了打开文件的相关信息。
FILE指针就是一个结构体指针。我们通过FILE指针去对文件进行操作。
当使用fopen函数成功打开文件的时候,就会返回一个FILE指针,后续我们对文件的读写操作都是通过这个FILE指针去进行的。
每个正在运行的程序都会维护自己的FILE指针,即使多个程序打开同一个文件,对应的FILE指针也是不同的。
每个正在运行的程序都有三个默认打开的FILE指针。
- 标准输入:stdin -- scanf
- 标准输出:stdout --- printf
- 标准出错:stderr --- perror
struct _IO_FILE
{ char *_IO_buf_base; /* 缓冲区的起始地址 */ char *_IO_buf_end; /* 缓冲区的结束地址 */ int _fileno; /*文件描述符*/
};
2.2. fopen函数
#include <stdio.h>
FILE *fopen(const char *pathname, const char *mode);
功能:打开pathname对应的文件
参数:pathname:文件的路径和名字mode:打开文件的模式 "r" "r+"r 以只读的方式打开文件,光标定位在文件的开头r+ 以读写的方式打开文件,光标定位在文件开头w 以只写的方式打开文件,光标定位在文件开头。如果文件不存在就创建,如果文件存在就清空w+ 以读写的方式打开文件,光标定位在文件开头。如果文件不存在就创建,如果文件存在就清空a 以追加的方式打开文件,光标定位在文件结尾,如果文件不存在就创建a+ 以追加和读的方式打开文件,如果写光标会定位到文件的结尾,如果读,光标会定位在文件的开头。如果文件不存在就创建
返回值:成功返回文件对应的FILE指针,失败返回NULL,置位错误码
fopen使用实例
#include<stdio.h>
int main()
{FILE *fp = NULL;//定义一个FILE指针//使用fopen 打开文件// //以只读的方式打开文件,文件不存在会报错// fp = fopen("./a.txt","r");// if(NULL == fp){// printf("fopen a.txt error\n");// return -1;// }//以只写的方式打开文件,文件不存在就创建,存在就清空fp = fopen("./a.txt","w");if(NULL == fp){printf("fopen a.txt error\n");return -1;}//不管以什么样的方式去打开文件,当前用户一定要有对该文件的操作权限return 0;
}
2.3. fclose函数
#include <stdio.h> int fclose(FILE *stream);
功能:关闭FILE指针
参数: stream:通过fopen获取到的文件指针
返回值:成功返回0,失败返回EOF,置位错误码
fclose代码实例
#include<stdio.h>
int main()
{//1.先做一个正常的输入int a = 0;scanf("%d",&a);printf("第一次输出a = %d\n",a);fclose(stdin); //关闭标准输入scanf("%d",&a);printf("第二次输出a = %d\n",a);//2.做一个正常的输出printf("111111111111\n");fclose(stdout); //关闭标准输出printf("2222222222222\n");return 0;
}
2.4. 错误码
2.4.1. 错误码的概念
- 错误码是系统调用失败之后,内核向用户空间返回的错误信息的编号。
- 错误码本质是一个整数,错误码保存在errno.h中的一个全局变量errno中。
- 错误码在内核中有4k个。
/usr/include/asm-generic/errno-base.h
2.4.2. 错误的原理
2.4.3. 错误码使用实例1
#include<stdio.h>
#include<errno.h>
int main(int argc,const char* argv[])
{//打开一个不存在的文件FILE *fp = fopen("b.txt","r");if(NULL == fp){printf("errno = %d\n",errno);//errno = 2,表示没有这个文件//return -1;}//成功调用函数,并不会置位错误码fp = fopen("a.txt","r");printf("errno = %d\n",errno);return 0;
}
2.4.4. 将错误码转换为错误信息的函数(strerror)
#include <string.h>char *strerror(int errnum);功能:将errnum转换为对应的错误信息参数:errnum:错误码返回值:错误码对应的错误信息,失败返回"Unknown error nnn"
2.4.5. 直接输出错误信息
#include <stdio.h> void perror(const char *s);
功能:直接输出错误信息,输出之后,会自动添加换行
参数: s:错误信息的提示,后面会自动添加冒号
返回值:空#include<stdio.h> #include<errno.h>
#include<string.h>
int main(int argc,const char* argv[])
{ //打开一个不存在的文件 FILE *fp = fopen("b.txt","r");
if(NULL == fp)
{ perror("fopen b.txt error"); }
return 0; }
2.5. fgetc函数
#include <stdio.h>
int fgetc(FILE *stream);
功能:从文件中读取一个字符,以返回值的形式返回
参数: stream:文件指针
返回值:成功返回获取到的字符,失败或者读取到文件结尾返回EOF
fgetc使用实例
#include <my_head.h>int main(int argc, const char *argv[])
{// 1.打开文件FILE *fp = fopen("./a.txt", "r");if (NULL == fp)PRINT_ERR("fopen a.txt error");// 2.从文件中读取一个字符,光标向后偏移一个字节char ch = 0;ch = fgetc(fp);printf("ch = %c\n", ch); //读取到 '1'//再次读取,读取到 '2'ch = fgetc(fp);printf("ch = %c\n", ch);//从终端获取一个字符ch = fgetc(stdin); //这种用法,等价于getchar()printf("ch = %c\n", ch);ch = fgetc(stdin); //这种用法,等价于getchar()printf("ch = %c\n", ch);return 0;
}
2.6. fputc函数
#include <stdio.h>
int fputc(int c, FILE *stream);
功能:向文件中写入一个字符
参数: c:要写入的字符 stream:文件指针
返回值:成功返回写入的字符的ascii码,失败返回EOF
fputc使用实例
#include<my_head.h>int main(int argc,const char* argv[])
{// //1.只写的方式打开文件// FILE *fp = fopen("./a.txt","w");// if(NULL == fp)// PRINT_ERR("fopen a.txt error");// //2.fputc向文件中写入内容// fputc('h',fp);// fputc('e',fp);// fputc('l',fp);// fputc('l',fp);// fputc('o',fp);// //3.向终端输出内容// fputc('a',stdout);//'a'会输出到终端中,这种用法和putchar()完全一致//以读写的方式打开文件FILE *fp = fopen("./a.txt","r+");if(NULL == fp)PRINT_ERR("fopen a.txt error");//fputc向文件中写入内容fputc('h',fp); //如果文件中原本有内容,那么fputc会将光标后的字符给覆盖掉//光标问题:读写用的是同一个光标fgetc(fp);//光标向后偏移一个字节fputc('0',fp);//会将文件中第二个字符给覆盖掉return 0;
}
2.7. fgets函数
char *fgets(char *s, int size, FILE *stream);
功能:从文件中获取字符串,读取size-1个字节的数据
参数: s:保存获取到的字符串的首地址
size:要读取的字节数 stream:文件指针
返回值:成功返回读取到的字符串,失败或者读取到文件结尾返回NULL
fgets的使用
2.8. sprintf/snprintf/fprintf
#include <stdio.h>
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
功能:向文件中格式化输出内容
参数:stream:文件指针format:输出格式...:可变参
返回值:成功返回格式化输出的字符的个数,失败返回负数
int sprintf(char *str, const char *format, ...);
功能:向数组中格式化输出内容
参数:str:输出的目标地址format:输出格式...:可变参
返回值:成功返回格式化输出的字符的个数,失败返回负数
int snprintf(char *str, size_t size, const char *format, ...);
功能:向数组中格式化输出内容
参数:str:输出的目标地址size:格式化输出字符的个数format:输出格式...:可变参
返回值:成功返回格式化输出的字符的个数,失败返回负数
printf家族使用实例
#include <my_head.h> // 包含自定义头文件int main(int argc, const char* argv[])
{// 定义字符变量 var1 并初始化为 'a'char var1 = 'a';// 定义整数变量 var2 并初始化为 12345int var2 = 12345;// 定义字符数组 var3 并初始化为一个长字符串char var3[128] = {"12345121111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"};// 定义字符数组 buf 并初始化为 0char buf[128] = {0};// 1. 使用 sprintf 函数将格式化的字符串写入 buf// 注意: sprintf 不会检查缓冲区大小,可能导致数组越界// sprintf(buf, "var1 = %c var2 = %d var3 = %s", var1, var2, var3);// printf("buf = [%s]\n", buf);// 2. 使用 snprintf 函数将格式化的字符串写入 buf// snprintf 解决了数组越界问题,虽然有时会警告,但程序不会崩溃snprintf(buf, sizeof(buf), "var1 = %c var2 = %d var3 = %s", var1, var2, var3);printf("buf = [%s]\n", buf);// 3. 使用 fprintf 向文件中格式化输出内容FILE *fp = fopen("a.txt", "w"); // 以写模式打开文件 a.txtif (NULL == fp) // 检查文件是否成功打开PRINT_ERR("fopen error"); // 如果文件打开失败,打印错误信息fprintf(fp, "var1 = %c var2 = %d var3 = %s", var1, var2, var3); // 向文件写入格式化字符串fclose(fp); // 关闭文件return 0; // 返回 0 表示程序成功结束
}
2.9. fseek/ftell/rewind 光标相关函数
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
功能:偏移光标位置
参数:stream:文件指针offset:偏移量>0:向后偏移=0:不偏移<0:向前偏移whence:偏移的基地址SEEK_SET:从文件开头开始偏移SEEK_CUR:从当前位置开始偏移SEEK_END:从文件结尾开始偏移
返回值:成功返回0,失败返回-1,置位错误码
long ftell(FILE *stream);
功能:获取光标当前位置到开头的字节数
参数:文件指针
返回值:成功返回当前位置到开头的字节数,失败返回-1,置位错误码void rewind(FILE *stream);
功能:将光标偏移到文件开头
参数:文件指针
偏移光标实例
#include<my_head.h>int main(int argc,const char* argv[])
{//1.以读写的方式打开文件FILE *fp = fopen("./a.txt","r+");if(NULL == fp)PRINT_ERR("fopen error");char ch = 0;//2.从当前位置向后偏移光标fseek(fp,3,SEEK_CUR);ch = fgetc(fp);printf("ch = %c\n",ch);//3.从文件开头向后偏移fseek(fp,3,SEEK_SET);ch = fgetc(fp);printf("ch = %c\n",ch);//4.从文件结尾偏移光标fseek(fp,-3,SEEK_END);ch = fgetc(fp);printf("ch = %c\n",ch);//5.从文件结尾向后偏移int ret = fseek(fp,3,SEEK_END);printf("ret = %d\n",ret);//0,不会出错fputc('a',fp); //会在文件结尾后空出三个字节,然后再将a写入//6.从文件开头向前偏移ret = fseek(fp,-3,SEEK_SET);printf("ret = %d\n",ret);//-1,出错//ftell函数的使用fseek(fp,0,SEEK_END);int pos = ftell(fp);printf("pos = %d\n",pos); //如果光标位置在结尾,获取到的刚好是文件的大小//rewind函数rewind(fp);pos = ftell(fp);printf("pos = %d\n",pos);return 0;
}
3. 文件IO(系统调用)
3.1. 文件描述符
- 在文件IO中我们文件描述符去操作文件。
- 文件描述符本质就是一个非负的整数。
- 文件描述符的最大的限制是1024.
- 可以通过ulimit -a去查看
- 可以通过 ulimit -n 2048 修改文件描述符的最大个数
每个正在行的程序都有三个默认打开的文件描述符
- 标准输入:0
- 标准输出:1
- 标准出错:2
- 文件描述符的分配,遵循最小分配原则。
- 系统会把最小的没有被分配的文件描述符分配给你。
- 文件描述符如何操作文件?
3.2. open函数的使用
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
功能:打开文件
参数:pathname:文件的路径和名字 flags:打开文件的模式O_RDONLY:以只读的方式打开文件O_WRONLY:以只写的方式打开文件O_RDWR:以读写的方式打开文件 //以上三种打开文件的模式必须包含一个O_APPEND:以追加的方式打开文件O_CREAT:创建文件的标志如果flags中有O_CREAT这个参数,那么就需要使用到第三个参数O_TRUNC:清空文件的标志O_EXCL :以独占的方式打开文件必须配合O_CREAT使用加了这个参数之后,使用open创建文件的时候,如果文件存在,会返回文件已经存在的错误 错误码置为EEXISTmode:创建文件的权限如果第二个参数有O_CREAT那么就需要填充这个参数 比如:open("./a.txt",O_RDWR|O_CREAT|O_EXCL,0666)0666就表示我想要创建的文件的权限实际创建出来的文件的权限和umask相关mode & (~umask)umask:是创建文件的掩码umask查看的方式:umask 命令修改umask的方式: umask 掩码值mode 0666 110 110 110umask 0002 000 000 010实际: 0664 110 110 110mode 0666 110 110 110umask 0222 010 010 010实际: 0444 100 100 100
返回值:成功返回文件描述符,失败返回-1置位错误码文件描述符遵循最小分配原则open("./a.txt",O_RDWR|O_CREAT|O_EXCL)"r":O_RDONLY
"r+":O_RDWR
"w":O_WRONLY|O_CREAT|O_TRUNC
"w+":O_RDWR|O_CREAT|O_TRUNC
"a":O_APPEND|O_WRONLY|O_CREAT
"a+":O_APPEND|O_RDWR|O_CREAT
flags的原理
open使用实例
#include <my_head.h> // 包含自定义头文件int main(int argc, const char* argv[])
{int fd = 0;// 打开文件,只读的方式打开// fd = open("./a.txt", O_RDONLY);// if (-1 == fd)// PRINT_ERR("open file error");// 以"w+"的方式打开文件// fd = open("./a.txt", O_RDWR | O_CREAT | O_TRUNC, 0664);// if (-1 == fd)// PRINT_ERR("open file error");// 以独占的方式打开文件// fd = open("./a.txt", O_RDWR | O_CREAT | O_EXCL, 0664);// if (-1 == fd) {// if (errno == EEXIST) {// printf("文件已经存在\n");// // 发现文件存在,我换个名字,重新创建一下// fd = open("./b.txt", O_RDWR | O_CREAT | O_EXCL, 0664);// if (-1 == fd) {// printf("再次创建文件失败\n");// return -1;// }// } else {// printf("打开失败\n");// }// }// 文件描述符遵循最小分配原则int fd1, fd2, fd3;// 以只读方式打开文件 a.txtfd1 = open("./a.txt", O_RDONLY);if (-1 == fd1) {PRINT_ERR("open file error");return -1;}printf("fd1 = %d\n", fd1); // 打印文件描述符 fd1 的值// 以只读方式打开文件 b.txtfd2 = open("./b.txt", O_RDONLY);if (-1 == fd2) {PRINT_ERR("open file error");return -1;}printf("fd2 = %d\n", fd2); // 打印文件描述符 fd2 的值// 关闭文件描述符 fd1close(fd1);printf("fd1 已关闭\n");// 再次以只读方式打开文件 b.txtfd3 = open("./b.txt", O_RDONLY);if (-1 == fd3) {PRINT_ERR("open file error");return -1;}printf("fd3 = %d\n", fd3); // 打印文件描述符 fd3 的值return 0; // 返回 0 表示程序成功结束
}
3.3. close函数
#include <unistd.h>
int close(int fd);
功能:关闭文件
参数:fd:文件描述符
返回值:成功返回0,失败返回-1,置位错误码
#include<my_head.h>int main(int argc,const char* argv[])
{int var1 = 0;scanf("%d",&var1);printf("var1 = %d\n",var1);close(0);//关闭标准输入scanf("%d",&var1);printf("var1 = %d\n",var1);printf("111111111111\n");close(stdout->_fileno);//关闭标准输出printf("22222222222222\n");perror("msg");close(2); //关闭标准出错perror("msg");return 0;
}
3.4. read/write函数
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
功能:从文件中读取count个字节到buf中
参数:fd:文件描述符buf:保存读取到的数据的首地址count:要读取的字节数
返回值:成功返回实际读取到的字节数,如果读取到文件结尾,返回0,失败返回-1.置位错误码
ssize_t write(int fd, const void *buf, size_t count);
功能:将buf中的数据,向文件中写入count个字节
参数:fd:文件描述符buf:保存我们要写入的数据count:想要写入的字节数
返回值:成功返回实际写入的字节数,失败返回-1,置位错误码
read使用实例
#include <my_head.h> // 包含自定义头文件int main(int argc, const char* argv[])
{// 1. 打开文件// 以只读方式打开文件 a.txt,如果文件不存在则创建,权限设置为 0664int fd = open("./a.txt", O_RDONLY | O_CREAT, 0664);if (-1 == fd) {PRINT_ERR("open error"); // 如果打开文件失败,打印错误信息return -1; // 返回 -1 表示程序失败}// 2. 从文件中读取字符串char buf[128] = {0}; // 定义一个长度为 128 的字符数组 buf,并初始化为 0int ret = 0; // 定义一个整数变量 ret 用于存储 read 函数的返回值// 使用 read 函数从文件描述符 fd 中读取数据到 buf 中,最多读取 sizeof(buf) 字节ret = read(fd, buf, sizeof(buf));printf("buf = [%s]\n", buf); // 打印读取到的字符串printf("ret = %d\n", ret); // 打印 read 函数的返回值,表示实际读取的字节数// 再次从文件中读取数据// 由于文件指针已经到达文件末尾,再次读取会返回 0ret = read(fd, buf, sizeof(buf));printf("ret = %d\n", ret); // 打印 read 函数的返回值,应为 0// 关闭文件描述符close(fd);return 0; // 返回 0 表示程序成功结束
}
write函数使用实例
#include <my_head.h> // 包含自定义头文件
#include <string.h> // 包含字符串处理函数的头文件int main(int argc, const char* argv[])
{// 1. 打开文件// 以读写方式打开文件 a.txtint fd = open("./a.txt", O_RDWR);if (-1 == fd) {PRINT_ERR("open error"); // 如果打开文件失败,打印错误信息return -1; // 返回 -1 表示程序失败}// 2. 向文件中写入内容, 写入整型int a = 100;// 使用 write 函数将整型变量 a 写入文件write(fd, &a, sizeof(a));// 3. 向文件中写入字符串char buf[128] = {"hello world"};// write(fd, buf, sizeof(buf)); // 这会将数组中所有的数据写进文件中,包括0// 使用 write 函数将字符串 buf 写入文件,只写入字符串的实际长度int ret = write(fd, buf, strlen(buf));printf("ret = %d\n", ret); // 打印 write 函数的返回值,表示实际写入的字节数// 关闭文件描述符close(fd);return 0; // 返回 0 表示程序成功结束
}
3.5. lseek函数
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
功能:偏移文件光标
参数:fd:文件描述符offset:偏移量<0:向前偏移=0:不偏移>0:向后偏移whence:SEEK_SET:从文件开头开始偏移SEEK_CUR:从当前位置开始偏移SEEK_END:从文件结尾开始偏移
返回值:成功返回当前光标位置到文件开头的距离,失败返回(off_t) -1置位错误码
lseek使用实例
#include <my_head.h>// 定义一个 RGB 结构体,用于表示颜色的 RGB 值
typedef struct RGB
{unsigned char b; // 蓝色通道的值unsigned char g; // 绿色通道的值unsigned char r; // 红色通道的值// unsigned char a;//如果位深是32,需要用到这个成员,是透明度
} rgb_t;/*** @brief 主函数,程序的入口点* * 该函数用于打开一个 BMP 图片文件,读取其头部信息,* 并在图片的左上角绘制一个 500x300 的彩色矩形。* * @param argc 命令行参数的数量* @param argv 命令行参数的数组* @return int 程序的退出状态码,0 表示正常退出*/
int main(int argc, const char *argv[])
{// 1.打开图片文件int fd = open("./ddm.bmp", O_RDWR); // 以读写模式打开指定的 BMP 文件if (-1 == fd)PRINT_ERR("fopen error"); // 如果打开文件失败,打印错误信息// 读取图片类型 BMchar bftype[3] = {0}; // 用于存储 BMP 文件的类型信息,以字符串形式存储read(fd, bftype, 2); // 从文件中读取 2 个字节的类型信息printf("bftype = %s\n", bftype); // 打印 BMP 文件的类型信息// 读取图片大小 622054int bfSize = 0; // 用于存储 BMP 文件的大小read(fd, &bfSize, 4); // 从文件中读取 4 个字节的文件大小信息printf("bfsize = %d\n", bfSize); // 打印 BMP 文件的大小// 读取图片头的大小,54int head_size = 0; // 用于存储 BMP 文件头的大小lseek(fd, 0xA, SEEK_SET); // 将文件指针移动到文件头中存储文件头大小的位置read(fd, &head_size, 4); // 从文件中读取 4 个字节的文件头大小信息printf("head_size = %d\n", head_size); // 打印 BMP 文件头的大小// 读取图片的宽度 1920int width = 0; // 用于存储 BMP 图片的宽度lseek(fd, 0x12, SEEK_SET); // 将文件指针移动到文件头中存储图片宽度的位置read(fd, &width, 4); // 从文件中读取 4 个字节的图片宽度信息printf("width = %d\n", width); // 打印 BMP 图片的宽度// 读取图片的高度 1080int high = 0; // 用于存储 BMP 图片的高度read(fd, &high, 4); // 从文件中读取 4 个字节的图片高度信息printf("high = %d\n", high); // 打印 BMP 图片的高度// 读取图片的位深int bitcount = 0; // 用于存储 BMP 图片的位深lseek(fd, 0x1C, SEEK_SET); // 将文件指针移动到文件头中存储图片位深的位置read(fd, &bitcount, 4); // 从文件中读取 4 个字节的图片位深信息printf("bitcount = %d\n", bitcount); // 打印 BMP 图片的位深// 修改图像数据int ret = lseek(fd, 54, SEEK_SET); // 偏移光标到像素数据之前printf("ret = %d\n", ret); // 打印文件指针的偏移量rgb_t color = {227, 22, 233}; // 定义一个 RGB 颜色值,用于绘制矩形// 在图片的左上角绘制一个 500x300 的彩色矩形for (int j = 0; j < 300; j++){for (int i = 0; i < 500; i++){write(fd, &color, sizeof(rgb_t)); // 将指定的颜色值写入文件}lseek(fd, (1920 - 500) * 3, SEEK_CUR); // 跳过当前行剩余的像素数据}close(fd); // 关闭文件return 0;
}
3.6. stat函数
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
功能:获取文件信息
参数:pathname:文件的路径和名字statbuf:保存文件信息的结构体的首地址
返回值:成功返回0,失败返回-1,置位错误码struct stat {dev_t st_dev; /* 文件所在磁盘的设备号 */ino_t st_ino; /* 文件的inode号 */mode_t st_mode; /* 文件的类型和权限 */ nlink_t st_nlink; /* 硬连接数,对于目录文件来说,这个数值是目录下子目录的个数*/uid_t st_uid; /* 文件所属用户的用户id */gid_t st_gid; /* 文件所属组的组id */dev_t st_rdev; /* 如果文件是设备文件,那么该字段为设备文件的设备id */off_t st_size; /* 文件的大小 */blksize_t st_blksize; /* 文件系统一页内存的大小*/blkcnt_t st_blocks; /* 文件所占块儿的数量*/struct timespec st_atim; /* 上次访问文件的时间 */struct timespec st_mtim; /* 上次修改文件的时间 */struct timespec st_ctim; /*上次文件状态改变的时间 */
};对于st_mode字段的解释:
mode_t st_mode;
st_mode :12~15bit位表示的是文件的类型
st_mode: 0~8个bit位表示的是文件的权限
获取文件类型:S_IFMT 0170000 文件类型的掩码S_IFSOCK 0140000 套接字文件S_IFLNK 0120000 链接文件S_IFREG 0100000 普通文件S_IFBLK 0060000 块设备文件S_IFDIR 0040000 目录文件S_IFCHR 0020000 字符设备文件S_IFIFO 0010000 管道文件stat(pathname, &sb);if ((sb.st_mode & S_IFMT) == S_IFREG) {/* Handle regular file */}也可以通过如下宏定义去判断文件类型:如果文件类型匹配,下列的宏定义会返回1;S_ISREG(m) is it a regular file?S_ISDIR(m) directory?S_ISCHR(m) character device?S_ISBLK(m) block device?S_ISFIFO(m) FIFO (named pipe)?S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.)S_ISSOCK(m) socket? (Not in POSIX.1-1996.)
stat(pathname, &sb);if (S_ISREG(sb.st_mode)) {/* Handle regular file */} 文件权限的获取:st_mode & 0777 即可获取到文件的所有权限信息如果想要查看系统提供的宏定义,可以 man 7 inode
#include <my_head.h>/*** @brief 主函数,程序入口,用于获取并输出文件的属性信息* * 该函数接收一个命令行参数作为文件名,通过 `stat` 函数获取文件的属性信息,* 然后输出文件的基本信息、访问/修改/状态改变时间、文件类型和权限。* * @param argc 命令行参数的数量* @param argv 命令行参数数组,其中 argv[1] 应为要查询的文件名* @return int 程序的退出状态码,0 表示成功,-1 表示入参错误*/
int main(int argc, const char *argv[])
{// 检查命令行参数数量是否正确if (argc != 2){// 若参数数量不对,输出错误信息printf("入参错误\n");// 提示正确的使用方式printf("Usage:./a.out filename\n");return -1;}// 1.获取文件属性信息// 定义一个 stat 结构体变量,用于存储文件的属性信息struct stat st;// 调用 stat 函数获取指定文件的属性信息stat(argv[1], &st);// 2.输出文件信息// 输出文件的 i 节点号、用户 ID、文件大小、块大小、占用块数printf("ino:%ld,uid:%d,size:%ld,blksize:%ld,blks:%ld\n",st.st_ino, st.st_uid, st.st_size, st.st_blksize, st.st_blocks);// 输出文件上次被访问的时间printf("上次访问文件的时间%ld\n", st.st_atime);// 输出文件内容上次被修改的时间printf("上次修改文件的时间%ld\n", st.st_mtime);// 输出文件状态(如权限、所有者等)上次改变的时间printf("上次文件状态改变的时间%ld\n", st.st_ctime);// 3.输出文件的类型和权限// 根据文件的模式位判断文件类型switch (st.st_mode & __S_IFMT){case __S_IFSOCK:// 如果是套接字文件,输出相应信息printf("是套接字文件\n");break;case __S_IFLNK:// 如果是符号链接文件,输出相应信息printf("是链接文件\n");break;case __S_IFREG:// 如果是普通文件,输出相应信息printf("是普通文件\n");break;case __S_IFBLK:// 如果是块设备文件,输出相应信息printf("是块设备文件\n");break;case __S_IFDIR:// 如果是目录文件,输出相应信息printf("是目录文件\n");break;case __S_IFCHR:// 如果是字符设备文件,输出相应信息printf("是字符设备文件\n");break;case __S_IFIFO:// 如果是命名管道文件,输出相应信息printf("是管道文件\n");break;}// 输出文件的权限,以八进制形式显示printf("mode = %#o\n", st.st_mode & 0777);return 0;
}
3.7. getpwuid,getgrgid函数的使用
#include <my_head.h>int main(int argc, const char *argv[])
{// 1.获取用户的uiduid_t uid = getuid();// 2.根据uid获取用户信息struct passwd *usr_info = NULL;usr_info = getpwuid(uid);if(NULL == usr_info)PRINT_ERR("getpwuid error");printf("用户名:%s 用户密码:%s uid:%d gid:%d 用户描述:%s 家目录:%s 命令行解释器:%s \n",\usr_info->pw_name,usr_info->pw_passwd,usr_info->pw_uid,usr_info->pw_gid,\usr_info->pw_gecos,usr_info->pw_dir,usr_info->pw_shell);return 0;
}
#include<my_head.h>int main(int argc,const char* argv[])
{//1.获取组idgid_t gid = getgid();//2.通过组id获取组信息struct group * gr_info = NULL;gr_info = getgrgid(gid);if(NULL == gr_info)PRINT_ERR("getgrgid error");printf("组名:%s 组密码:%s 组id:%d \n",\gr_info->gr_name,gr_info->gr_passwd,gr_info->gr_gid);return 0;
}
3.8. 目录操作
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
功能:打开目录
参数:name:目录的路径和名字
返回值:成功返回目录指针,失败返回NULL,置位错误码#include <dirent.h>
struct dirent *readdir(DIR *dirp);
功能:从目录中读取内容,每读取一次,返回一个保存文件信息的结构体指针
参数:dirp:opendir返回的目录指针
返回值:成功返回一个结构体指针,这个结构体指针指向的结构体中包含了目录中某个文件的相关信息失败:返回NULL,置位错误码如果读取到文件结尾,返回NULL
struct dirent {ino_t d_ino; /* 文件的inode号*/off_t d_off; /* 不需要关注 */unsigned short d_reclen; /* 这条记录的长度 */unsigned char d_type; /*
文件的类型 */DT_BLK 块儿设备文件.
DT_CHR 字符设备文件.
DT_DIR 目录文件.
DT_FIFO 管道文件.
DT_LNK 链接文件.
DT_REG 普通文件.
DT_SOCK 套接字文件.
DT_UNKNOWN 未知的文件类型char d_name[256]; /* 文件的名字 */};#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
功能:关闭目录
参数:dirp:目录指针
返回值:成功返回0,失败返回-1,置位错误码
4.库的制作
4.1. 库的概念
库就是将.c文件编程生成的二进制文件。当我们需要使用的时候,直接将库文件链接到我们的可执行程序中即可。
windows:
- xxx.lib -- 静态库
- xxx.dll -- 动态库
linux:
- libxxx.a -- 静态库
- libxxx.so -- 动态库
4.2. 静态库
4.2.1. 静态库的概念
- 静态库的使用,需要将整个库文件编译到我们的可执行程序中去。
- 使用静态库的可执行程序,体积较大。
- 使用静态库的可执行程序,执行效率更高。
- 使用静态库的可执行程序,运行的时候,不需要依赖库文件。
- 静态库的更新比较麻烦。
4.2.2. 静态库的制作
1.编译生成.o文件
gcc -c xxx1.c xxx2.c xxx3.c
2.将.o文件制作生成库文件
ar -cr libxxx.a xxx1.o xxx2.o xxx3.o
ar:制作静态库的命令
c:create
r:replace
上面的命令就是制作生成了静态库,将.o文件放入了库中
4.2.3. 静态库的使用
1.直接编译
gcc main.c libxxx.a -o main
2.更加标准的编译方式
gcc main.c -lxxx -L 库的路径
-l表示链接库,xxx表示库的名字
-L 指明库的路径
main.c
#include<my_head.h>
#include"add.h"
int main(int argc,const char* argv[])
{ int sum = 0; sum =add_func(10,20); printf("sum = %d\n",sum); return 0;
}
add.c
int add_func(int x,int y){ return x+y; }
add.h
#ifndef __ADD_H__ #define __ADD_H__ int add_func(int x,int y); #endif
编译和使用的命令
4.3. 动态库(共享库)
4.3.1. 动态库的概念
- 动态库的使用,只会将库中函数的符号表编译到可执行程序中。
- 使用动态库的可执行程序,体积较小。
- 使用动态库的可执行程序执行效率会低一些。
- 使用动态库的执行程序,运行的时候,需要依赖库文件。
- 动态库的更新比较方便。
4.3.2.动态库的制作
方式1:
- gcc -c -fPIC xxx.c -o xxx.o //编译生成.o文件
- gcc -shared xxx.o -o libxxx.so
- //-fPIC:表示忽略文件位置(赋予动态库共享的特性)
- //-shared 制作动态库的命令
方式2:直接编译生成库文件
gcc -shared -fPIC xxx.c -o libxxx.so
4.3.3. 动态库的使用
- gcc main.c -lxxx -L 库的路径
- -l表示链接库,xxx表示库的名字
- -L 指明库的路径
相关文章:
《Linux C 智能 IO 矩阵:输入输出的自适应数据流转》
1. 标准库IO简介 标准库IO特点:通过操作系统提供的接口(API)和操作系统进行交互。(接近100个函数) 1.1. IO的过程 操作系统:向上为用户提供操作接口,向下为统筹控制硬件。 操作系统的组成&#…...
idea生成自定义Maven原型(archetype)项目工程模板
一、什么是Maven原型(Maven archetype) 引自官网的介绍如下: Maven原型插件官网地址 这里采用DeepSeek助手翻译如下: Maven 原型 什么是原型? 简而言之,原型是一个 Maven 项目模板工具包。原型被定义为一…...
CES Asia 2025增设未来办公教育板块,科技变革再掀高潮
作为亚洲消费电子领域一年一度的行业盛会,CES Asia 2025(第七届亚洲消费电子技术贸易展)即将盛大启幕。今年展会规模再度升级,预计将吸引超过500家全球展商参展,专业观众人数有望突破10万。除了聚焦人工智能、物联网、…...
(二 十 二)趣学设计模式 之 备忘录模式!
目录 一、 啥是备忘录模式?二、 为什么要用备忘录模式?三、 备忘录模式的实现方式四、 备忘录模式的优缺点五、 备忘录模式的应用场景六、 总结 🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方式,…...
物联网同RFID功能形态 使用场景的替代品
在物联网(IoT)和自动识别技术领域,除了RFID标签外,还有一些其他技术产品可以在形态和大小上与RFID标签相似,同时提供类似或更强大的功能。以下是几种能够替代RFID标签的产品: 一、NFC标签 NFC(…...
蓝陵科技:以“数字底座”之力,全面布局影视行业工业化
“在数字技术与文化产业深度融合的今天,海南蓝陵数字科技有限公司(以下简称蓝陵科技)凭借其卓越的渲染实力和前瞻性的战略布局,正逐步成为推动中国影视行业工业化进程的重要力量。2025年2月,蓝陵科技不仅获得了陵水融媒…...
React + TypeScript 实战指南:用类型守护你的组件
TypeScript 为 React 开发带来了强大的类型安全保障,这里解析常见的一些TS写法: 一、组件基础类型 1. 函数组件定义 // 显式声明 Props 类型并标注返回值 interface WelcomeProps {name: string;age?: number; // 可选属性 }const Welcome: React.FC…...
本地部署大数据集群前置准备
1. 设置VMware网段 虚拟网络编辑器——更改设置——选择VMnet8——子网改成192.168.88.0——NAT设置——网关设置为192.168.88.2 2. 下载CentOS操作系统 下载CentOS 7.6(1810)版本 3. 在VMware中安装CentOS操作系统 创建新的虚拟机——典型——安装光盘映像文件——输入账…...
016.3月夏令营:数理类
016.3月夏令营:数理类: 中国人民大学统计学院: http://www.eeban.com/forum.php?modviewthread&tid386109 北京大学化学学院第一轮: http://www.eeban.com/forum.php?m ... 6026&extrapage%3D1 香港大学化学系夏令营&a…...
历年北京理工大学计算机复试上机真题
历年北京理工大学计算机复试上机真题 在线评测:https://app2098.acapp.acwing.com.cn/ 分段函数 题目描述 编写程序,计算下列分段函数 yf(x) 的值。 当 0< x <2,y -x2.5;当 2< x <4,y2-1.5(x-3)(x-3)…...
Linux的缓存I/O和无缓存IO
一、I/O缓存的背景 I/O缓存是指在内存里开辟一块区域,存放用来接收用户输入和用于计算机输出的数据,以减小系统开销和提高外设效率。linux对IO文件的操作分为不带缓存的IO操作和带缓存的IO操作(标准IO操作)。为什么存在C标准I/O库…...
题目 3216 ⭐团建⭐【DFS】蓝桥杯2024年第十五届省赛
小蓝正在和朋友们团建,有一个游戏项目需要两人合作,两个人分别拿到一棵大小为 n 和 m 的树,树上的每个结点上有一个正整数权值 c 1 , c 2 , ⋅ ⋅ ⋅ , c n c_1, c_2, , c_n c1,c2,⋅⋅⋅,cn, d 1 , d 2 , ⋅ ⋅ ⋅ , d m d_1, d_…...
从0到1入门Linux
一、常用命令 ls 列出目录内容 cd切换目录mkdir创建新目录rm删除文件或目录cp复制文件或目录mv移动或重命名文件和目录cat查看文件内容grep在文件中查找指定字符串ps查看当前进程状态top查看内存kill终止进程df -h查看磁盘空间存储情况iotop -o直接查看比较高的磁盘读写程序up…...
战略合作升级 | 大势智慧携手广西地测院,共绘智慧测绘新蓝图
2月26日,武汉大势智慧科技有限公司(以下简称“大势智慧”)与广西壮族自治区地理信息测绘院(以下简称“广西地测院”)在南宁举行战略合作升级签约仪式暨技术交流座谈会。 大势智慧董事长黄先锋与广西地测院党委书记、院…...
批量插入对比-mysql-oracle-sqlserver
单个插入mysql //单个 根据有值就插入,无值不改动 <insert id"insertOne" keyColumn"id" keyProperty"id"parameterType"com.test.log" useGeneratedKeys"true">insert into test_mysql_tab<trim p…...
jmeter阶梯式压测
1、安装plugins manager 链接 Install :: JMeter-Plugins.org 将下载下来的jar包放置在jemter文件的lib\ext下, 重启Jmeter 2、安装阶梯测试第三方插件 在Available Plugins中找到Custom Thread Groups,点击Apply Changes and Restart JMeter后等待插件…...
nginx.conf 完整配置总结概述
----------------------------------------------------------- /usr/local/nginx/sbin/nginx -s reload # 重新载入配置文件 /usr/local/nginx/sbin/nginx -s reopen # 重启 Nginx /usr/local/nginx/sbin/nginx -s stop # 停止 Nginx /usr/local/nginx/sbin/nginx …...
docker常规命令和高级用法
Docker 是一个强大的容器化平台,提供了丰富的命令和功能来管理容器、镜像、网络和存储等。以下是一些常用的 Docker 命令及其高级用法。 1. 容器管理 1.1 启动容器 基本用法: docker run <image_name>示例: docker run ubuntu高级用法…...
Spark核心之02:常用算子详解
1、RDD操作详解 # 启动spark-shell spark-shell --master local[2] 1.1 基本转换 1) map map是对RDD中的每个元素都执行一个指定的函数来产生一个新的RDD。 任何原RDD中的元素在新RDD中都有且只有一个元素与之对应。 举例: scala> val a sc.parallelize(1 …...
【CSS—前端快速入门】CSS 常用样式
CSS 常用 CSS 样式 1. 前端样式查询网站: MDN Web Docs (mozilla.org) w3school 2. border 2.1 借助 MDN 了解 border 我们借助 MDN 网站来学习 border 样式的使用: 2.2 border 常见属性 保存代码,打开页面: 对于标签不同样式的…...
探索DeepSeek-R1的核心秘诀:突破SFT技术的新篇章
摘要 近期,一种显著超越SFT(Sequence-to-Sequence with Teacher Forcing)的技术成为研究焦点。作为o1/DeepSeek-R1的核心秘诀,该技术不仅提升了模型性能,还成功应用于多模态大型模型中,实现了功能扩展。与传…...
DailyNotes 增加提醒功能
TODO:准备给 DailyNotes 增加一个提醒功能,准备接入 AI 来做一些事情。试了一下,非常靠谱。 具体 DailyNotes 和 Ollama 的交互方式,可以直接调用命令行,也可以走网络API。 rayuK2CD9WCYN4 ~ % ollama run deepseek-…...
[Computer Vision]实验六:视差估计
目录 一、实验内容 二、实验过程 2.1.1 test.py文件 2.1.2 test.py文件结果与分析 2.2.1 文件代码 2.2.2 结果与分析 一、实验内容 给定左右相机图片,估算图片的视差/深度;体现极线校正(例如打印前后极线对)、同名点匹配…...
软件测试基础:功能测试知识总结
🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快 一、测试项目启动与研读需求文档 (一) 组建测试团队 1、测试团队中的角色 2、测试团队的基本责任 尽早地发现软件程序、系统或产品中…...
171. Excel 表列序号
Excel 表列序号 题目描述尝试做法推荐做法 题目描述 给你一个字符串 columnTitle ,表示 Excel 表格中的列名称。返回 该列名称对应的列序号 。 例如: A -> 1 B -> 2 C -> 3 … Z -> 26 AA -> 27 AB -> 28 … 示例 1: 输入: colum…...
03.05 QT事件
实现一个绘图工具,具备以下功能: 鼠标绘制线条。 实时调整线条颜色和粗细。 橡皮擦功能,覆盖绘制内容。 撤销功能,ctrl z 快捷键撤销最后一笔 程序代码: <1> Widget.h: #ifndef WIDGET_H #define WIDGET…...
es如何进行refresh?
在 Elasticsearch 中,refresh 操作的作用是让最近写入的数据可以被搜索到。以下为你介绍几种常见的执行 refresh 操作的方式: 1. 使用 RESTful API 手动刷新 你可以通过向 Elasticsearch 发送 HTTP 请求来手动触发 refresh 操作。可以针对单个索引、多个索引或者所有索引进…...
unity6 打包webgl注意事项
webgl使用资源需要异步加载 使用localization插件时要注意,webgl不支持WaitForCompletion,LocalizationSettings.InitializationOperation和LocalizationSettings.StringDatabase.GetTable都不能用 web里想要看到具体的报错信息调试开启这两个…...
【前端基础】Day 9 PC端品优购项目
目录 1. 品优购项目规划 1.1 网站制作流程 1.2 品优购项目整体介绍 1.3 学习目的 1.4 开发工具以及技术栈 1.5 项目搭建工作 1.6 网站favicon图标 1.7 网站TDK三大标签SEO优化 2. 品优购首页制作 2.1 常见模块类命名 2.2 快捷导航shortcut制作 2.3 header制作 2.4…...
【django初学者项目】
下面为你详细介绍如何创建一个简单有趣的 Django 项目——博客系统。这个项目允许用户创建、查看、编辑和删除博客文章。 步骤 1:环境准备 首先,确保你已经安装了 Python 和 pip。然后,创建一个虚拟环境并激活它,接着安装 Django…...
自学微信小程序的第十三天
DAY13 1、使用map组件在页面中创建地图后,若想在JS文件中对地图进行控制,需要通过地图API来完成。先通过wx.createMapContext()方法创建MapContext(Map上下文)实例,然后通过该实例的相关方法来操作map组件。 const m…...
gitbash忽略未追踪文件的解决方式
文章目录 问题描述,如下图解决方式 问题描述,如下图 因为这些事项目本地运行或者IDE环境配置时产生的文件或目录,手动删除后还来出现,怎么实现忽略不显示呢? 解决方式 查看项目的根目录下是否存在.gitignore文件&…...
React生态、Vue生态与跨框架前端解决方案
React生态系统 1 基础框架 React.js 是一个用于构建UI的JavaScript库。 2 应用框架 Next.js 是基于React.js的完整应用框架。主要负责应用如何工作: 应用架构:路由系统、页面结构渲染策略:服务端渲染(SSR)、静态生成(SSG)、客户端渲染性…...
GPPT: Graph Pre-training and Prompt Tuning to Generalize Graph Neural Networks
GPPT: Graph Pre-training and Prompt Tuning to Generalize Graph Neural Networks KDD22 推荐指数:#paper/⭐⭐# 动机 本文探讨了图神经网络(GNN)在迁移学习中“预训练-微调”框架的局限性及改进方向。现有方法通过预训练(…...
【Elasticsearch】Elasticsearch 的`path.settings`是用于配置 Elasticsearch 数据和日志存储路径的重要设置
Elasticsearch 的path.settings是用于配置 Elasticsearch 数据和日志存储路径的重要设置,这些路径在elasticsearch.yml配置文件中定义。以下是关于 Elasticsearch 的路径设置(path.data和path.logs)以及快照存储库配置的详细说明:…...
使用vue3+element plus 的table自制的穿梭框(支持多列数据)
目录 一、效果图 二、介绍 三、代码区 一、效果图 话不多说,先上图 二、介绍 项目需要:通过穿梭框选择人员信息,可以根据部门、岗位进行筛选,需要显示多列(不光显示姓名,还包括人员的一些基础信息&…...
学习笔记:IC存储总结(ROM,RAM, EEPROM, Flash, SRAM, DRAM, DDL)
一,概述 半导体存储器是一种可以存储大量二值信息的半导体器件。在电子计算机及一些其他的数字系统的工作过程中,需要对大量的数据进行储存。由于数据处理的数据量和运算速度的要求,因此把存储量和存取速度作为衡量存储器的重要指标。 在电子…...
本地部署pangolin获取谱系,从而达到预测新冠的流行趋势
步骤 1:安装Docker 注:此步骤忽略,可通过Docker官网对于文档进行安装,地址如下 Docker: Accelerated Container Application Developmenthttps://www.docker.com/ 步骤 2:拉取Pangolin镜像 docker pull staphb/pangolin:latest 步…...
【Python】文件File处理详细解释,附示例(文件操作、模式、编码、指针、调试、大文件处理、文件管理等)
文件 File 处理方法 1. 前言2. 文件基础操作2.1 文件打开与关闭2.2 with 语句(上下文管理器)3. 文件模式详解3.1 基础模式3.2 扩展模式4. 文件读写操作4.1 读取内容4.2 写入内容5. 文件指针和随机访问5.1 seek(offset.whence)5.2 二进制模式下的指针操作6. 文件编码处理6.1 指定…...
Windows 10/11 系统下 Git 的详细安装步骤和基础设置指南
以下是 Windows 10/11 系统下 Git 的详细安装步骤和基础设置指南: Windows 10/11 系统下 Git 的详细安装步骤和基础设置指南 一、详细安装步骤1. 下载 Git 安装包2. 运行安装程序1. 双击安装包,按以下选项配置:2. 点击 Install 完成安装。 二…...
RabbitMQ的四种交换机
RabbitMQ交换机 什么是RabbitMQ RabbitMQ 是一个开源的消息代理和队列服务器,用于在分布式系统中存储和转发消息。它基于 AMQP(高级消息队列协议)实现,支持多种消息传递模式,广泛应用于异步通信、应用解耦、负载均衡…...
探秘基带算法:从原理到5G时代的通信变革【一】引言
文章目录 一、引言1.1 研究背景与意义1.2 研究目的与方法1.3 研究内容与创新点 本博客为系列博客,主要讲解各基带算法的原理与应用,包括:viterbi解码、Turbo编解码、Polar编解码、CORDIC算法、CRC校验、FFT/DFT、QAMtiaozhi/解调、QPSK调制/解…...
ES中数据刷新策略refresh
在 Elasticsearch 中,插入数据时的 refresh 参数控制文档在写入后何时对搜索可见,其行为直接影响数据可见性和系统性能。以下是 refresh 参数的三个可选值(true、false、wait_for)的详细说明及适用场景: 1. refreshtr…...
【向量数据库Weaviate】 和Elasticsearch的区别
Weaviate 和 Elasticsearch 是两种不同类型的数据库,设计目标和应用场景有显著差异。以下是它们的核心区别和适用场景的详细对比: 1. 设计目标与核心能力 维度WeaviateElasticsearch核心能力向量数据库 图数据库(语义搜索优先)全…...
【Wireshark 02】抓包过滤方法
一、官方教程 Wireshark 官网文档 : Wireshark User’s Guide 二、显示过滤器 2.1、 “数据包列表”窗格的弹出过滤菜单 例如,源ip地址作为过滤选项,右击源ip->prepare as filter-> 选中 点击选中完,显示过滤器&#…...
【零基础到精通Java合集】第十五集:Map集合框架与泛型
课程标题:Map集合框架与泛型(15分钟) 目标:掌握泛型在Map中的键值类型约束,理解类型安全的键值操作,熟练使用泛型Map解决实际问题 0-1分钟:泛型Map的意义引入 以“字典翻译”类比泛型Map:明确键和值的类型(如英文→中文)。说明泛型Map的作用——确保键值对的类型一…...
三参数水质在线分析仪:从源头保障饮用水安全
【TH-ZS03】饮用水安全是人类健康的重要保障,其质量直接关系到人们的生命健康。随着工业化、城市化的快速发展,水体污染问题日益严峻,饮用水安全面临着前所未有的挑战。为了从源头保障饮用水安全,科学、高效的水质监测手段必不可少…...
Java8-Stream流介绍和使用案例
Java 8 引入了 Stream API,它提供了一种高效且声明式的方式来处理集合数据。Stream 的核心思想是将数据的操作分为中间操作(Intermediate Operations)和终端操作(Terminal Operations),并通过流水线&#x…...
FieldFox 手持射频与微波分析仪
FieldFox 手持射频与微波分析仪 简述 Keysight FieldFox 便携式分析仪可以在非常恶劣的工作环境中,轻松完成从日常维护到深入故障诊断的各项工作。 选择最适合您需求且有强大软件支持的 Keysight FieldFox 配置。 主要特性 特点: FieldFox 分析仪可…...
JQuery学习笔记,点击按钮加载更多的图片
利用点击按钮模拟某京,某宝,滚动页面加载图片的效果,代码: <!DOCTYPE html> <html><head><meta charset"utf-8"><title>Ajax请求</title></head><body><button id…...