Linux系统--基础IO

news2024/11/17 21:22:10


文章目录

  • 文件的概念
  • C语言 文件 IO 相关操作
  • 系统调用接口
  • 文件描述符

一、文件的概念

1.在系统角度上来说

文件=内容+属性

如果在磁盘上建立一个为0KB的文件,磁盘上也会存储文件的属性。(因为文件的属性也是数据).

文件的操作

  • 1.一种是对于文件内容做操作。
  • 2.另外一种是对于文件的属性,比如说更改文件的相关权限等。

注意:

  • 对于文件内容做操作也可能会影响文件属性改变,比如说文件的大小发生了变化。
  • 由于文件在磁盘(硬件)中存放,我们访问文件,先写代码->编译->链接->生成可执行文件->运行。

注意:

  • 访问文件的本质是进程在访问,进程访问文件是需要通过接口(语言层面的接口,C语言、C++)访问的。
  • 如果想要向硬件写入,那么只能通过操作系统。如果普通用户也想向硬件写入,那么就必须让操作系统提供相应的系统调用接口(文件类的系统调用接口)。由于文件类的系统调用接口比较复杂,所以一写语言对于这些系统调用接口进行了封装,这就导致了不同语言有不同的语言级别的文件访问接口(都不一样),但是都封装的是系统接口,底层原理相同。

为什么要学习OS层面的文件接口?

  • 1.由于选择的操作系统只有一个,这样的接口,在Linux上只有一套,其他OS也是一样的。
  • 2.这样的代码具有跨平台性。使用C++的平台都可以使用C++的文件接口,使用Python的平台都可以使用Python的文件接口。
  • 如果语言不提供给文件的系统接口的封装,所有访问文件的操作都必须直接使用操作系统的接口。(Windows的系统接口和Linux的系统接口种类,参数等都是不一样的)。

注意:

        使用语言的用户,也需要访问文件,但是一旦使用系统接口编写文件代码,这份代码只能在该平台中使用,无法在其他平台上运行,不具有跨平台性。而C语言和C++语言将所有平台中的代码都实现出来并封装好。然后采用条件编译的方式,在编译的时候实现动态编译。

2.stdin & stdout & stderr

C/C++默认会打开三个输入输出流,分别是stdin, stdout, stderr
仔细观察发现,这三个流的类型都是FILE*, fopen返回值类型,文件指针

 由于显示器也是硬件,那么printf向显示器打印,也是一种写入,和磁盘写入到文件没有本质区别!

3.Linux下一切皆文件

在Linux下,硬件设备可以被看成文件,可以进行scanf、fgets、printf、cin、cout。在C/C++程序在编译的时候,将代码加载到你的程序中,这就是默认情况下会打开stdin、stdout、stderr。

  • stdin标准输入->默认为键盘
  • stdout标准输出->默认为显示器
  • stderr标准错误->默认为显示器

对于文件来说,读和写是文件操作的核心。

对于显示器来说,printf/cout本质上也是一种写入(write),对于键盘来说,scanf/cin本质上也是一种读入(read).将输入内容给显示器一份也给程序一份。站在内存角度,程序必须加载到内存,键盘将我们输入的数据交给内存,系统将内存中的数据刷新到显示器或者写入到硬盘中,也就是对应着input和output(也就是I/O的动作)。如果一个普通文件,我们使用fopen/fread去读取它,他就被读取到我们程序(进程)的内部(内存),再使用fwrite将数据写入到文件中,从普通程序读取到进程内部(内存)就是input,从内存中写入文件中就是output。

文件的定义:站在系统角度上来说,能够被input读取,能够被output写出的设备就是文件。

  • 狭义上的文件:普通的磁盘文件(.txt .doc文件等等)
  • 广义上的文件:显示器,键盘,网卡,声卡,显卡,磁盘,几乎所有的外设都可以称之为文件。(这些设备都具有上面可以被读或者被写的特点)。

二、C语言文件IO相关操作

1.文件类型

  • 文本文件:把数据的终端形式的二进制数据输出到磁盘上存放,也就是说存放的是数据的终端形式。
  • 二进制文件:把内存中的数据按其在内存中的存储形式原样输出到磁盘上存放,也就是说存放的是数据的原形式。

2.相对路径和绝对路径的理解

  • 绝对路径:是从目录树的树根"/"目录开始往下直至到达文件所经过的所有节点目录。下级目录接在上级目录后面用“/"隔开。
  • 相对路径:相对路径是指目标目录相对于当前目录的位置。
  • 注意:绝对路径都是从“/"开始的,所以第一个字符一定是“/"。

3.C语言中文件操作函数

文件的打开

fopen():打开文件

FILE *fopen( const char *filename, const char *mode );

 文件的关闭

fclose():关闭文件

int fclose( FILE *stream );

文件的读写

fgetc():读取一个字符

fputc():写入一个字符

fgets():读取一个字符串

fputs():写入一个字符串

fprintf():写入格式化数据

fscanf():格式化读取数据

fread():读取数据

fwrite():写入数据

int fgetc( FILE *stream );
int fputc( int ch, FILE *stream );
char *fgets( char *str, int count, FILE *stream );
int fputs( const char *str, FILE *stream );
int fprintf( FILE *stream, const char *format, ... );
int fscanf( FILE *stream, const char *format, ... );
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
int fwrite( const void *buffer, size_t size, size_t count, FILE *stream );

 文件状态检查

feof():文件是否结束

ferror():文件读/写是否出错

clearerr():清除文件错误标志

ftell():文件指针的当前位置

int feof ( FILE * stream );
int ferror ( FILE * stream );
void clearerr ( FILE * stream );
long int ftell ( FILE * stream );

 文件指针定位

rewind():把文件指针移到开始处

fseek():重定位文件指针                     

void rewind ( FILE * stream );
int fseek ( FILE * stream, long int offset, int origin );

 注意:r+具有读写属性,从文件头开始写,保留原文件中没有被覆盖的内容,w+也具有读写属性,如果原文件存在,会被清空从头开始写。

perror打印错误信息

#include <stdio.h>
#include <stdlib.h>

int main()
{
    //当前目录中不存在这个文件
    FILE* fp=fopen("log.txt","r");
    //如果打开失败,就以文本形式返回
    if(fp==NULL)
    {
        perror("fopen");
        exit(1);
    }
    return 0;
}

在Linux下,如果当前是以写的方式的话,如果写入的文件不存在,会在当前路径下直接创建。

4.通过进程来创建一个文件

#include <stdio.h>
#include <stdlib.h>

int main()
{
    FILE* fp=fopen("log.txt","w");
    if(fp==NULL)
    {
        perror("fopen");
        exit(1);
    }
    fclose(fp);
    while(1) sleep(1);
    return 0;
}

 从上图我们可以发现ext指向的路径就是我们当前进程的工作路径。

cwd:进程的内部属性,就是我们这个进程所指向的工作目录。将cwd所指向的路径,和我们上面传入的文件拼接起来,形成完整的路径名称。当一个进程运行起来,每个进程都会记录当前所处的工作路径,当你打开一个文件的时候,创建的文件就是我们当前路径下,也就是我们进程所处的路径下。由于我们进程内部会直接用这个进程的cwd也就是当前的工作路径,然后将文件名test拼接起来形成我们的exe找到可执行文件。

注意:进程具有确定性,一般我们程序将程序部署到系统中,路径一般不发生改变,比如说你安装了一个程序到D盘中,那么路径就在D盘下。

5.文件相关接口演示:

相关代码:

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

int main()
{
    FILE* fp=fopen("log.txt","w");
    //如果打开失败了,就将打开失败的原因以文本的形式返回
    if(fp==NULL)
    {
        perror("fopen");
        return 1;
    }

    //进行文件的相关操作
    const char* s1="hello fwrite\n";

    //二进制的方式写入
    fwrite(s1,strlen(s1),1,fp);
    
    const char* s2="hello fprintf\n";

    //往特定的文件流中,写入特定的字符串
    fprintf(fp,"%s",s2);

    const char* s3="hello fputs\n";
    fputs(s3,fp);

    //关闭文件
    fclose(fp);
    return 0;
}

 

7.文件不同模式

1.w模式

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

int main()
{
    FILE * fp=fopen("log.txt","w");

    if(fp==NULL)
    {
        perror("fopen");
        return 1;
    }

    const char* s1="hello world\n";

    fwrite(s1,strlen(s1),1,fp);

    fclose(fp);
    return 0;
}

 由于是在w模式下,先将文件打开的时候,将文件中的内容进行清空处理,然后才写入内容!

这里我们通过echo指令对log.txt进行写入内容,首先将文件中的全部内容被清空。这与先清空再写入的原理相同!

2.a模式追加

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

int main()
{
    FILE *fp=fopen("log.txt","a");

    if(fp==NULL)
    {
        perror("fopen");
        return 1;
    }

    const char*s1="hello world\n";
    fwrite(s1,strlen(s1),1,fp);

    fclose(fp);
    return 0;
}

上图产生的原因是因为打开了文件,而不是将文件的内容进行清空的操作而是将文件后面的内容进行追加处理。

3.fgets进行按行读取操作

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

int main()
{
    FILE* fp=fopen("log.txt","r");

    if(fp==NULL)
    {
        perror("fopen");
        return 1;
    }

    char line[64];

    while(fgets(line,sizeof(line),fp)!=NULL)
    {
        //将读到行的内容显示出来,同时也可以通过printf的方式打印出来
        printf("%s\n",line);

        //也可以通过标准输出的方式打印出来
        fprintf(stdout,"%s",line);
    }

    fclose(fp);
    return 0;
}


4.利用cat命令来读取文件

cat命令用来打印文件中的内容。

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

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        printf("argc error!\n");
        return 1;
    }

    //argv[1]就是我们传入的参数
    FILE* fp=fopen(argv[1],"r");

    //如果打开失败的话,则将失败的原因以文本的方式进行返回
    if(fp==NULL)
    {
        perror("fopen");
        return 2;
    }

    //按行读取
    char line[64];
    while(fgets(line,sizeof(line),fp)!=NULL)
    {
        //将读取的行显示出来
        printf("%s",line);

        //往显示器上写,stdout就是标准输出
        fprintf(stdout,"%s",line);
    }

    //关闭文件
    fclose(fp);
    return 0;
}

这里我们通过给argv[1]中传入文件名,我们可以发现我们可以打印其文件中的内容。

三、系统调用接口

操作文件,除了上述C接口(当然,C++也有接口,其他语言也有),我们还可以采用系统接口来进行文件访问。

1.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: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。
    • 参数:
      • O_RDONLY: 只读打开
      • O_WRONLY: 只写打开
      • O_RDWR : 读,写打开
      • 这三个常量,必须指定一个且只能指定一个
      • O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
      • O_APPEND: 追加写
  • 返回值:
    • 成功:新打开的文件描述符
    • 失败:-1
注意:open 函数具体使用哪个,和具体应用场景相关,如目标文件不存在,需要open创建,则第三个参数表示创建文件的默认权限(mode),否则,使用两个参数的open。

如何给函数传递标志位?

在宏定义中利用大写字母和_来表示一个宏,上面的flags只能传递一种状态,但是如果在C语言中传入大量的选项呢,这时候我们可以利用标记位来表示该状态是否的意思,例如一个int是32字节,那么一个标记位就是一个比特位,那么就可以表示32个状态了。这种表示方式就是一种数据结构--位图

测试代码:

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

#define ONE 0x1
#define TWO 0x2
#define THREE 0x3

void show(int flags)
{
    if(flags&ONE) printf("hello one\n");
    if(flags&TWO) printf("hello two\n");
    if(flags&THREE) printf("hello three\n");
}

int main()
{
    show(ONE);
    printf("--------------------------------\n");
    show(TWO);
    printf("--------------------------------\n");
    show(ONE|TWO);
    printf("--------------------------------\n");
    show(ONE|TWO|THREE);
    return 0;
}

1.O_CREAT

若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限

测试代码:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    int fd=open("log.txt",O_CREAT);
    if(fd<0)
    {
        perror("open");
        return 1;
    }

    printf("open success fd:%d\n",fd);
    return 0;
}

2.O_WRONLY

只写打开
测试代码:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    int fd=open("log.txt",O_WRONLY);
    if(fd<0)
    {
        perror("open");
        return 1;
    }

    printf("open success fd:%d\n",fd);
    return 0;
}

这里我们发现,使用O_WRONLY不会自动创建文件,我们需要添加O_CREAT选项来解决。

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    int fd=open("log.txt",O_WRONLY|O_CREAT);
    if(fd<0)
    {
        perror("open");
        return 1;
    }

    printf("open success fd:%d\n",fd);
    return 0;
}

传入标记位

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    int fd=open("log.txt",O_WRONLY|O_CREAT,0666);
    if(fd<0)
    {
        perror("open");
        return 1;
    }

    printf("open success fd:%d\n",fd);
    return 0;
}

这里我们通过给文件设置相关的权限为0666(即-rw-rw-rw-),而实际上不是,是由于系统中有创建时默认的权限umask权限(默认是0002)

如果想要得到我们想要设置的权限,那么我们只需要将此时umask设置为0即可解决问题。

2.close

关闭文件

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    //设置文件掩码为0
    umask(0);
    
    int fd=open("log.txt",O_WRONLY|O_CREAT);
    if(fd<0)
    {
        perror("open");
        return 1;
    }

    printf("open success fd:%d\n",fd);

    //关闭文件
    close(fd);
    return 0;
}

3.write

向文件中写入

测试代码:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    umask(0);
    int fd=open("log.txt",O_WRONLY|O_CREAT,0666);
    if(fd<0)
    {
        perror("open");
        return 1;
    }

    const char* s="hello write\n";
    write(fd,s,strlen(s));
    printf("open success fd:%d\n",fd);
    close(fd);
    return 0;
}

这里我们只将上述代码写入字符串s改变为“HeLLoWRITE”,那么会写入到文件中是什么内容呢?

这里我们发现此时在log.txt中是进行覆盖式的写入,而不是先清空再进行写入的方式!

1.O_TRUNC

先清空文件再向文件中写入

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    umask(0);
    int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
    if(fd<0)
    {
        perror("open");
        return 1;
    }

    const char* s="hello\n";
    write(fd,s,strlen(s));
    printf("open success fd:%d\n",fd);
    close(fd);
    return 0;
}

这里我们发现此时文件首先进行了清空处理然后重新写入了hello。

2.O_APPEND

在文件后面进行追加方式。

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    umask(0);
    int fd=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);
    if(fd<0)
    {
        perror("open");
        return 1;
    }

    const char* s="hello write\n";
    write(fd,s,strlen(s));
    printf("open success fd:%d\n",fd);
    close(fd);
    return 0;
}

4.read

对文件进行读取处理

 1.O_RDONLY

以只读的方式打开

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    umask(0);
    int fd=open("log.txt",O_RDONLY,0666);
    if(fd<0)
    {
        perror("open");
        return 1;
    }

    char buffer[64];
    memset(buffer,'\0',sizeof(buffer));
    read(fd,buffer,sizeof(buffer));
    printf("%s\n",buffer);
    printf("open success fd:%d\n",fd);
    close(fd);
    return 0;
}

四、文件描述符

为什么打开一个文件,默认的文件描述符为3呢?

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    umask(0);
    int fd=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);
    if(fd<0)
    {
        perror("open");
        return 1;
    }

    printf("open success fd:%d\n",fd);
    close(fd);
    return 0;
}

这里我们发现此时打开的文件该文件的文件描述符为3。那么此时我们打开多个文件呢?

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    umask(0);
    int fd1=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);
    printf("open success fd1:%d\n",fd1);
    int fd2=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);
    printf("open success fd2:%d\n",fd2);
    int fd3 =open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);
    printf("open success fd3:%d\n",fd3);
    int fd4=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);
    printf("open success fd4:%d\n",fd4);

    close(fd1);
    close(fd2);
    close(fd3);
    close(fd4);
    return 0;
}

这里我们发现打开多个文件此时文件描述符是从3开始递增的,为什么不是从0开始呢?

这是因为在C语言中,系统会默认打开三个默认的文件,分别是stdin,stdout,stderr,它们都是FILE*类型的,每一个文件都对应了一个文件描述符。0-标准输入,1-标准输出,2-标准错误。

测试代码:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    //向显示屏中打印
    fprintf(stdout,"hello fprintf\n");

    const char*s="hello write\n";
    write(1,s,strlen(s));//向显示屏中写入

    //从标准输入中读取
    int a=10;
    fscanf(stdout,"%d",&a);
    printf("%d\n",a);

    //从0中读取
    char buff[16];
    size_t ss=read(0,buff,sizeof(buff));

    if(ss>0)
    {
        buff[ss]='\0';
        printf("%s\n",buff);
    }
    return 0;
}

1.FILE的认识

这里的FILE是由C语言的标准库提供的!,是一个结构体,所以其内部封装了很多属性,由于是C语言的库函数,所以内部一定要进行系统调用,在系统角度只认识fd,由于是FILE结构体,所以其内部一定封装了fd!

验证是否存在fd代码:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    printf("stdin:%d\n",stdin->_fileno);
    printf("stdout:%d\n",stdout->_fileno);
    printf("stderr:%d\n",stderr->_fileno);
    return 0;
}

上述代码说明了:C语言将我们系统中的0,1,2文件封装进了stdin,stdout,stderr中,而stdin,stdout,stderr都是结构体指针,其内部的_fileno属性就是我们对应的0,1,2!

2.fd的认识

首先进程需要访问文件,那么就必须先将文件打开。一个进程可以打开多个文件,文件打开的目的就是被访问,文件想要被访问,前提是加载到内存当中才能够被访问!如果多个进程打开自己的文件,那么系统可能会存在大量被打开的文件!那么OS将这些被打开的文件进行先描述再组织的管理方式,首先OS内部需要管理每一个被打开的文件,首先需要构建出内核的结构体对象struct file,这是一种内核数据结构,里面包含了文件的所有内容和属性(包括文件的打开的时间,修改时间,所属组,所有者等等)

struct file结构体定义在/linux/include/linux/fs.h(Linux 2.6.11内核)中,其原型是:
struct file {
        /*
         * fu_list becomes invalid after file_free is called and queued via
         * fu_rcuhead for RCU freeing
         */
        union {
                struct list_head        fu_list;
                struct rcu_head         fu_rcuhead;
        } f_u;
        struct path             f_path;
#define f_dentry        f_path.dentry
#define f_vfsmnt        f_path.mnt
        const struct file_operations    *f_op;
        atomic_t                f_count;
        unsigned int            f_flags;
       mode_t                  f_mode;
        loff_t                  f_pos;
        struct fown_struct      f_owner;
        unsigned int            f_uid, f_gid;
        struct file_ra_state    f_ra;

        unsigned long           f_version;
#ifdef CONFIG_SECURITY
        void                    *f_security;
#endif
        /* needed for tty driver, and maybe others */
        void                    *private_data;

#ifdef CONFIG_EPOLL
        /* Used by fs/eventpoll.c to link all the hooks to this file */
        struct list_head        f_ep_links;
        spinlock_t              f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
        struct address_space    *f_mapping;

};

创建出struct file对象来充当一个被打开的文件,如果被打开的文件很多,那么此时需要OS用双链表将这些对象组织起来!所以一个进程的PCB只要找到上面那个打开的文件的链表头部就可以找到全部的文件!

进程与文件的对应关系是多对一的,在内核当中为了维护进程和文件的关系,会有一个数组(struct_file *array[32])(指针数组,数组中的类型都是struct file*),第一个数组元素指向第一个文件,依次类推,系统就可以通过数组进行哈希索引来找到对应的文件。

综上所述:fd在内核中,本质上来说是数组下标!

在内存当中的文件,OS通过双链表来添加我们新打开的文件,并且将其地址放入struct_file*array数组中,然后OS可以通过fd可以查询到对应文件的存储地址,进而可以读取到打开的文件!

(文件对象)struct file里面包含了文件中的所有内容,(文件描述符表)struct_file*array也可以成为文件映射表。本质上来说文件描述符表就是数组下标!

3.文件的分类

内存文件:被进程打开的文件(open属于系统调用),这里的文件称为内存文件。

磁盘文件:没有被进程打开,那么此时该文件保留在磁盘中,磁盘上保存的文件(内容和属性).

一旦操作系统打开了大量文件的情况,操作系统此时就需要将这些文件管理起来,先构建出struct file对象,里面包含了文件的所有内容和属性(包括文件的打开时间,修改时间,所属组,所有者等信息)。文件存在于磁盘当中,本身就有属性,从磁盘中被加载到内存中,相关属性被填充到结构体中。

文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了fifile结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*fifiles, 指向一张表fifiles_struct,该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件 。

 

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

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

相关文章

Solidworks PDM二次开发---文件相关操作

本文介绍如何把文件增加到库&#xff0c;并检入。 上一篇文章简单的讲解了文件夹的创建等操作&#xff0c;这一次来讲文件相关操作&#xff0c;相对来说比较重要。界面 漂亮的界面&#xff0c;不接受反驳&#xff01; 代码 private void btnFile_Click(object sender, Even…

MASM32编程状态栏显示字符动画,按钮跑马灯

一、需求分析 由于sysInfo扫描的内容比较多&#xff0c;打算为它增加一点动画效果&#xff0c;提醒用户程序正在运行&#xff0c;耐心等待。 二、构建测试窗口 测试窗口上放置有一个按钮&#xff0c;按钮上的初始文字是“开始扫描”&#xff1b;并使用状态栏&#xff0c;状态…

喜报 | 再度中标南网项目!AR 开启电力远程运维新智慧

近日&#xff0c;中国南方电网官网发布《2023年南方电网数字平台科技 (广东)有限公司物资品控远程协助软件采购项目中标公告》&#xff0c;ALVA Systems 凭借 ALVA Rainbow 创新应用竞得此标。 随着相关技术的逐步成熟&#xff0c;基础问题远程化解决已经在工业领域广泛应用。 …

Python中的装饰器

迷途小书童的 Note 读完需要 5分钟 速读仅需 2 分钟 装饰器是一个非常有用而又常被误解的功能&#xff0c;可以让我们在不修改函数或类的源代码情况下给它们提供扩展功能。本文将通过具体示例带你深入理解 Python 装饰器的用法。 1 装饰器基础 装饰器本质上是一个函数&#xff…

SpringMVC的简介及工作流程

一.简介 Spring MVC是一个基于Java的开发框架&#xff0c;用于构建灵活且功能强大的Web应用程序。它是Spring Framework的一部分&#xff0c;提供了一种模型-视图-控制器&#xff08;Model-View-Controller&#xff0c;MVC&#xff09;的设计模式&#xff0c;用于组织和管理Web…

职责链设计模式

职责链模式又叫命令链、CoR、Chain of Command、Chain of Responsibility。 该模式允许你将请求沿着处理者链进行发送&#xff0c;使多个对象都可以处理请求&#xff0c;每个对象有权决定处理或传递给下个节点。 客户端&#xff1a;用来定义职责链条。 处理者&#xff1a;声明…

基于Vgg-Unet模型自动驾驶场景检测

1.VGG VGG全称是Visual Geometry Group属于牛津大学科学工程系&#xff0c;其发布了一些列以VGG开头的卷积网络模型&#xff0c;可以应用在人脸识别、图像分类等方面,VGG的输入被设置为大小为224x244的RGB图像。为训练集图像上的所有图像计算平均RGB值&#xff0c;然后将该图像…

vscode上搭建go开发环境

前言 Go语言介绍&#xff1a; Go语言适合用于开发各种类型的应用程序&#xff0c;包括网络应用、分布式系统、云计算、大数据处理等。由于Go语言具有高效的并发处理能力和内置的网络库&#xff0c;它特别适合构建高并发、高性能的服务器端应用。以下是一些常见的Go语言应用开发…

静态路由配置出错记录

根据实验手册&#xff0c;配置静态路由&#xff0c;但是怎么也排除不了错误。 最后发现&#xff0c;是自己的默认网关配置错误了。但是使用模拟器抓包看到的&#xff0c;也没有提示网关信息啊。

docker desktop如何一键进入容器内部

对着对应的容器 点击 view files

电压互感器倍频感应耐压试验注意事项

注意事项 被试 PT 在三倍频耐压时呈容性&#xff0c; 对于 110kV、 220kV 互感器进行感应耐压试验时&#xff0c;应在开口 a D x D 端子间励磁&#xff0c; 可在 PT 二次绕组 ax 上接补偿电感&#xff0c; 对于 35kV 电压互感器励磁电压一般加至二次 a—x 间&#xff1b;三倍频…

测开之 Python 自动化全栈工程师 + 性能专项

功能测试基础 接口测试基础 接口的通信原理与本质 cookie、session、token 详解 接口测试的意义与测试方法 接口测试用例的设计 app 测试 app 流程测试 app 兼容性测试 app 稳定性测试 app 性能专项测试 app 抓包 UI 功能测试基础 常见功能测试方法&#xff1a;等价类&…

JVM | 垃圾回收器(GC)- Java内存管理的守护者

引言 在编程世界中&#xff0c;有效的内存管理是至关重要的。这不仅确保了应用程序的稳定运行&#xff0c;还可以大大提高性能和响应速度。作为世界上最受欢迎的编程语言之一&#xff0c;通过Java虚拟机内部的垃圾回收器组件来自动管理内存&#xff0c;是成为之一的其中一项必…

极米RS Pro 3投影参数是多少?极米投影仪RS Pro 3好用吗?

近年来&#xff0c;随着投影技术的快速发展&#xff0c;越来越多的用户开始选择投影产品来打造家庭影院&#xff0c;为生活带来新的观影体验。但要想打造一个家庭影院&#xff0c;选到一台合适的投影仪却并不是一件容易的事&#xff0c;因为家庭影院对画面的亮度、色彩和观影舒…

(18)线程的实例认识:线程的控制,暂停,继续,停止,线程相互控制,协作

一、老方式 1、这是一个老的实现方式&#xff0c;基本不推荐&#xff0c;背后控制的原理需要了解。 界面&#xff1a;三个button一个textbox 代码&#xff1a; private volatile bool isPause false;//fprivate void BtnStart_Click(object…

力扣|两数相加

先放题目&#xff1a; 给你两个非空的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c…

敏捷开发方法:快速响应需求变化的开发流程

在快速变化的技术和市场环境下&#xff0c;传统的软件开发方法可能显得笨重和不灵活。敏捷开发方法应运而生&#xff0c;以其快速响应需求变化、持续交付和团队协作的特点&#xff0c;成为现代软件开发的重要方法之一。本文将深入探讨敏捷开发方法的概念、原则、流程以及在实际…

《王道24数据结构》课后应用题——第三章 栈和队列

第三章 【3.1】 03、 假设以I和O分别表示入栈和出操作。栈的初态和终态均为空&#xff0c;入栈和出栈的操作序列可表示为仅由I和O组成的序列&#xff0c;可以操作的序列称为合法序列&#xff0c;否则称为非法序列。 如IOIIOIOO 和IIIOOIOO是合法的&#xff0c;而IOOIOIIO和II…

maven基础学习

什么是maven 构建 依赖 maven核心概念坐标 在黑窗口使用maven命令生成maven工程 pom.xml 想导入哪个jar包把它的坐标放到dependency里就可以 maven核心概念POM maven核心概念约定的目录结构 执行maven的构建命令 清理操作&#xff0c;clean 编译操作 compile 测试操作 test 打包…

ElasticSearch进阶

一、 search检索文档 ES支持两种基本方式检索&#xff1b; 通过REST request uri 发送搜索参数 &#xff08;uri 检索参数&#xff09;&#xff1b;通过REST request body 来发送它们&#xff08;uri请求体&#xff09;&#xff1b; 1、信息检索 API&#xff1a; https://w…