Linux---文件io

news2024/11/18 12:42:27

1.系统调用

由操作系统实现并提供给外部应用程序的编程接口。(Application Programming Interface,API)。是应用程序同系统之间数据交互的桥梁。

C标准函数和系统函数调用关系。一个helloworld如何打印到屏幕。

man手册中一共有九卷,其中一卷就有讲到系统调用,内核就当前操作系统的核心程序,系统的本质都是个程序。内核和硬件打交道,提供的函数只能给上层应用所使用。

提供的系统调用函数实际上在linux内核当中是没有的,只不过却有与之对应的一样功能的函数,比如open在内核当中的源码对应的是sys_open,虽然名字不同,但是几乎是一模一样的

sys_open >>浅封装>> open,操作系统避免与用户进行交互,但又不想让用户真正窥探到内核,因此使用了浅封装给内核中的sys_open包了个保护壳变成open函数让用户可以去调用系统而又不会导致让用户窥探到本质

2.open/close

函数原型:

要导入头文件 #include<unistd.h>

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
int close(int fd);
int creat(const char *pathname, mode_t mode);

 # 可以通过 man open 2 指令去查看配置的文档
 # pathname:文件路径
 # flags:打开方式
 # mode: 权限,mode_t是一个八进制的整型
 # 返回的是一个文件描述符,如果执行错误,会返回-1
 # 同时返回一个errno(操作系统的全局变量),需要导入 errno.h
 # 返回的errno的数字想要知道是什么含义可以通过 man strerror 去查看

常用参数 -- flags

要导入头文件:#include<fcntl.h>

O_RDONLY

O_WRONLY
O_RDWR读写
O_APPEND追加
O_CREAT创建
O_EXCL存放
O_TRUNC截断
O_NONBLOCK非阻塞

创建文件时,指定文件访问权限。权限同时受umask影响。结论为:

文件权限 = mode & ~umask

使用头文件:<fcntl.h>

O_CREAT -- 如果没有该文件就进行创建

创建文件时,其权限与umask挂钩,比如umask = 0002,取反后就是775,然后与mode进行按位与(二进制),最后才得出创建文件的真正权限

 O_TRUNC --- int ftruncate(int fd, off_t length); -- 把文件截断成0

open常见错误

1. 打开文件不存在

2. 以写方式打开只读文件(打开文件没有对应权限)

3. 以只写方式打开目录

perror、strerror、errno

运用

[....]# cd /linux_01
[....]# mkdir -a ./file_IO_test/test
[....]# cd ./file_IO_test/test
[....]# touch dict.txt
[....]# touch ./makefile
[....]# mkdir ./dirct
[....]# vim open.c
    #include<unistd.h>
    #include<stdlib.h>
    #include<fcntl.h>
    #include<string.h>
    int main(int argc,char *agrv[])
    {
         int fd = 0;
         fd = open("./dict.txt",O_RDONLY);
         printf("fd = %d\n",fd);

         int fd1 = 0;
         fd1 = open("./dict.cp",O_RDONLY | O_CREAT,0644);
         printf("fd1 = %d\n",fd);

         //1.打开文件不存在
         int fd2 = 0;
         fd2 = open("./dict.cp1",O_RDONLY);         
         printf("fd2 = %d, error = %d:%s\n",fd2,error,strerror(error)));

         //2.以写方式打开只读文件(打开文件没有对应权限)
         int fd3 = 0; 
         open("./dict.cp2",O_RDONLY | O_CREAT,0411); 
         //创建一个只读文件
         fd3 = open("./dict.cp2",O_WRONLY);
         printf("fd3 = %d, error = %d:%s\n",fd3,error,strerror(error)));
         //fd = -1,errno=13:Permissiondenied

         //3.以只写方式打开目录
         int fd4 = 0;
         fd4 = open("./dict.cp2",O_WRONLY);
         printf("fd4 = %d, error = %d:%s\n",fd4,error,strerror(error)));
         // fd = -1, errno=21:Is a directory                                                   

         close(fd);
         ......
         return 0;

     }

3.read/write函数

ssize_t read(int fd, void *buf, size_t count); 
    从指定位置fd读,然后将读取的东西存入缓冲区buf(待写出数据的缓冲区),count是数据的大小
    成功的话会返回读取到的字节数(读取到文件尾部会返回0),失败的话会返回-1,同时设置errno
ssize_t write(int fd, const void *buf, size_t count);

练习:编写程序实现简单的cp功能。
[....]# vim cptest.c
    #include<Stdio.h>
    #include<stdlib.h>  //perror所用到的头文件
    ....
    #include<fcntl.h>
    int main(int agrc,int **argv){
        char buf[1024];
        int n = 0;

        int fd1 = open(argv[1],O_RDONLY); //read
        if(fd1 == -1){
            perror("open argv1 error\n");
            // 如果读取出错就打印出自定义提示 
            exit(1);       
        }
        int fd2 = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0644);
        # fd2是创建打开一个文件进行进行写入操作,如果该文件中有我内容则清0
        # 如果没有该文件就创建该文件,目的是将fd1的内容写入到fd2
        if(fd2 == -1){
            perror("open argv2 error\n");
            // 如果读取出错就打印出自定义提示 
            exit(1);       
        }

        //写入操作:
        while((n = read(fd1,buf,1024))!=0){
            if(n < 0){
                perror("read error");
                break;           
            }
            write(fd2,buf,n);
            // 第三个参数为n是为了防止缓冲区资源的浪费        
        }

        close(fd1);
        close(fd2);

        return 0;
    }
gcc cptest.c  -o cptest
./cptest.c open.c open2.c
# open.c是要拷贝过去的内容,open2.c是拷贝目的地

比较:如果一个只读一个字节实现文件拷贝,使用read、write效率高,还是使用对应的标库函数(fgetc、fputc)效率高呢?

理想上是write比fputc效率更高:

不管是fputc还是write,最终目的都是要从用户空间进入到系统内核,然后系统内核去驱动磁盘进行写入写出工作,但是只有系统函数才能才去调用系统内核让驱动工作,因此write效率更高,因为write本身就是系统调用提供的函数。而fputc并不是系统调用提供的函数,它底层是先去调用write,然后从用户空间进入到内核空间,借助驱动去驱动磁盘工作

但真是这样吗?

但实际上却是fputc比wirte效率更快:

strace ./可执行文件名称

可以看函数的调用过程

用read和write:read一次读一个,write一次写一个,一次只读取一个字节

用fgetc和fputc:并不是一个字节一个字节的操作,而是4096个字节的进行一次操作

探究:

fputc有自己的缓冲区,当缓冲区的东西满了后,才会去调用write进入到内核,将数据放入到系统级缓冲区,调用驱动进入到磁盘

而write和read没有自己的缓冲区,又因为人为的将buf缓冲区设置为1,因此只能不断地来回反复操作只读取或写入一个字节

----因此可以将buf缓冲区的大小重新设置好,就能实现wirte和read效率更高

read、write函数常常被称为Unbuffered I/O。指的是无用户及缓冲区。但不保证不使用内核缓冲区。-----预读入和缓输出

4.文件描述符

PCB进程控制块

使用命令查看其位置:
[....]# locate sched.h
/usr/src/linux-headers-3.16.0-30/include/linux/sched.h

PCB进程控制块就像一个结构体
struct task_struct { 结构体 }

文件描述符

结构体PCB 的成员变量file_struct *file 指向文件描述符表。

从应用程序使用角度,该指针可理解记忆成一个字符指针数组,下标0/1/2/3/4...找到文件结构体。

本质是一个键值对0、1、2...都分别对应具体地址。但键值对使用的特性是自动映射,我们只操作键不直接使用值。

value中就是个指针指向了一个文件结构体,这个文件结构体中记录了进行操作文件的内容,比如属组、属主、路径等,但操作系统不想暴露这些value,因此只返回了key的值 -- 文件描述符

新打开文件返回文件描述符表中未使用的最小文件描述符。

  • STDIN_FILENO  0
  • STDOUT_FILENO  1
  • STDERR_FILENO 2

最大打开文件数:

一个进程默认打开文件的个数1024。

命令:ulimit -a 查看open files 对应值。默认为1024,可以使用ulimit -n 4096 修改;当然也可以通过修改系统配置文件永久修改该值,但是不建议这样操作。

cat /proc/sys/fs/file-max 可以查看该电脑最大可以打开的文件个数。受内存大小影响

FILE结构体

主要包含文件描述符、文件读写位置、IO缓冲区三部分内容。

struct file {
    ...
        文件的偏移量;
        文件的访问权限;
        文件的打开标志;
        文件内核缓冲区的首地址;
        struct operations * f_op;
    ...
    };

查看方法:

(1) /usr/src/linux-headers-3.16.0-30/include/linux/fs.h

(2) lxr:百度 lxr → lxr.oss.org.cn → 选择内核版本(如3.10) → 点击File Search进行搜索

        → 关键字:“include/linux/fs.h” → Ctrl+F 查找 “struct file {”

        → 得到文件内核中结构体定义

        → “struct file_operations”文件内容操作函数指针

        → “struct inode_operations”文件属性操作函数指针

5.阻塞和非阻塞

读常规文件是不会阻塞的,不管读多少字节,read一定会在有限的时间内返回。从终端设备或网络读则不一定,如果从终端输入的数据没有换行符,调用read读终端设备就会阻塞,如果网络上没有接收到数据包,调用read从网络读就会阻塞,至于会阻塞多长时间也是不确定的,如果一直没有数据到达就一直阻塞在那里。同样,写常规文件是不会阻塞的,而向终端设备或网络写则不一定。

现在明确一下阻塞(Block)这个概念。当进程调用一个阻塞的系统函数时,该进程被置于睡眠(Sleep)状态,这时内核调度其它进程运行,直到该进程等待的事件发生了(比如网络上接收到数据包,或者调用sleep指定的睡眠时间到了)它才有可能继续运行。与睡眠状态相对的是运行(Running)状态,在Linux内核中,处于运行状态的进程分为两种情况:

正在被调度执行。CPU处于该进程的上下文环境中,程序计数器(eip)里保存着该进程的指令地址,通用寄存器里保存着该进程运算过程的中间结果,正在执行该进程的指令,正在读写该进程的地址空间。

就绪状态。该进程不需要等待什么事件发生,随时都可以执行,但CPU暂时还在执行另一个进程,所以该进程在一个就绪队列中等待被内核调度。系统中可能同时有多个就绪的进程,那么该调度谁执行呢?内核的调度算法是基于优先级和时间片的,而且会根据每个进程的运行情况动态调整它的优先级和时间片,让每个进程都能比较公平地得到机会执行,同时要兼顾用户体验,不能让和用户交互的进程响应太慢。

  • 阻塞读终端:【block_readtty.c】
  • 非阻塞读终端【nonblock_readtty.c】
  • 非阻塞读终端和等待超时【nonblock_timeout.c】

注意,阻塞与非阻塞是对于文件而言的。而不是read、write等的属性。read终端,默认阻塞读。

总结read 函数返回值:   

  1. 返回非零值:  实际read到的字节数
  2. 返回-1:
    1. errno != EAGAIN (或!= EWOULDBLOCK)  read出错
    2. errno == EAGAIN (或== EWOULDBLOCK)  设置了非阻塞读,并且没有数据到达。read在以非阻塞方式读一个设备文件(网络文件),并且文件无数据
  3. 返回0:读到文件末尾

例子:

/dev/tty -- 终端文件,STDIN_FILENO和STDOUT_FILENO都是终端文件中的内容,实际上终端文件是已经跟着打开的了

标准输入和输出,当运行该文件时,如果不按键盘输入东西和点击回车,这时候终端就在等待,称为阻塞

阻塞是设备文件、网络文件的属性,不要误以为阻塞是read和write的特性,并且读常规文件无阻塞属性

那么能不能用非阻塞的方式去操作终端文件?

用open中的O_NONBLOCK非阻塞的方式打开tty终端文件,这时候只会反复的读,读到了就输出到屏幕,读不到就继续读,终端并不会进入等待状态(阻塞)

6.fcntl函数

【fcntl.c】 想改变文件的访问控制属性,比如从阻塞状态变成非阻塞状态,那就得关闭文件重新打开文件进行操作,而使用 fcntl 函数可以直接改变

改变一个【已经打开】的文件的访问控制属性,重点掌握这两个参数的使用,F_GETEL F_SETFL

F_GETFL 读取到标准输入终端文件的状态后,通过 |= 添加上非阻塞属性,然后用F_SETFL 将其重新设置,使标准输入变为非阻塞

7.lseek函数

理解

官方定义:重新定位读或写的文件偏移量。

Linux中可使用系统函数lseek来修改文件偏移量(读写位置)

  • 每当打开一个文件,都会有一个叫做“当前文件偏移量”的东西,如果难理解也可以将他理解为指针。 除非打开文件时指定O_APPEND选项,否则文件偏移量默认设置为0。当我们发生了一次读或者写操作时,都会使这个当前文件偏移量发生变化,读/写多少字节,当前偏移量就会向后移动多少。
  • 因此当我们对一个新文件进行完写操作后,进行读操作,会发现什么都读不到,是因为偏移量经过写操作后移到了文件尾部,此时进行读操作肯定什么都读不到了,也就是读和写操作用的是同一个偏移量(文件指针)

lseek和标准I/O库的fseek函数类似,可以移动当前读写位置(或者叫偏移量)。

回忆fseek的作用及常用参数:
SEEK_SET、SEEK_CUR、SEEK_END
int fseek(FILE *stream, long offset, int whence); 
成功返回0;失败返回-1
特别的:超出文件末尾位置返回0;往回超出文件头位置,返回-1

include<lseek.c>
off_t lseek(int fd, off_t offset, int whence); 
    参数:fd //文件描述符,可以通过open函数得到,通过这个fd可以操作某个文件
    参数: offset //文件偏移量,是一个整形数,与whence对应的位置继续往后偏移
    参数:whence //偏移类型,下列三个值中选一个。

            SEEK_SET:该文件的偏移量设为离文件开头offset个字节.
            SEEK_CUR:该文件的偏移量设为其当前值加offset(PS :offest可正负).
            SEEK_END:该文件的偏移量设为文件长度加offset
特别的:lseek允许超过文件结尾设置偏移量,文件会因此被拓展。

注意文件“读”和“写”使用同一偏移位置。                                
lseek函数返回的偏移量(off_t)总是相对于文件头而言的。                                

作用

  1. 移动文件指针到文件头:lseek(fd, 0, SEEK_SET)
  2. 获取当前文件指针的位置:lseek(fd, 0, SEEK_SUR)
  3. 获取文件长度:lseek(fd, 0, SEEK_END)
  4. 拓展文件的长度,当前文件10b、110b,增加了100个字节:lseed(fd, 100, SEEK_END),需要注意拓展完需要再写一次数据,否侧拓展无效

还有另一种方式也可以来拓展文件的大小

[....]# main 2truncate  # 可以查找到另一个函数truncate
>>>int truncate(const char* path, off_t length)

例子

1.移动文件指针到文件头和获取当前文件指针的位置

//导入所有需要的头文件
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>

//我们的目的是:移动文件指针到文件头:
int main()
{
    //获取文件的文件描述符
    int fd = open("text.txt", O_RDWR);
    if (fd == -1)
    {
        perror("open");
        return -1;
    }

    //输出当前文件的偏移量
    long long int loc = lseek(fd, 0, SEEK_CUR);
    printf("%lld\n", loc);   //0

    //使用read函数读3个字节的数据
    char buf[3] = {0};
    int rnum = read(fd, buf, sizeof(buf));
    printf("%d\n", rnum);   //3

    //再次查看文件的偏移量(获取当前文件指针的位置)
    long long int loc1 = lseek(fd, 0, SEEK_CUR);
    printf("%lld\n", loc1);   //3

    //移动文件指针到文件头
    long long int loc2 = lseek(fd, 0, SEEK_SET);
    printf("%lld\n", loc2);   //0

    return 0;
}

2.获取文件长度

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
int main()
{
    //获取文件的文件描述符
    int fd = open("hello.txt", O_RDWR);


    //获取文件长度
    long long int loc1 = lseek(fd, 0, SEEK_END);
    printf("%lld\n", loc1);

    return 0;
}

3.拓展文件的长度(注:拓展完成后需要再写一次数据,否则拓展无效)

int main()
{
    //获取文件的文件描述符
    int fd = open("hello.txt", O_RDWR);


    //获取文件长度
    long long int loc1 = lseek(fd, 0, SEEK_END);
    printf("%lld\n", loc1);

    //拓展文件的长度,需要引起IO操作后文件的大小才会改变
    //可以通过 ll 指令查看文件的详细属性
    long long int loc2 = lseek(fd, 100, SEEK_END);
    write(fd," ",1);//写入一个空数据
    //该空数据前的100个字节是文件空洞,这是系统自动帮我们填补的:^@
    printf("%lld\n", loc2);


    return 0;
}

od -tcx filename  查看文件的16进制表示形式
od -tcd filename  查看文件的10进制表示形式

8.传入传出参数

传入参数:

1.指针作为函数参数

2.通常有const关键字修饰

3.指针指向有效区域, 在函数内部做读操作

char *strcpy(cnost char *src, char *dst);

传出参数:

1.指针作为函数参数

2.在函数调用之前,指针指向的空间可以无意义,但必须有效(如不能指向未初始化的空间)

3.在函数内部,做写操作

4.函数调用结束后,充当函数返回值

传入传出参数:

1.指针作为函数参数

2.在函数调用之前,指针指向的空间有实际意义

3.在函数内部,先做读操作,后做写操作

4.函数调用结束后,充当函数返回值

char strtok(char str, const char delim, char ** saveptr) 其中第三个参数就是传入传出参数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2173879.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

快速了解graphql特点

graphql--快速了解graphql特点 1.它的作用2.demo示例2.1依赖引入2.2定义schema2.3定义GrapQL端点2.4运行测试2.5一些坑 今天浏览博客时看到graphQL,之前在招聘网站上第一次接触,以为是图数据查询语言, 简单了解后,发现对graphQL的介绍主要是用作API的查询语言,不仅限于图数据查…

目标检测系列(三)yolov2的全面讲解

YOLOv2&#xff08;论文原名《YOLO9000: Better, Faster, Stronger》&#xff09;作为该系列的第二个版本&#xff0c;对原始YOLO进行了显著的改进&#xff0c;进一步提高了检测速度和准确度。在精度上利用一些列训练技巧&#xff0c;在速度上应用了新的网络模型DarkNet19&…

个性化大语言模型:PPlug——让AI更懂你

在当今数字化转型的时代&#xff0c;大型语言模型&#xff08;LLMs&#xff09;已经成为了不可或缺的工具&#xff0c;它们在自然语言理解、生成和推理方面展现了非凡的能力。然而&#xff0c;这些模型普遍采用的是“一刀切”的方式&#xff0c;即对于相同的输入给予所有用户相…

828华为云征文|部署多功能集成的协作知识库 AFFiNE

828华为云征文&#xff5c;部署多功能集成的协作知识库 AFFiNE 一、Flexus云服务器X实例介绍二、Flexus云服务器X实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置2.4 Docker 环境搭建 三、Flexus云服务器X实例部署 AFFiNE3.1 AFFiNE 介绍3.2 AFFiNE 部署3.3 AFFiNE 使用 四、…

【深度学习】(10)--ResNet残差网络

文章目录 ResNet残差网络1. 传统卷积神经网络的问题1.1 梯度消失和梯度爆炸1.2 退化问题 2. 解决问题2.1 梯度消失与爆炸2.2 退化问题 3. 残差结构结构归纳 4. BN&#xff08;Batch Normalization&#xff09; 总结 ResNet残差网络 ResNet 网络是在 2015年 由微软实验室中的何…

ComfyUI 完全入门:必备插件

前言 大家好&#xff0c;我是每天分享AI应用的月月&#xff01; ComfyUI 是一个基于 Stable Diffusion 的AI绘画创作工具&#xff0c;最近发展势头特别迅猛&#xff0c;但是 ComfyUI 的上手门槛有点高&#xff0c;用户需要对 Stable Diffusion 以及各种数字技术的原理有一定的…

小麦生长状态检测系统源码分享

小麦生长状态检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer…

基于SpringBoot的新冠检测信息管理系统的设计与实现

文未可获取一份本项目的java源码和数据库参考。 国内外在该方向的研究现状及分析 新型冠状病毒肺炎疫情发生以来&#xff0c;中国政府采取积极的防控策略和措施&#xff0c;经过两个多月的不懈努力&#xff0c;有效控制了新发病例的増长&#xff0c;本地传播已经趋于完全控制…

万字面试题大模型面试,最全八股和答案

自ChatGPT开启大模型时代以来&#xff0c;大模型正迎来飞速发展&#xff0c;现在从事大模型开发相关工作可谓是处在时代的风口。那么大模型面试需要哪些技能和技巧呢&#xff0c;本文详细整理了全套的面试问题及答案&#xff0c;希望对大家有所帮助&#xff01; 目录 大模型&a…

如何让 Android 的前端页面像 iOS 一样“优雅”?

作者:方英杰&#xff08;崇之&#xff09; 最近在调研前端页面适配 Android 端异形屏的方案&#xff0c;调研过程中发现了一些比较有意思的点&#xff0c;本文主要是做一个总结。 一、提出问题 首先&#xff0c;我们需要知道 Android 上的前端适配面临着什么问题。 问题其实很…

视频怎么加字幕?视频加字幕的5种方法,小白进阶高手!

视频怎么加字幕&#xff1f;视频加字幕不仅可以添加内容的可读性&#xff0c;也避免很多语言错误&#xff0c;可以更-好地帮助观看者理解创作者的制作理念。对于视频创作的初学者而言&#xff0c;掌握几种简单易用的加字幕方法尤为重要。本文将详细介绍五种视频加字幕的方法&am…

一文速读 LLaMA3.2-Vision 模型的结构

随着 Meta 放出了 LLaMA3.2 系列模型&#xff0c;LLaMA 系列也是正式迎来了官方版本的多模态大模型 LLaMA3.2-Vision [1]。那我们就在本期内容中聊一聊 LLaMA3.2-Vision 模型的结构&#xff0c;希望对大家有所帮助。 相关代码位于 [2] 结论 先说结论&#xff0c;LLaMA3.2 的…

6.Javaweb-过滤器与监听器

Javaweb-过滤器与监听器 文章目录 Javaweb-过滤器与监听器一、过滤器**Filter接口API&#xff1a;** 过滤器生命周期1.创建&#xff08;Creation&#xff09;&#xff1a;2.初始化&#xff08;Initialization&#xff09;&#xff1a;3.执行&#xff08;Execution&#xff09;&…

【设计模式-状态模式】

定义 状态模式&#xff08;State Pattern&#xff09;是一种行为型设计模式&#xff0c;允许对象在其内部状态改变时改变其行为。该模式将状态的变化封装在状态对象中&#xff0c;从而使得对象的行为随着状态的变化而变化。 UML图 角色 Context&#xff08;上下文&#xff0…

使用scroll-behavior属性实现页面平滑滚动的几个问题

在较长的页面中&#xff0c;为了便于用户浏览&#xff0c;开发人员经常会使用锚点链接&#xff0c;锚点链接默认的效果是瞬间跳转&#xff0c;为了让用户体验更好&#xff0c;往往会添加滚动效果。我记得要实现滚动效果&#xff0c;以前一般是结合一段JavaScript代码来实现。 后…

CSS04-Chrome调试工具

Chrome 浏览器提供了一个非常好用的调试工具&#xff0c;可以用来调试我们的 HTML结构和 CSS 样式。

万户OA-ezOFFICE fileUpload.controller 任意文件上传漏洞复现

0x01 产品描述&#xff1a; 万户OA&#xff08;Office Automation&#xff09;是一款企业级协同办公管理软件&#xff0c;旨在为企业提供全面的办公自动化解决方案。万户ezOFFICE存在任意文件上传漏洞。攻击者可以通过该远程下载任意文件到目标服务器&#xff0c;导致攻击者可获…

生信初学者教程(十四):差异结果的火山图

文章目录 介绍加载R包导入数据画图函数火山图输出结果总结介绍 火山图(Volcano Plot)是一种用于展示基因差异表达分析结果的二维散点图。它通过同时展示统计显著性和变化幅度,帮助研究者识别出在不同条件下显著差异表达的基因。火山图的横轴通常表示基因表达变化的倍数对数(…

第 18 章 从猫爷借钱说起——事务简介

18.1 事务的起源 CREATE TABLE account ( id INT NOT NULL AUTO_INCREMENT COMMENT 自增id, name VARCHAR(100) COMMENT 客户名称, balance INT COMMENT 余额, PRIMARY KEY (id) ) EngineInnoDB CHARSETutf8;insert into account (name, balance) values (狗哥, 11), (猫爷, 2…

VS开发C++项目常用基础属性配置

这篇文件简单讨论一下visual studio中项目属性的常用基础配置。 1.输出目录&#xff1a;项目目标文件生成位置。 2.中间目录&#xff1a;项目生成的中间文件所在的位置。 3.目标文件名&#xff1a;项目生成目标文件名称。 4.附加包含目录&#xff1a;三方库等头文件所在的位…