文件管理—linux(基础IO)

目录

​编辑

一、C语言文件接口(库函数)

hello.c写文件

hello.c读文件 

输出信息到显示器

 stdin & stdout & stderr

二、系统文件I/O(系统调用)

hello.c 写文件:

hello.c读文件

接口介绍

open

open函数返回值

三、文件描述符fd

文件描述符的分配规则

使用 dup2 系统调用 (重定向)

四、FILE

户级缓冲区

五、理解文件系统

文件=文件内容+文件属性

 inode(类似于进程pid)

六、软链接和硬链接 

硬链接 

 软链接

七、linux中文件系统内核图(简略):​编辑

八、动态库和静态库

  生成静态库(shell指令) 

库搜索路径

生成动态库

使用动态库

运行动态库

库文件名称和引入库的名称


 

一、C语言文件接口(库函数)

写接口功能

读接口

printf()默认输出到显示器scanf()默认从键盘读
fprintf()写入格式类上,输出到指定文件中,指定需要通过C语言提供的流(一种对文件进行描述的数据结构指针 FILE *fscanf()写入格式类上,写入到指定文件中,通过流
fread()指定地址,字节数,数目,写入到指定文件中,通过流指定文件,fseek可以设置流指向文件中的位置,来改变写入文件的起始地址fwrite()指定文件,和字节数,以及数目,写入到程序提供的地址中,文件中的地址默认在开头,fseek可以设置流指向文件中的位置,来改变拷贝文件的起始地址

hello.c写文件

#include <stdio.h>
 #include <string.h>
 
int main()
 {
    FILE *fp = fopen("myfile", "w");
    if(!fp){
        printf("fopen error!\n");
    }
 
    const char *msg = "hello bit!\n";
    int count = 5;
    while(count--){
        fwrite(msg, strlen(msg), 1, fp);
    }
 
    fclose(fp);
 
    return 0;
 }

hello.c读文件 

#include <stdio.h>
 #include <string.h>
 
int main()
 {
    FILE *fp = fopen("myfile", "r");
    if(!fp){
        printf("fopen error!\n");
    }
 
    char buf[1024];
    const char *msg = "hello bit!\n";
    while(1){
        //注意返回值和参数,此处有坑,仔细查看man手册关于该函数的说明
        ssize_t s = fread(buf, 1, strlen(msg), fp);
        if(s > 0){
            buf[s] = 0;
            printf("%s", buf);
        }
        if(feof(fp)){
            break;
        }
    }
 
    fclose(fp);
    return 0;
 }

输出信息到显示器

#include <stdio.h>
 #include <string.h>
 
int main()
 {
    const char *msg = "hello fwrite\n";
    fwrite(msg, strlen(msg), 1, stdout);
 
    printf("hello printf\n");
    fprintf(stdout, "hello fprintf\n");
    return 0;
 }

 stdin & stdout & stderr

C默认会打开三个输入输出流,分别是stdin, stdout, stderr

仔细观察发现,这三个流的类型都是FILE*, fopen返回值类型,文件指针

打开文件的方式

  1. r Open text file for reading. The stream is positioned at the beginning of the file.
  2. r+ Open for reading and writing. The stream is positioned at the beginning of the file.
  3. w Truncate(缩短) file to zero length or create text file for writing. The stream is positioned at the beginning of the file.
  4. w+ Open for reading and writing. The file is created if it does not exist, otherwise it is truncated. The stream is positioned at the beginning of the file.
  5. a Open for appending (writing at end of file). The file is created if it does not exist. The stream is positioned at the end of the file.
  6. a+ Open for reading and appending (writing at end of file). The file is created if it does not exist. The initial file position for reading is at the beginning of the file, but output is always appended to the end of the file.

如上,是我们之前学的文件相关操作。还有fseek ftell rewind的函数,在C部分已经有所涉猎。请百度。

二、系统文件I/O(系统调用)

        操作文件,除了上述C接口(当然,C++也有接口,其他语言也有),我们还可以采用系统接口来进行文件访问, 先来直接以代码的形式,实现和上面一模一样的代码:

注意:以下是用linux系统进行演示的,在windows下系统调用,可能不一样,但是之前的c语言代码可以多个平台编译后运行,c语言库中对各个系统的都有各自的编译器,c语言的标准库中封装了各个系统的系统调用,通过编译时的处理,来匹配各自系统的系统调用,从而实现c语言的跨平台性。

hello.c 写文件:

#include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <string.h>
 
int main()
 {
    umask(0);
    int fd = open("myfile", O_WRONLY|O_CREAT, 0644);
    if(fd < 0){
        perror("open");
        return 1;
    }
 
    int count = 5;
    const char *msg = "hello bit!\n";
    int len = strlen(msg);
 
    while(count--){
        write(fd, msg, len);//fd: 后面讲, msg:缓冲区首地址, len: 本次读取,期望写入多少个字节的数
据。 返回值:实际写了多少字节数据
    }
 
    close(fd);
    return 0;
 }

hello.c读文件

#include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <string.h>
 
int main()
 {
    int fd = open("myfile", O_RDONLY);
    if(fd < 0){
        perror("open");
        return 1;
    }
 
    const char *msg = "hello bit!\n";
    char buf[1024];
    while(1){
        ssize_t s = read(fd, buf, strlen(msg));//类比write
        if(s > 0){
            printf("%s", buf);
        }else{
            break;
        }
    }
 
    close(fd);
    return 0;
 }

接口介绍

open

linux 手册查看命令:man open

 
#include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <string.h>
 
int main()
 {
    int fd = open("myfile", O_RDONLY);
    if(fd < 0){
        perror("open");
        return 1;
    }
 
    const char *msg = "hello bit!\n";
    char buf[1024];
    while(1){
        ssize_t s = read(fd, buf, strlen(msg));//类比write
        if(s > 0){
            printf("%s", buf);
        }else{
            break;
        }
    }
 
    close(fd);
    return 0;
 }
 #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

mode_t理解:直接 man 手册,比什么都清楚。命令:man mode_t

open 函数具体使用哪个,和具体应用场景相关,如目标文件不存在,需要open创建,则第三个参数表示创建文件的默认权限,否则,使用两个参数的open。

 write read close lseek ,类比C文件相关接口。

open函数返回值

  • 在认识返回值之前,先来认识一下两个概念: 系统调用 和库函数
  • 上面的 fopen fclose fread fwrite 都是C标准库当中的函数,我们称之为库函数(libc)。
  • 而,open fread close read write lseek 都属于系统提供的接口,称之为系统调用接口

系统调用接口和库函数的关系,一目了然。 所以,可以认为,f#系列的函数,都是对系统调用的封装,方便二次开发。

三、文件描述符fd

        通过对open函数的学习,我们知道了文件描述符就是一个小整数

0 & 1 & 2

  • Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2.
  • 0,1,2对应的物理设备一般是:键盘,显示器,显示器
  • 所以输入输出还可以采用如下方式:
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <string.h>
 int main()
 {
     char buf[1024];
     ssize_t s = read(0, buf, sizeof(buf));
     if(s > 0){
         buf[s] = 0;
         write(1, buf, strlen(buf));
         write(2, buf, strlen(buf));
     }
     return 0;
 }

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

文件描述符的分配规则

直接看代码:

#include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 
int main()
 {
    int fd = open("myfile", O_RDONLY);
    if(fd < 0){
        perror("open");
        return 1;
    }
    printf("fd: %d\n", fd);
 
    close(fd);
    return 0;
 }

 输出发现是 fd: 3

关闭0或者2,再次实验

#include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <stdlib.h>
 
int main()
 {
    close(1);
   int fd = open("myfile", O_WRONLY|O_CREAT, 00644);
   if(fd < 0){
       perror("open");
       return 1;
   }
    printf("fd: %d\n", fd);
    fflush(stdout);
    
   close(fd);
    exit(0);
 }

        此时,我们发现,本来应该输出到显示器上的内容,输出到了文件myfile当中,其中,fd=1。这种现象叫做输出 重定向。常见的重定向有:>, >>, <

        那重定向的本质是什么呢?

使用 dup2 系统调用 (重定向)

函数声明和头文件:

#include <unistd.h>
 
int dup2(int oldfd, int newfd);

函数功能使文件描述符newfd的被文件描述符oldfd覆盖,本质上是oldfd下标的指针指向newfd下标的指针所指向的用于描述文件的结构体file。

示例代码 

 #include <stdio.h>
 #include <unistd.h>
 #include <fcntl.h>
 
int main() {
  int fd = open("./log", O_CREAT | O_RDWR);
  if (fd < 0) {
    perror("open");
    return 1;
  }
  close(1);
  dup2(fd, 1);
  for (;;) {
    char buf[1024] = {0};
    ssize_t read_size = read(0, buf, sizeof(buf) - 1);
    if (read_size < 0) {
      perror("read");
      break;
    }
    printf("%s", buf);
    fflush(stdout);
  }
  return 0;
 }

printf是C库当中的IO函数,一般往stdout中输出,但是stdout底层访问文件的时候,找的还是fd:1, 但此时,fd:1 下标所表示内容,已经变成了myfile的地址,不再是显示器文件的地址,所以,输出的任何消息都会往文件中写 入,进而完成输出重定向。那追加和输入重定向如何完成呢?请同学们自行研究。

四、FILE

  • 因为IO相关函数与系统调用接口对应,并且库函数封装系统调用,所以本质上,访问文件都是通过fd访问的。
  • 所以C库当中的FILE结构体内部,必定封装了fd。

 来段代码在研究一下:

 
 if (pid == 0) {
        do_redirect(buff);
        argv = do_parse(buff);
        if (argv[0] == NULL) {
            exit(-1);
        }
        execvp(argv[0], argv);
    }else {
        waitpid(pid, NULL, 0);
    }
 
    return 0;
 }
 
int main(int argc, char *argv[])
 {
    while(1) {
        if (do_face() < 0)
            continue;
        do_exec(command);
    }
    return 0;
 }
 #include <stdio.h>
 #include <string.h>
 
int main()
 {
    const char *msg0="hello printf\n";
    const char *msg1="hello fwrite\n";
    const char *msg2="hello write\n";
 
    printf("%s", msg0);
    fwrite(msg1, strlen(msg0), 1, stdout);
    write(1, msg2, strlen(msg2));
 
    fork();
 
    return 0;
}

运行出结果:

hello printf
 hello fwrite
 hello write

但如果对进程实现输出重定向呢? ./hello > file , 我们发现结果变成了:

hello write
 hello printf
 hello fwrite
 hello printf
 hello fwrite

我们发现printf 和 fwrite (库函数)都输出了2次,write只输出了一次(系统调用)。为什么呢?肯定和而fork有关!

户级缓冲区

  • 一般C库函数写入文件时是全缓冲的,而写入显示器是行缓冲。
  • printf fwrite 库函数会自带缓冲区(属于每个进程的缓冲区,进度条例子就可以说明),当发生重定向到普通文件时,数据的缓冲方式由行缓冲变成了全缓冲。
  • 而我们放在缓冲区中的数据,就不会被立即刷新,甚至fork之后但是进程退出之后,会统一刷新,写入文件当中。
  • 但是fork的时候,父子数据会发生写时拷贝,所以当你父进程准备刷新的时候,子进程也就有了同样的一份数据,随即产生两份数据。
  • write 没有变化,说明没有所谓的缓冲。

        综上: printf fwrite 库函数会自带缓冲区,而 write 系统调用没有带缓冲区。另外,我们这里所说的缓冲区, 都是用户级缓冲区。其实为了提升整机性能,OS也会提供相关内核级缓冲区,不过不再我们讨论范围之内。 那这个缓冲区谁提供呢?

        printf fwrite 是库函数, write 是系统调用,库函数在系统调用的“上层”, 是对系统调用的“封装”,但是 write 没有缓冲区,printf,fwrite有,足以说明,该缓冲区是二次加上的,又因为是而C,所以由C标准库提供。 

如果有兴趣,可以看看FILE结构体:

typedef struct _IO_FILE FILE; 在/usr/include/stdio.h

五、理解文件系统

文件=文件内容+文件属性

我们使用ls -l的时候看到的除了看到文件名,还看到了文件的属性。

[root@localhost linux]# ls -l
total 12
-rwxr-xr-x. 1 root root 7438 "9月  13 14:56" a.out
-rw-r--r--. 1 root root  654 "9月  13 14:56" test.c

每行包含7列:模式    硬链接数    文件所有者    文件所属组    大小    最后修改时间    文件名

ls -l读取存储在磁盘上的文件信息,然后显示出来

其实这个信息除了通过这种方式来读取,还有一个stat命令能够看到更多信息 

 上面的执行结果有几个信息需要解释清楚

 inode(类似于进程pid)

为了能解释清楚inode我们先简单了解一下文件系统

Linux ext2文件系统,上图为磁盘文件系统图(内核内存映像肯定有所不同),磁盘是典型的块设备,硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的,并且不可以更改。例如mke2fs的-b选项可以设 定block大小为1024、2048或4096字节。而上图中启动块(Boot Block)的大小是确定的。每个区域都是以块为单位组成的。

  • Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相 同的结构组成。政府管理各区的例子
  • 超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量, 未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的 时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了,不是每个块组都有superBlock,每隔几个会存在一个Super Block。
  • GDT,Group Descriptor Table:块组描述符,描述块组属性信息,有兴趣的同学可以在了解一下
  • 块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没 有被占用
  • inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。
  • i节点表(inode Table):存放文件属性 如 文件大小,所有者,最近修改时间等,可以理解为文件属性的存放地址
  • 数据区:存放文件内容

将属性和数据分开存放的想法看起来很简单,但实际上是如何工作的呢?我们通过touch一个新文件来看看如何工作。

[root@localhost linux]# touch abc
 [root@localhost linux]# ls -i abc
 263466 abc

为了说明问题,我们将上图简化

创建一个新文件主要有一下4个操作:

1. 存储属性内核先找到一个空闲的i节点(这里是263466)。内核把文件信息记录到其中。

2. 存储数据该文件需要存储在三个磁盘块,内核找到了三个空闲块:300,500,800。将内核缓冲区的第一块数据 复制到300,下一块复制到500,以此类推。

3. 记录分配情况 文件内容按顺序300,500,800存放。内核在inode上的磁盘分布区记录了上述块列表。

4. 添加文件名到目录 新的文件名abc。linux如何在当前的目录中记录这个文件?内核将入口(263466,abc)添加到目录文 件。文件名和inode之间的对应关系将文件名和文件的内容及属性连接起来。

六、软链接和硬链接 

硬链接 

理解硬链接 

我们看到,真正找到磁盘上文件的并不是文件名,而是inode,利用inode找到文件。

其实在linux中可以让多个文件名对应于同一个 inode。

创建一个硬链接实际内存中就是在目录下添加一个文件名和inode的映射。ps:目录文件的内容:包含文件名和inode的映射。这样才能通过输入的指令中包含的文件名找到文件inode,对文件进行各自操作。

 [root@localhost linux]# touch abc 
[root@localhost linux]# ln abc def 
[root@localhost linux]# ls -1i abc def 
263466 abc 
263466 def

abc和def的链接状态完全相同,他们被称为指向文件的硬链接。

内核记录了这个连接数,inode 263466 的硬连接数为2。

我们在删除文件时干了两件事情:

1.在目录中将对应的记录删除,

2.将硬连接数-1,如果为0,则将对应 的磁盘释放

 实例:可以发现除了文件名不同其他都相同。

 软链接

硬链接是通过inode引用另外一个文件,软链接是通过文件内容引用另外一个文件,在shell中的做法。(可以理解成快捷方式,存储的是另一文件的地址)

263563 -rw-r--r--. 2 root root 0 9月  15 17:45 abc
 261678 lrwxrwxrwx. 1 root root 3 9月  15 17:53 abc.s -> abc
 263563 -rw-r--r--. 2 root root 0 9月  15 17:45 def

acm 下面解释一下文件的三个时间:

  • Access 最后访问时间
  • Modify 文件内容最后修改时间
  • Change 属性最后修改时间 

七、linux中文件系统内核图(简略):

八、动态库和静态库

  • 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库
  • 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
  • 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码
  • 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)
  • 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚 拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。
测试程序
/add.h/
 #ifndef __ADD_H__
 #define __ADD_H__ 
int add(int a, int b); 
#endif // __ADD_H__
 /add.c/
 #include "add.h"
 int add(int a, int b)
 {
 return a + b;
 }
 /sub.h/
 #ifndef __SUB_H__
 #define __SUB_H__ 
int sub(int a, int b); 
#endif // __SUB_H__
 /add.c/
 #include "add.h"
 int sub(int a, int b)
 {
 return a - b;
 }
 ///main.c
 #include <stdio.h>
 #include "add.h"
 #include "sub.h"
 int main( void )
 {
 int a = 10;
 int b = 20;
 printf("add(10, 20)=%d\n", a, b, add(a, b));
 a = 100;
 b = 20;
 printf("sub(%d,%d)=%d\n", a, b, sub(a, b));
 }

  生成静态库(shell指令) 

[root@localhost linux]# ls
 add.c  add.h  main.c  sub.c  sub.h
 [root@localhost linux]# gcc -c add.c -o add.o
 [root@localhost linux]# gcc -c sub.c -o sub.o
 
生成静态库
[root@localhost linux]# ar -rc libmymath.a add.o sub.o 
ar是gnu归档工具,rc表示(replace and create)
 
查看静态库中的目录列表
[root@localhost linux]# ar -tv libmymath.a 
rw-r--r-- 0/0   1240 Sep 15 16:53 2017 add.o
 rw-r--r-- 0/0   1240 Sep 15 16:53 2017 sub.o
 t:列出静态库中的文件
v:verbose 详细信息
 
[root@localhost linux]# gcc main.c -L. -lmymath
 -L 指定库路径-l 指定库名
测试目标文件生成后,静态库删掉,程序照样可以运行。

库搜索路径

从左到右搜索-L指定的目录。

由环境变量指定的目录 (LIBRARY_PATH)

由系统指定的目录 (/usr/lib       /usr/local/lib)

生成动态库

  • shared: 表示生成共享库格式
  • fPIC:产生位置无关码(position independent code)
  • 库名规则:libxxx.so
示例:   
[root@localhost linux]# gcc -fPIC -c sub.c add.c 
[root@localhost linux]# gcc -shared -o libmymath.so *.o 
[root@localhost linux]# ls add.c add.h add.o libmymath.so main.c sub.c sub.h sub.o

使用动态库

编译选项

l:链接动态库,只要库名即可(去掉lib以及版本号)

L:链接库所在的路径.

示例: gcc main.o -o main –L. -lhello

运行动态库

1、拷贝.so文件到系统共享库路径下, 一般指/usr/lib

2、更改LD_LIBRARY_PATH

[root@localhost linux]# export LD_LIBRARY_PATH=.
 [root@localhost linux]# gcc main.c -lmymath
 [root@localhost linux]# ./a.out
 add(10, 20)=30
 sub(100, 20)=8

3、ldconfig 配置/etc/ld.so.conf.d/,ldconfig更新

[root@localhost linux]# cat /etc/ld.so.conf.d/bit.conf 
/root/tools/linux
 [root@localhost linux]# ldconfig

使用外部库

系统中其实有很多库,它们通常由一组互相关联的用来完成某项常见工作的函数构成。比如用来处理屏幕显示情况 的函数(ncurses库)

#include <math.h>
 #include <stdio.h>
 int main(void)
 {
 double x = pow(2.0, 3.0);
 printf("The cubed is %f\n", x);
 return 0;
 }
 gcc -Wall calc.c -o calc -lm

-lm表示要链接libm.so或者libm.a库文件

库文件名称和引入库的名称

如:libc.so -> c库,去掉前缀lib,去掉后缀.so,.a

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MQTT服务器/MQTT_C#客户端/Websoket连MQTT

MQTT(消息队列遥测传输)是ISO 标准(ISO/IEC PRF 20922)下基于发布/订阅范式的消息协议。它工作在 TCP/IP协议族上,是为硬件性能低下的远程设备以及网络状况糟糕的情况下而设计的发布/订阅型消息协议,为此,它需要一个消息中间件 。 MQTT是一个基于客户端-服务器的消息发布/订…

ue 材质贴图Tiling repeat

材质问题&#xff0c;如下 贴图显然不符合逻辑&#xff0c;太大&#xff0c;并且是一次性贴图 换一个红砖纹理&#xff0c;就看清了&#xff0c;砖太大了 修改&#xff1a; 拖出一个TexCoord&#xff0c;代表坐标&#xff0c;拖出一个参数&#xff0c;代表次数&#xff0c;如…

Python数据分析之-Oracle数据库连接

文章目录 cx_Oracle 介绍cx_Oracle运行原理cx_Oracle 安装linux环境安装windows环境安装 cx_Oracle 使用单独使用结合Pandas使用 参考资料 cx_Oracle 介绍 cx_Oracle 8是一个Python扩展模块&#xff0c;它提供了对Oracle数据库的访问能力。以下是cx_Oracle 8的一些关键特性和功…

【学习笔记】Hive

Hive 作为数仓应用工具&#xff0c;对比 RDBMS&#xff08;关系型数据库&#xff09; 有3个“不能”&#xff1a; 不能像 RDBMS 一般实时响应&#xff0c;Hive 查询延时大&#xff1b; 不能像 RDBMS 做事务型查询&#xff0c;Hive 没有事务机制&#xff1b; 不能像 RDBMS 做行…

Android性能优化——卡顿优化

文章目录 一、从XML到屏幕上的展示造成跳帧的因素有那些发现问题定位问题定位代码 一、从XML到屏幕上的展示 数据加载阶段 数据控制阶段 数据展示阶段 xml —> view onCreat —> 解析layout.xml resume —> view —> wms ViewRootImpl UI 绘制流程 &#xff1a;测…

A股探底回升,跑出惊天大阳,你们知道为什么吗?

今天的A股&#xff0c;探底回升&#xff0c;让人惊呆了&#xff0c;你们知道是为什么吗&#xff1f;盘面上出现3个重要信号&#xff0c;一起来看看&#xff1a; 1、今天A股市场炸锅了&#xff0c;AI人工智能、国产软件、存储芯片迎来了涨停潮&#xff0c;惊呆了&#xff0c;科技…

DataGrip 2024 mac/win版:让数据库管理更简单

JetBrains DataGrip 2024 是一款专为数据库开发者设计的集成开发环境(IDE)&#xff0c;它凭借其卓越的性能和丰富的功能&#xff0c;为数据库管理提供了前所未有的便利。 DataGrip 2024 mac/win版获取 DataGrip 2024 支持几乎所有主流的关系型数据库管理系统&#xff0c;如 My…

Vue41 ref属性

ref属性 ref是Vue提供的获取组件的属性 <template><div><h1 v-text"msg" ref"title"></h1><button ref"btn" click"showDOM">点我输出上方的DOM元素</button><MySchool ref"sch"…

酷开科技丨酷开系统大屏购物 打造沉浸式购物体验

在这个信息化的时代&#xff0c;购物已经不仅仅局限于传统的线下店铺&#xff0c;线上购物逐渐成为了我们生活中重要的一部分。而大屏购物作为线上购物的一种形式&#xff0c;更是凭借其独特的优势和实用的技巧&#xff0c;成为了消费者们的新宠。随着科技的进步和消费者需求的…

Redis报错:MISCONF Redis is configured to save RDB snapshots

错误提示内容&#xff1a; 2024-06-25 16:30:49 : Connection: Redis_Server > [runCommand] PING 2024-06-25 16:30:49 : Connection: Redis_Server > Response received : -MISCONF Redis is configured to save RDB snapshots, but it is currently not able to pers…

江协科技51单片机学习- p19 串口通信

前言&#xff1a; 本文是根据哔哩哔哩网站上“江协科技51单片机”视频的学习笔记&#xff0c;在这里会记录下江协科技51单片机开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了江协科技51单片机教学视频和链接中的内容。 引用&#xff1a; 51单片机入门教程-2…

算法基础精选题单 动态规划(dp)(递推+线性dp)(个人题解)

前言&#xff1a; 一些简单的dp问题。 正文&#xff1a; 题单&#xff1a;237题】算法基础精选题单_ACM竞赛_ACM/CSP/ICPC/CCPC/比赛经验/题解/资讯_牛客竞赛OJ_牛客网 (nowcoder.com) 递推&#xff1a; NC235911 走楼梯&#xff1a; #include<bits/stdc.h> using na…

郑州大学人工智能简答

第一章 1. 什么是人工智能&#xff1f; 人工智能又称机器智能&#xff0c;主要研究人工的方法和技术开发智能机器或智能系统&#xff0c;以模仿、延伸和扩展人的智能、生物智能、自然智能&#xff0c;实现机器的智能行为。 人工智能的定义分四类&#xff1a; &#xff08;1&am…

切线与切平面的可视化

切线与切平面的可视化 flyfish 切线的可视化 import numpy as np import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation, PillowWriter# 定义一个简单的一元函数&#xff0c;例如 f(x) x^2 def func(x):return x**2# 计算函数的导数 def deriva…

Docker搭建ELK

docker安装ElasticSearch 创建网络 #这里先创建一个网络&#xff1a;因为我们还需要部署kibana容器、logstash容器&#xff0c;需要让这些容器互联。 docker network create elk-net#查看网络 docker network ls下载ES镜像 #搜索镜像 docker search elasticsearch #下载镜像…

【活动】搜维尔科技携Xsens邀您出席世界人工智能大会

展会介绍 由外交部、国家发展改革委、教育部、科技部、工业和信息化部、国家网信办、中国科学院、中国科协和上海市政府共同主办的世界人工智能大会&#xff08;WAIC&#xff09;&#xff0c;将于7月4日-7日在上海举行。围绕“以共商促共享 以善治促善智”主题&#xff0c;打造…

【MySQL】数据库事务详解

文章目录 前言1. 事务的定义2. 事务的四个特性2.1 原子性2.2 一致性2.3 隔离性2.4 持久性 3. 事务的并发问题3.1 脏读3.2 不可重复读3.3 幻读3.4 更新丢失 4. 事务的隔离级别5. 事务的使用结语 前言 假设我们现在需要操作数据库进行转账&#xff0c;A 给 B 转账 100 块钱&…

【Linux】进程信号_3

文章目录 八、进程信号2. 信号的保存3. 信号的处理 未完待续 八、进程信号 2. 信号的保存 实际执行信号的处理动作称为信号递达(Delivery) 信号从产生到递达之间的状态,称为信号未决(Pending)。 进程可以选择阻塞 (Block )某个信号。 被阻塞的信号产生时将保持在未决状态,直到…

6.26作业

1.整理思维导图 2.统计家目录下.c文件的个数 ls ~/*.c | wc -l 3.终端输入一个.sh文件&#xff0c;判断文件是否由可执行权限&#xff0c;如果有可执行权限运行脚本&#xff0c;没有可执行权限添加可执行权限后&#xff0c;再运行脚本 #!/bin/bash read -p "请输入一个.…

Go语言学习:每日一练1

Go语言学习&#xff1a;每日一练1 目录 Go语言学习&#xff1a;每日一练1变量声明函数定义流程控制 ifrange遍历switch 变量声明 package main//定义变量 var a 1 const Message “hello,world”func main() {b : 2 //短变量声明var c 3c TestMethod(a, b, c)} //定义函数…