linux学习之详解文件

目录

1.先认识文件

2.c语言中常用文件接口

fopen(打开文件)

3.系统接口操作文件

open

 write

文件的返回值以及打开文件的本质

理解struct_file内核对象

了解文件描述符(fd)分配规则

重定向

dup接口

标准错误流

文件缓冲区

举例

总结:

简单接口的封装


1.先认识文件

首先了解文件之前,我们必须清楚的了解文件的本质:

1.文件=内容+属性,对文件的操作,就是对内容或者属性操作。

2.其实内容属于数据,属性也是属于数据的。存储文件,既要存储文件内容们也要存放文件属性。

3.我们(进程)在访问文件时,首先要打开这个文件,打开前他是存储在磁盘中的,打开后需要把文件加载都内存当中。

4.一个进程可打开多个文件,多个文件都会被加载到内存当中。

而打开文件这些工作也是操作系统干的事,因此操作系统要管理这些文件,就需要先描述在组织:

首先描述出文件的各个属性及内容,再将它组织成一个结构体,即文件的内核数据结构,通过链表的方式链接这些结构体,之后对文件实现增删查改就是操作链表。

因此打开一个文件,操作系统会在内核中形成一个被打开的文件对象来描述该文件。

5.因此一个打开的文件,与一个未被打开的文件两者此时是不一样的,没打开的文件就在磁盘里,打开的文件需要被加载到内存当中并形成对应的文件对象结构表示该文件,并用来管理该文件。

2.c语言中常用文件接口

fopen(打开文件)

 先看第一个fopen参数第一个是文件路径,第二个是文件句柄(文件指针)。

  1 #include<stdio.h>2 3 int main()4 {5   FILE *p=fopen("log.txt","w");//以下的方式在当前路径下打开一个log.txt文件6   if(p==NULL)7   {8     perror("fopen");//打开失败,打印错误信息9     return 1;10   }11   const char*str="hello linux\n";12   int cnt=10;13   while(cnt--)14   {15     fputs(str,p);//像文件里面写入十行字符串                                                                                                           16   }17   fclose(p);//关闭文件18   return 0;19 }

基本了解一下常用接口。

对于文件的打开方式,我们再看一下:

 r:以读的方式打开文件,只能读。

r+:支持读文件,也支持写入,写入在文件末尾写。

对于w,以写方式打开的时候时截断的,即每次会先清空之前的内容,文件未创建会创建。即覆盖式打开文件。

而我们的重定向>文件,就是以w方式打开文件,当我们需要清空文件内容时,就是用重定向方式打开文件。

w+:与w方式一样,不过增加了读。

a:也是文件写入,只不过写入是从文件结尾写入,即追加写入。

我们也可以利用追加重定向的符号进行写入 >>文件。

a+:与a效果一样,增加了读。

3.系统接口操作文件

上述c语言操作文件的接口,在底层其实都是操作系统打开文件的指令被封装成c接口。

因此我们来尝试用系统接口操作文件:

open

首先对于open的返回值,如果打开成功,它会返回一个文件描述符(简称fd),失败会返回-1和错误信息。

第一个参数文件名,第二个参数flags,表示打开文件的标记位。

对于标志位,可能会右很多参数,对于linux下,传参方式是这样的:

这里的一个标志位,是可以传多个标志位的,

如果文件存在:

就是这里的O_RDONLY(以读方式打开),O_WRONLIY(以写的方式打开),O_RDWR(以读写的方式打开).

若果文件不存在:

标志位是下面这些,O_CREAT(创建文件),O_DIRCTORY(),O_NOCTTY().......

 

 实际上这些标志位就是一个宏(整数),这里的每一个宏都是唯一的。

通过宏传参,我们可以实现对于满足宏条件的语句都可以执行,因此可以实现多个一起传入参数,且实现其中的多个功能。

如下一个简单的程序:

 #include<stdio.h>#include<unistd.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 failed");return 1;}                                                                                                                                                   close(fd);return 0;}                                             

因为我们并没有提供文件属性设置的指令,因此这里会是乱码的。

 因此我们可以看到对于函数open第二个是有三个参数,第三个参数就代表设置文件的权限:

这里的权限就是对应的8进制数:

当我们在打开时这样写:

 int fd=open("log.txt",O_WRONLY|O_CREAT,0666);

 但是这里的权限表示的是664,主要原因创建权限时,系统中会有权限掩码帮我们过滤我们设置的权限,可利用umask函数修改掩码。

//再open前加入
umask(0)//权限掩码设置为0

 之后就可以看见都是6660了。

 我们在一般使用的时候,就使用系统的umask。

 write

打开晚间后,那么我们就可以操作文件了,最常用的就是文件写入了

向一个指定的文件描述符写入。

参数也不难看出是 fd文件描述符  buf写的字符串 count个数

char*str="hello,linux!";
write(fd,str,strlen(str));

其次,我们再写入时,如果之前有内容,并不会清空,而是从头开始覆盖式的写入,因此我们再写入之前如果想写入新的数据,需要添加新的标志位-(O_TRUNC),截断文件为0。

int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);

若我们想要在文件结尾处写入,则式将这里的O_TRUNC换成0_QPPEND,追加写入。

int fd=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);

看到这里,我们就会发现如何去将系统库函数封装成c语言的接口。

文件的返回值以及打开文件的本质

    当我们在代码创建了多个文件,将他们的文件描述符一一打印出来的时候,我们会发现他是从3开始,逐渐增加,且是连续的,逐渐增加我们明白,因为文件标识符不可能一样,通过++的方式确保每一个文件的文件描述符是唯一的,但是为什么是从3开始的呢?

首先和管理进程一样,在管理文件是操作系统要为每一个打开的文件创建对应的内核结构struct_fIle)管理该文件,结构体里面存放的就是描述文件的各种属性。

 为了区分好文件结构体与进程的结构体,确定那个进程有哪些文件,文件被打开时,系统创建对应的文件结构体struct_file,同时会在该进程有一个数组里存放文件的地址,并将此时的下标返回给上级,通过此方式,哪些进程的哪些文件就可以被知道,且两者更好能区分。且这个下标就是我们这里的fd,进程标识符。

知道了这些,那么为什么不是从0开始的呢?前三个数组下标呢?

实际上,这个我们之前在学c语言的时候就会知道文件在打开时,会默认打开三个文件流:

标准输入流 stdin    键盘                 0

标准输出流 stdout  显示器             1

标准错误流 stderr   显示器           2

这其实也就是前三个文件描述符。

我们知道c语言里FILE*来表示文件的开的返回值,那么是什么?

FILE*    其实是一个结构体,由c语言标准库提供,作为一个结构体,他其中必定封装有fd(文件描述符),其实对应的返回值与函数c语言库中都进行了封装。

int main()  {printf("stdin->fd",stdin->_fileno);printf("stdout->fd",stdout->_fileno);printf("stderrer->fd",stderr->_fileno);FILE*p=fopen("log.txt","w");printf("FILE->fd",p->_fileno);fclose(p);}         

 了解了以上,那么为什么文件被打开时要默认打开这三个文件流?

默认打开这三个就是为了让用户直接读写数据,直接用函数接口操作文件。

其次在每一个文件架构体重都会有两个函数指针,red,wirte。对于键盘,显示器,这样的书输入输出设备,他们就会有对应的读写方法。

理解struct_file内核对象

我们可以大概猜到struct_file与进程的内个对象类似,里面存放了各种关于文件的信息(属性,内容), 对于结构体的创建,在内存当中被如何创建我们都可以类比进程。对于文件,我们想要读数据时,需要将文件加载到内存当中,其次写数据也是需要我们将数据先加载到内存当中,而文件数据加载到内存当中并不是直接加载到内存当中,而是先加载到文件缓冲区当中,那我们我们读写数据的本质就是在缓冲区里来回拷贝。

了解文件描述符(fd)分配规则

我们已经知道了fd本质就是文件结构体指针数组的下标,那么在实际使用时如何分配的呢?

我们继续了解一下read接口,向指定的文件标识符中读取数据。

既然默认打开三个流文件,我们来试试这

先看看输入流文件,我们知道它对应的文件标识符位0,我们直接通过read读取输入缓冲区的字符:

int main(){char buffer[100];//因为文件在打开时默认打开了三个流,因此我们可以直接做读写操作read(0,buffer,100);//给输入流读取buffer数组大小的字符串,及我们输入的字符串保存在bufferprintf("%s",buffer);return 0;                                                                                                                                           }                                                            

通过打印侧面证明了我们可以访问输入这个文件。不用通过scanf来读字符。

int main(){char buffer[100];read(0,buffer,100);//给输入流读取字符串,并保存在bufferwrite(1,buffer,strlen(buffer));//给输出流写入字符串buffer                                                                                           return 0;                                                  }          

所以fd的分配规则就是默认先打开这三个文件流,0,1,2.

且在分配的时候,从下开始找最小的,没有被使用的位置,再分配给打开的指定的文件。

当然我们也可以打开文件,再关闭这三个默认的文件流,例如close(1),那么我们想要打印出的数据就打印不出了。

重定向

基本了解以上内容之后,我们看看这个代码,是为什么呢?

 int main(){close(1);//关闭输出流int fd=open(FILENAME,O_CREAT| O_WRONLY | O_TRUNC,0666);if(fd<0) {                                                                                          perror("open failed");                                   return 1;                                 }                printf("%d\n",fd);                                   printf("stdout->%d\n",stdout->_fileno);                                                                                                             fflush(stdout);      close(fd);     }

首首先我们关闭了输出流,运行程序之后,没有输出信息,没问题,关闭之后我们又打开了一个文件,该文件的输入输出错误流是打开的,此时我们进行打印之后,就刷新缓冲区,打印的信息,没出来,正常,但是当我们打开文件后,却发现写入显示器的内容到了文件里面,而这就是输出重定向。

那么为什么会是这样呢?

总结的来说就是,刚开始关闭了输入流,这里的结构体文件指针下标1对应没有指向(原本只想显示器),此时又打开了一个文件,(此时操作系统要看当前文件与此时打开的文件的关联,即打开我们.c文件时,下标0,2对应的指针又指向,1被关闭了,此时再次打开一个文件,则该文件地址要放到结构体指针数组,且要从最小的没被占用开始,所以该文件指向了下标1,即我们新打开的这个文件的描述符变成了1),因此打印进文件当中了。

因此,文件结构体数组下标没变,我们改变下标对应的内容,就可以实现重定向。

上述就是输入流:stdout->显示器转变stdout->文件

例如我们这里可以重新让他输入,而且这里我们使用fprintf接口,与printf差不多,只是多了我们需要的接口。

printf的stdout默认是向显示器里输出,利用fprintf我们可以决定向哪个地方输出,

将上述的代码的两个打印变成这样写:

 fprintf(stdout,"%d\n",fd);                                   fprintf(stdout,"stdout->%d\n",stdout->_fileno); 

取消关闭输出流,在运行就可以看到会向显示器打入:

此时新打开的文件标识符位3,默认stdout的是1 。向显示器打印。此时数据1位置指向的是显示器。

再关闭,在运行,此时1位置对应的指向是文件,我们就发现他就是相对应文件里打印数据。

根据上述结论可以验证我们的想法。

打开文件的文件标识符为1,stdout也为1/

但是对于这里我们是通过刷新缓冲区测i可以,去掉刷新缓冲区,文件里也没写入,这与我们的文件缓冲区有关。

通过上述方式,我们很容易实现输出输入重定向。

我们可以从文件读数据,从键盘读数据,我们也可以向显示器打印数据,也可以向文件打印数据。

上层fd不变,指向的内容在改变。

dup接口

我们可以看到关于dup函数的功能,它会改变旧文件的文件描述符,即改变文件指针的指向。且dup会默认关闭旧的文件流(这里就是显示器)。

通过该种方式,我们也可以实现文件描述符的重定向,其中在文件结构体内部还定义了一个引用计数的fcount,有几个文件指向结构体数组的某个位置,对应fcount就为几,当fcount为0时就会释放掉。当然我们也可以自己再重定向之前关闭这个文件流,不关闭系统也会帮我们重新指向。

int main(){int fd=open(FILENAME,O_CREAT| O_WRONLY | O_TRUNC,0666);if(fd<0){perror("open failed");return 1;}//利用dup接口实现重定向,我们这里替换下标为1的输出流文件dup2(fd,1);//把原本文件的fd变成1,此时下标为1的地址指向的是文件fprintf(stdout,"file->%d",fd);fprintf(stdout,"stdout->%d",stdout->_fileno);   return 0;
}        

了解到重定向的本质,我们就可以通过命令行参数,来自己实现输入重定向符号>,追加重定向>>。

其次进程替换与重定向两者之间是没有影响的。程序替换只是地址映射发上了变换,并没有创建新的进程。,因此不影响重定向。

标准错误流

标准输入输出存在,我们很清楚,每次都要先打开这两个流我们也能理解,那么标准错误流,为什么每一次也要打开,错误流是干什么用的。

首先除了重定向输入流,输出流,我们也是可以重定向错误六,例如我们可以将错误流重定向到输出流。

1>log.txt   2>&1,通过连续的重定向我们可以实现,将多个文件的内容指向输出流1。通过该种方式我们就可以看到错误信息,方便我们排查。

文件缓冲区

当一个文件被访问时,无论读写都需要我们将它加载到文件缓冲区当中。即我们读写的数据都先事先拷贝到一个buffer里,再通过write接口将内容写到文件当中,且一个文件的缓冲刷新机制是全缓冲的。

那么什么是缓冲区,如何去理解缓冲区?

对于缓冲区,就是一部份内存,我们将数据拷贝其中,无论是C语言还是c++,我们都里理解为是malloc开辟出来的一块空间。

那为什么要有缓冲区呢?

缓冲区的作用是为了提高使用者的效率,我们不再把数据直接交给对方,而是先直接交给缓冲区,对于用户我们就直接完成了工作,缓冲区之后的工作让操作系统来搞。

因为有缓冲区,我们可以积累一部分派发数据,拥有不同的派发效果。当然积累数据的不同程度,缓冲区有不同的派发策略-----(无缓冲,行缓冲,全缓冲....)。其次也有特殊情况下的策略-------如强制刷新,进程退出(强制刷新)。

用过这种方式也提高了发送的效率。

举例

下来我们分析一下这段代码、

    #include<stdio.h>2 #include<unistd.h>3 #include<string.h>4 int main()5 {6 7   fprintf(stdout,"hello linux1\n");8   fputs("hello linux2\n",stdout);9   printf("hello linux3\n");10   const char *str="hello write\n";11   write(1,str,strlen(str));12 13   fork();//注意在该位置创建的子进程                                    14   return 0;15 }

运行之后的输出,和重定向到log.txt的输出,为什么是这样子的?

对于write接口的数据先写到文件当中,其次是c的接口的写入,且写了两份?

首先第一次直接输出到显示器上的,没问题,创建的子进程的位置也是在最后,与他无关。

输入正常。

第二次重定向到文件之后,再打开里面的内容为什么是这样子的呢?

这里的fork是如何执行的呢?

首先我们的缓冲区刷新是行刷新,因为我们在每一句话后面都带\n了,即在fork之前,缓冲区都是刷新了的。

但是当我们通过输出重定向到log.txt,此时我们依然知道这里的文件结构一直真的数组下标1里面不是指向显示器的,而是指向log.txt的文件当中了,此时的缓冲区刷新由行刷新变成了全缓冲,

全缓冲意味着缓冲区变大,更加意味着,我们写入的简单数据不足以把缓冲区写满,因此fork在执行的时候,此时数据还在缓冲区中。

目前我们这里所说的缓冲区与操作系统无关,而是c语言的封装,因为我们的接口printf,fprintf底层都是write的封装,但是这里取有缓冲区的概念,系统接口本身是没有这的。因此这里的缓冲区就是与c语言本身自己有关。

而我们这里的c/c++提供的缓冲区所保存的数据,属不属于进程的数据呢?实际上该缓冲区的数据属于进程本身的数据。

但是对于文件里面的数据,他与进程是什么关系呢,文件里的数据与进程的此时来说因该是没有啥关系的,即文件里的数据不属于进程的数据,当我们把缓冲区的数据交给到操作系统时,此时的数据就与进程没什么关系,而是属于文件。

因此当进程退出的时候,一般要刷新缓冲区,而刷新缓冲区就是要把这里的数据写到文件当中。

而父子进程,数据共享,当一方写入到文件中时(对于这里来说就是任意一个进程退出,强制刷新缓冲区,像文件里写入),两方都发生写时拷贝,因此我们的数据写入了两份。

但是对于系统调用接口,他与缓冲区没有任何关系,他是直接写入的,因此系统接口只写一次。

而且系统接口先进行写入,之后缓冲区刷新,再写入缓冲区的数据。因此我们看到先写的write的内容,之后是两份拷贝。

总结:

对于系统的文件读写接口,直接接像文件写入的,但是c/c++等语言不仅对读写接口进行了封装,还提供了缓冲区,使得读写数据对缓冲区操作,缓冲区的数据属于进程,但当刷新写入文件当中时,此时的数据不属于进程,而属于操作系统(文件)。

对于c语言,我们的缓冲区就封装在FILE中(由许多指针构成的一块空间)。

简单接口的封装

.h文件

pragma once
#define MAXSIZE 1024
//三种刷新策略
#define Flushline 1
#define Flushall  2
#define Flushnone 3typedef struct _myFILE
{int fileno;//文件标识符char buffer[MAXSIZE];//缓冲区int end;//占用空间int flag;//标志
}myFILE;myFILE* my_fopen(const char *path,const char* mode);
int my_fclose(myFILE*fp);
int my_fputs(const char*s,int num,myFILE* stream);
int my_fflush(myFILE*stream);

.c文件

#include"mystdio.h"
#include<string.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib.h>
#include<errno.h>
#include<unistd.h>
#define permison 0666
//简单的封装io接口myFILE* my_fopen(const char *path,const char* mode)
{int fd=0;//文件标识符int flag=0;//标志位,模式//打开文件模式if(strcmp(mode,"r")==0){//以读的方式打开flag |=O_RDONLY;//只读}else if(strcmp(mode,"w")==0){//以写的方式打开flag|=(O_WRONLY | O_CREAT |O_TRUNC);}else if(strcmp(mode,"a")==0){//以追加的方式flag|=(O_WRONLY|O_CREAT|O_APPEND);}//打开文件if(flag & O_CREAT){//若文件不存在,创建文件fd=open(path,flag,permison);}else{fd=open(path,flag);}if(fd<0){errno=2;return NULL;}//打开成功,返回myFILE*p=(myFILE*)malloc(sizeof(myFILE));if(!p){//申请失败errno=3;return NULL;} p->flag=Flushline;p->fileno=fd;p->end=0;return p;
}
int my_fclose(myFILE*stream)
{my_fflush(stream);//把数据刷新到内核当中//fsync(stream->fileno);return close(stream->fileno);
}
int my_fputs(const char*s,int num,myFILE* stream)
{//把字符写到缓冲区当中memcpy(stream->buffer+stream->end,s,num);//从end位置处写入stream->end+=num;//判断\n ,遇到就要刷新if(stream->flag & Flushline&& stream->end>0 &&(stream->buffer[num-1]=='\n')){my_fflush(stream); //行刷新}return stream->end;}
int my_fflush(myFILE*stream)
{   //若缓冲区为空,就直接关闭if(stream->end==0){close(stream->fileno);}//刷新,写到文件中write(stream->fileno,stream->buffer,stream->end); stream->end=0;return 0; 
}

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

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

相关文章

YITH WooCommerce Product Bundles Premium电商商城产品捆绑销售高级版

点击阅读YITH WooCommerce Product Bundles Premium电商商城产品捆绑销售高级版原文 YITH WooCommerce Product Bundles Premium电商商城产品捆绑销售高级版的作用是在您的商店中创建特别优惠&#xff0c;将产品捆绑在一起提供折扣和特价。 您如何从中受益&#xff1a; 您将…

Swift 中 User Defaults 的读取和写入

文章目录 前言介绍 User Defaults共享 User DefaultsUser Defaults 存储数据类型响应更改监控 User Defaults 更改覆盖User Defaults 设置考虑的替代方案Keychain 用于安全性用于跨平台的 CloudKit 结论 前言 User Defaults 是 Swift 应用程序存储在应用启动之间保持的首选项的…

Nginx实战教程二

一.介绍 本文介绍SPRINGBOOTVUE项目配置API服务器的两种情况 NGINX 配置VUE项目 二.vue项目和后端api接口不在同一台服务器 如果打包好的vue项目应用(dist) 和后端 api 接口没有运行在同一个主机上 此时需要在开发环境下将 API 请求代理到 API 所在服务器。通过配置 vue.confi…

基于ssm实验室课程管理系统源码和论文

idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 环境&#xff1a; jdk8 tomcat8.5 摘 要 随着科学实验规模的不断扩大&#xff0c;实验室课程数量的急剧增加&#xff0c;有关实验室课程的各种信息量也在不断成倍增长。面对庞大的信息量&#xff0c;就需要有…

HBase 使用JDK21

HBase 使用JDK21 启动zookeeper和hadoop 创建软件目录 mkdir -p /opt/soft cd /opt/soft下载软件 wget https://dlcdn.apache.org/hbase/2.5.6/hbase-2.5.6-hadoop3-bin.tar.gz解压 hbase tar -zxvf hbase-2.5.6-hadoop3-bin.tar.gz修改 hbase 目录名称 mv hbase-2.5.6-had…

一则广告,一个故事,这就我选择学习计算机专业的两个原因

还记得当初自己为什么选择计算机&#xff1f; 现在回想起来&#xff0c;当初驱使自己选择学习计算机专业的原因&#xff0c;一共有两个&#xff1a; 一、一则长城电脑的广告。 上个世纪80年代&#xff0c;我还在读小学&#xff0c;当时在中央电视台上经常播放着的长城电脑的一则…

Abaqus基础教程--胶合失效仿真

胶合是电子行业中常见的连接方式&#xff0c;abaqus中常用cohesive单元或者cohesive接触两种方法进行胶合失效仿真&#xff0c;这两种方式操作方法有所差别&#xff0c;但结果一般大同小异。 本例模型比较简单&#xff0c;建模过程从略&#xff0c;使用静态分析&#xff0c;使…

【GAMES101】三维变换

games101的第四节课讲了三维变换和观察变换&#xff0c;我们这里先记录一下三维变换的知识&#xff0c;后面再讲观察变换 齐次坐标下的三维变换 类似于解决之前二维变换平移的问题&#xff0c;三维变换下用齐次坐标通过增加一个维度来表示&#xff0c;第四个维度为1表示这是个…

无敌是多么的寂寞!一本书讲透Java多线程!吊打多线程从原理到实践!

摘要 互联网的每一个角落&#xff0c;无论是大型电商平台的秒杀活动&#xff0c;社交平台的实时消息推送&#xff0c;还是在线视频平台的流量洪峰&#xff0c;背后都离不开多线程技术的支持。在数字化转型的过程中&#xff0c;高并发、高性能是衡量系统性能的核心指标&#xff…

vue2+electron桌面端一体机应用

vue2+electron项目 前言:公司有一个项目需要用Vue转成exe,首先我使用vue-cli脚手架搭建vue2项目,然后安装electron 安装electron 这一步骤可以省略,安装electron-builder时会自动安装electron npm i electron 安装electron-builder vue add electron-builder 项目中多出…

(NeRF学习)3D Gaussian Splatting Instant-NGP

学习参考&#xff1a; 3D Gaussian Splatting入门指南【五分钟学会渲染自己的NeRF模型&#xff0c;有手就行&#xff01;】 三维重建instant-ngp环境部署与colmap、ffmpeg的脚本参数使用 一、3D Gaussian Splatting &#xff08;一&#xff09;3D Gaussian Splatting环境配置…

JVM 类的加载器的基本特征和作用

Java全能学习面试指南&#xff1a;https://javaxiaobear.cn 1、作用 类加载器是 JVM 执行类加载机制的前提 ClassLoader的作用&#xff1a; ClassLoader是Java的核心组件&#xff0c;所有的Class都是由ClassLoader进行加载的&#xff0c;ClassLoader负责通过各种方式将Class信…

【跨境营商】创新科技助力数码转型 增强大湾区企业核心竞争力

粤港澳大湾区作为国家的重点发展区域&#xff0c;坐拥丰富的资源及商机&#xff0c;企业积极推行数码化&#xff0c;务求在大湾区抢占先机。香港电讯商业客户业务董事总经理吴家隆表示&#xff0c;近年企业锐意加快数码化步伐&#xff0c;香港电讯以创新科技融入的数码方案&…

UE学习C++(1)创建actor

创建新C类 在 虚幻编辑器 中&#xff0c;点击 文件&#xff08;File&#xff09; 下拉菜单&#xff0c;然后选择 新建C类...&#xff08;New C Class...&#xff09; 命令&#xff1a; 此时将显示 选择父类&#xff08;Choose Parent Class&#xff09; 菜单。可以选择要扩展的…

Linux Component概述和高通V4l2驱动模型

1 Linux为什么要引入Component框架&#xff1f; 为了让subsystem按照一定顺序初始化设备才提出来的。 subsystem中由很多设备模块&#xff0c;内核加载这些模块的时间不确定。子系统内有些模块是需要依赖其它模块先初始化才能进行自己初始化工作(例如v4l2 subdev和v4l2 video …

电商类直播介绍

电商直播是一种购物方式&#xff0c;通过直播技术向消费者展示商品&#xff0c;并引导其进行购买。在法律上&#xff0c;电商直播属于商业广告活动&#xff0c;主播需要根据具体行为承担“广告代言人"“广告发布者"或“广告主"的责任。 电商直播的特点在于其更…

月薪6W!美团、网易等大厂急招HarmonyOS开发!

近期&#xff0c;多家互联网公司发布了多个和鸿蒙系统有关的岗位。 不仅如此&#xff0c;还与Windows等主流老牌操作系统并列&#xff0c;并且排在首位介绍。 此外&#xff0c;今日头条招聘Android开发工程师也提及岗位需要“负责今日头条 Android、鸿蒙系统等新技术方向调研…

Http协议与Tomcat

HTTP协议 HTTP协议&#xff08;HyperText Transfer Protocol&#xff09;即超文本传输协议 &#xff0c;是TCP/IC网络体系结构应用层的一个客户端-服务端协议&#xff0c;是所有客户端&#xff0c;服务端数据传输的基石&#xff08;数据传输规则&#xff09; 特点 ⭐基于TCP协…

class059 建图、链式前向星、拓扑排序【算法】

class059 建图、链式前向星、拓扑排序【算法】 code1 建图 package class059;import java.util.ArrayList; import java.util.Arrays;public class Code01_CreateGraph {// 点的最大数量public static int MAXN 11;// 边的最大数量// 只有链式前向星方式建图需要这个数量// 注…

基于AT89C51单片机的秒表设计

1&#xff0e;设计任务 利用单片机AT89C51设计秒表&#xff0c;设计计时长度为9:59:59&#xff0c;超过该长度&#xff0c;报警。创新&#xff1a;设置重启&#xff1b;暂停&#xff1b;清零等按钮。最后10s时播放音乐提示。 本设计是采用AT89C51单片机为中心&#xff0c;利用其…