Linux基础IO【 详 解 】

news2024/12/26 23:38:36

文章目录

  • C语言文件IO
    • C语言文件接口汇总
    • 默认打开的三个流
  • 系统文件IO
    • open
    • close
    • write
    • read
  • 文件描述符fd
  • 文件描述符的分配规则
  • 重定向
    • 重定向的本质
    • dup2
  • FILE
    • FILE当中的文件描述符
    • FILE当中的缓冲区
  • 理解文件系统
    • 初识inode
    • 磁盘分区与格式化介绍
  • 软硬链接
    • 软链接
    • 硬链接
    • 软硬链接的区别

C语言文件IO

C语言文件接口汇总

C语言中的文件操作函数如下:
在这里插入图片描述

对文件进行写入操作

#include <stdio.h>
int main()
{
	FILE* fp = fopen("log.txt", "w");
	if (fp == NULL){
		perror("fopen");
		return 1;
	}
	int count = 5;
	while (count){
		fputs("hello world\n", fp);//向文件中写入
		count--;
	}
	fclose(fp);
	return 0;
}

运行后,当前路径下会生成log.txt文件,并会写入内容。
在这里插入图片描述

对文件进行读取操作示例:

#include <stdio.h>
int main()
{
	FILE* fp = fopen("log.txt", "r");
	if (fp == NULL){
		perror("fopen");
		return 1;
	}
	char buffer[64];
	for (int i = 0; i < 5; i++){
		fgets(buffer, sizeof(buffer), fp);//读取
		printf("%s", buffer);
	}
	fclose(fp);
	return 0;
}

运行后,会读取文件内容到buffer里面,并打印到显示器上。
在这里插入图片描述

默认打开的三个流

Linux下一切皆文件,显示器和键盘也可以看作文件。我们能看到显示器上的数据,是因为我们向显示器写入了数据,电脑能
获取我们键盘上的字符,是电脑从“键盘文件” 读取了数据。

为什么我们向“显示器文件”写入数据以及从“键盘文件”读取数据前,不需要进行打开“显示器文件”和“键盘文件”的相应操作?

需要注意的是,打开文件一定是进程运行的时候打开的,而任何进程在运行的时候都会默认打开三个输入输出流,即标准输入流、标准输出流以及标准错误流,对应到C语言当中就是stdin、stdout以及stderr。
其中,标准输入流对应的设备就是键盘,标准输出流和标准错误流对应的设备都是显示器。

查看man手册我们就可以发现,stdin、stdout以及stderr这三个家伙实际上都是FILE*类型的。

extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;

当我们的程序被运行起来时,操作系统就会默认使用C语言的相关接口将这三个输入输出流打开。

注意: 不止是C语言当中有标准输入流、标准输出流和标准错误流,C++当中也有对应的cin、cout和cerr,其他所有语言当中都有类似的概念。实际上这种特性并不是某种语言所特有的,而是由操作系统所支持的

系统文件IO

操作文件除了C语言接口、C++接口或是其他语言的接口外,操作系统也有一套系统接口来进行文件的访问。
相比于C库函数或其他语言的库函数而言,系统调用接口更贴近底层,实际上这些语言的库函数都是对系统接口进行了封装。
在这里插入图片描述
我们在Linux平台下运行C代码时,C库函数就是对Linux系统调用接口进行的封装,在Windows平台下运行C代码时,C库函数就是对Windows系统调用接口进行的封装,这样做使得语言有了跨平台性,也方便进行二次开发。

open

open函数原型:

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

open参数介绍:
在这里插入图片描述
注意:

  1. pathname:
  • 若pathname以路径的方式给出,则当需要创建该文件时,就在pathname路径下进行创建。
  • 若pathname以文件名的方式给出,则当需要创建该文件时,默认在当前路径下进行创建。(注意当前路径的含义)
  1. 打开文件时,可以传入多个参数选项,当有多个选项传入时,将这些选项用“或”运算符隔开。
    例如 :O_WRONLY | O_CREAT
  2. 当不需要创建文件时,open的第三个参数可以不必设置
    在这里插入图片描述

open函数的返回值是新打开文件的文件描述符。

一次打开很多文件,来看看他们的文件描述符。

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main()
{
	umask(0);
	int fd1 = open("log1.txt", O_RDONLY | O_CREAT, 0666);
	int fd2 = open("log2.txt", O_RDONLY | O_CREAT, 0666);
	int fd3 = open("log3.txt", O_RDONLY | O_CREAT, 0666);
	int fd4 = open("log4.txt", O_RDONLY | O_CREAT, 0666);
	int fd5 = open("log5.txt", O_RDONLY | O_CREAT, 0666);
	printf("fd1:%d\n", fd1);
	printf("fd2:%d\n", fd2);
	printf("fd3:%d\n", fd3);
	printf("fd4:%d\n", fd4);
	printf("fd5:%d\n", fd5);
	return 0;
}

在这里插入图片描述
我们可以发现,文件的文件描述符是从3后面递增的。

实际上这里所谓的文件描述符本质上是一个指针数组的下标,指针数组当中的每一个指针都指向一个被打开文件的文件信息,通过对应文件的文件描述符就可以找到对应的文件信息。

当使用open函数打开文件成功时数组当中的指针个数增加,然后将该指针在数组当中的下标进行返回,而当文件打开失败时直接返回-1,因此,成功打开多个文件时所获得的文件描述符就是连续且递增的。

而Linux进程默认情况下会有3个缺省打开的文件描述符,分别就是标准输入0、标准输出1、标准错误2,这就是为什么成功打开文件时所得到的文件描述符是从3开始进程分配的。

close

系统接口中使用close函数关闭文件,close函数的函数原型如下:

int close(int fd);

使用close函数时传入需要关闭文件的文件描述符即可,若关闭文件成功则返回0,若关闭文件失败则返回-1。

write

系统接口中使用write函数向文件写入信息,write函数的函数原型如下:

ssize_t write(int fd, const void *buf, size_t count);

write函数,将buf位置开始向后count字节的数据写入文件描述符为fd的文件当中。

写入成功返回写入数据的字节个数,失败返回-1.

对文件写入操作

#include <stdio.h>
#include <string.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, 0666);
	if (fd < 0){
		perror("open");
		return 1;
	}
	const char* msg = "hello syscall\n";
	for (int i = 0; i < 5; i++){
		write(fd, msg, strlen(msg));
	}
	close(fd);
	return 0;
}

在这里插入图片描述

read

系统接口中使用read函数从文件读取信息,read函数的函数原型如下:

ssize_t read(int fd, void *buf, size_t count);

使用read函数,从文件描述符为fd的文件读取count字节的数据到buf位置当中。

写入成功返回写入数据的字节个数,失败返回-1.

文件描述符fd

文件是由进程运行时打开的,一个进程可以打开多个文件,而系统当中又存在大量进程,也就是说,在系统中任何时刻都可能存在大量已经打开的文件。

因此,操作系统务必要对这些已经打开的文件进行管理,操作系统会为每个已经打开的文件创建各自的struct file结构体,然后将这些结构体以双链表的形式连接起来,之后操作系统对文件的管理也就变成了对这张双链表的增删查改等操作。
而为了区分已经打开的文件哪些属于特定的某一个进程,我们就还需要建立进程和文件之间的对应关系。

进程和文件之间的对应关系是如何建立的?

当进程运行的时候,操作系统会将该程序的代码和数据加载到内存,然后创建对应的task_struct, mm_struct, 页表等…
在这里插入图片描述

task_struct 里面有一个指针,指向files_struct结构体,结构体里面有名为fd_array的指针数组,该数组的下标就是文件描述符。

当进程打开log.txt文件时,我们需要先将该文件从磁盘当中加载到内存,形成对应的struct file,将该struct file连入文件双链表,并将该结构体的首地址填入到fd_array数组当中下标为3的位置,使得fd_array数组中下标为3的指针指向该struct file,最后返回该文件的文件描述符给调用进程即可。

在这里插入图片描述
因此,我们只要有某一文件的文件描述符,就可以找到与该文件相关的文件信息,进而对文件进行一系列输入输出操作。

注意: 向文件写入数据时,是先将数据写入到对应文件的缓冲区当中,然后定期将缓冲区数据刷新到磁盘当中。

磁盘文件 VS 内存文件?

当文件存储在磁盘当中时,我们将其称之为磁盘文件,而当磁盘文件被加载到内存当中后,我们将加载到内存当中的文件称之为内存文件。磁盘文件和内存文件之间的关系就像程序和进程的关系一样,当程序运行起来后便成了进程,而当磁盘文件加载到内存后便成了内存文件。

文件描述符的分配规则

在这里插入图片描述
若我们在打开这五个文件前,先关闭文件描述符为0的文件,此后文件描述符的分配又会是怎样的呢?

close(0);

可以看到,第一个打开的文件获取到的文件描述符变成了0,而之后打开文件获取到的文件描述符还是从3开始依次递增的。
在这里插入图片描述

结论: 文件描述符是从最小但是没有被使用的fd_array数组下标开始进行分配的。

重定向

重定向的本质

先来看一组代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
	close(1);
	int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);
	if (fd < 0){
		perror("open");
		return 1;
	}
	printf("hello world\n");
	printf("hello world\n");
	printf("hello world\n");
	printf("hello world\n");
	printf("hello world\n");
	fflush(stdout);
	
	close(fd);
	return 0;
}

在这里插入图片描述

我们发现,显示器并没有显示数据,对应数据输出到了log.txt文件中。

注意:C语言的数据并不是立马写到了内存操作系统里面,而是写到了C语言的缓冲区当中,所以使用printf打印完后需要使用fflush将C语言缓冲区当中的数据刷新到文件中。

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

追加重定向本质

在这里插入图片描述

dup2

在Linux操作系统中提供了系统接口dup2,我们可以使用该函数完成重定向。dup2的函数原型如下:

int dup2(int oldfd, int newfd);

函数功能: dup2会将fd_array[oldfd]的内容拷贝到fd_array[newfd]当中,如果有必要的话我们需要先使用关闭文件描述符为newfd的文件。
函数返回值: dup2如果调用成功,返回newfd,否则返回-1。

注意:

  • 如果oldfd不是有效的文件描述符,则dup2调用失败,并且此时文件描述符为newfd的文件没有被关闭。
  • 如果oldfd是一个有效的文件描述符,但是newfd和oldfd具有相同的值,则dup2不做任何操作,并返回newfd。

例如,我们将打开文件log.txt时获取到的文件描述符和1传入dup2函数,那么dup2将会把fd_arrya[fd]的内容拷贝到fd_array[1]中,在代码中我们向stdout输出数据,而stdout是向文件描述符为1的文件输出数据,因此,本应该输出到显示器的数据就会重定向输出到log.txt文件当中。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
	int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);
	if (fd < 0){
		perror("open");
		return 1;
	}
	close(1);
	dup2(fd, 1);
	printf("hello printf\n");
	fprintf(stdout, "hello fprintf\n");
	return 0;
}

在这里插入图片描述
我们发现,数据被输入到了log.txt文件中。

FILE

FILE当中的文件描述符

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

FILE究竟是个什么东西呢?是一个c语言提供的结构体类型

我们在/usr/include/stdio.h头文件中可以看到下面这句代码,也就是说FILE实际上就是struct _IO_FILE结构体的一个别名。

typedef struct _IO_FILE FILE;

而我们在/usr/include/libio.h头文件中可以找到struct _IO_FILE结构体的定义,在该结构体的众多成员当中,我们可以看到一个名为_fileno的成员,这个成员实际上就是封装的文件描述符。

struct _IO_FILE {
	int _flags;       /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags

	//缓冲区相关
	/* The following pointers correspond to the C++ streambuf protocol. */
	/* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
	char* _IO_read_ptr;   /* Current read pointer */
	char* _IO_read_end;   /* End of get area. */
	char* _IO_read_base;  /* Start of putback+get area. */
	char* _IO_write_base; /* Start of put area. */
	char* _IO_write_ptr;  /* Current put pointer. */
	char* _IO_write_end;  /* End of put area. */
	char* _IO_buf_base;   /* Start of reserve area. */
	char* _IO_buf_end;    /* End of reserve area. */
	/* The following fields are used to support backing up and undo. */
	char *_IO_save_base; /* Pointer to start of non-current get area. */
	char *_IO_backup_base;  /* Pointer to first valid character of backup area */
	char *_IO_save_end; /* Pointer to end of non-current get area. */

	struct _IO_marker *_markers;

	struct _IO_FILE *_chain;

	int _fileno; //封装的文件描述符
#if 0
	int _blksize;
#else
	int _flags2;
#endif
	_IO_off_t _old_offset; /* This used to be _offset but it's too small.  */

#define __HAVE_COLUMN /* temporary */
	/* 1+column number of pbase(); 0 is unknown. */
	unsigned short _cur_column;
	signed char _vtable_offset;
	char _shortbuf[1];

	/*  char* _save_gptr;  char* _save_egptr; */

	_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

FILE当中的缓冲区

我们来看看下面这段代码,代码当中分别用了两个C库函数和一个系统接口向显示器输出内容,在代码最后还调用了fork函数。

#include <stdio.h>
#include <unistd.h>
int main()
{
	//c
	printf("hello printf\n");
	fputs("hello fputs\n", stdout);
	//system
	write(1, "hello write\n", 12);
	fork();
	return 0;
}

运行该程序,我们可以看到printf、fputs和write函数都成功将对应内容输出到了显示器上。

在这里插入图片描述
但是,当我们将程序的结果重定向到log.txt文件当中后,我们发现文件当中的内容与我们直接打印输出到显示器的内容是不一样的。

在这里插入图片描述
那为什么C库函数打印的内容重定向到文件后就变成了两份,而系统接口打印的内容还是原来的一份呢?

首先我们应该知道的是,缓冲的方式有以下三种:

  1. 无缓冲。
  2. 行缓冲。(常见的对显示器进行刷新数据)
  3. 全缓冲。(常见的对磁盘文件写入数据)

当我们直接执行可执行程序,将数据打印到显示器时所采用的就是行缓冲,因为代码当中每句话后面都有\n,所以当我们执行完对应代码后就立即将数据刷新到了显示器上。

而当我们将运行结果重定向到log.txt文件时,数据的刷新策略就变为了全缓冲,此时我们使用printf和fputs函数打印的数据都打印到了C语言自带的缓冲区当中,之后当我们使用fork函数创建子进程时,由于进程间具有独立性,而之后当父进程或是子进程对要刷新缓冲区内容时,本质就是对父子进程共享的数据进行了修改,此时就需要对数据进行写时拷贝,至此缓冲区当中的数据就变成了两份,一份父进程的,一份子进程的,所以重定向到log.txt文件当中printf和puts函数打印的数据就有两份。但由于write函数是系统接口,我们可以将write函数看作是没有缓冲区的,因此write函数打印的数据就只打印了一份。

这个缓冲区是谁提供的?

实际上这个缓冲区是C语言自带的,如果说这个缓冲区是操作系统提供的,那么printf、fputs和write函数打印的数据重定向到文件后都应该打印两次。

这个缓冲区在哪里?

我们常说printf是将数据打印到stdout里面,而stdout就是一个FILE*的指针,在FILE结构体当中还有一大部分成员是用于记录缓冲区相关的信息的。

//缓冲区相关
/* The following pointers correspond to the C++ streambuf protocol. */
/* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
char* _IO_read_ptr;   /* Current read pointer */
char* _IO_read_end;   /* End of get area. */
char* _IO_read_base;  /* Start of putback+get area. */
char* _IO_write_base; /* Start of put area. */
char* _IO_write_ptr;  /* Current put pointer. */
char* _IO_write_end;  /* End of put area. */
char* _IO_buf_base;   /* Start of reserve area. */
char* _IO_buf_end;    /* End of reserve area. */
/* The following fields are used to support backing up and undo. */
char *_IO_save_base; /* Pointer to start of non-current get area. */
char *_IO_backup_base;  /* Pointer to first valid character of backup area */
char *_IO_save_end; /* Pointer to end of non-current get area. */

也就是说,这里的缓冲区是由C语言提供,在FILE结构体当中进行维护的,FILE结构体当中不仅保存了对应文件的文件描述符还保存了用户缓冲区的相关信息。

操作系统有缓冲区吗?

操作系统实际上也是有缓冲区的,当我们刷新用户缓冲区的数据时,并不是直接将用户缓冲区的数据刷新到磁盘或是显示器上,而是先将数据刷新到操作系统缓冲区,然后再由操作系统将数据刷新到磁盘或是显示器上。(操作系统有自己的刷新机制,我们不必关系操作系统缓冲区的刷新规则)

在这里插入图片描述

理解文件系统

初识inode

磁盘文件由两部分构成,分别是文件内容和文件属性。文件内容就是文件当中存储的数据,文件属性就是文件的一些基本信息,例如文件名、文件大小以及文件创建时间等信息都是文件属性,文件属性又被称为元信息。

ls -l,可显示当前目录下各文件的属性信息。

在这里插入图片描述
在Linux操作系统中,文件的元信息和内容是分离存储的,其中保存元信息的结构称之为inode,因为系统当中可能存在大量的文件,所以我们需要给每个文件的属性集起一个唯一的编号,即inode号。
也就是说,inode是一个文件的属性集合,Linux中几乎每个文件都有一个inode,为了区分系统当中大量的inode,我们为每个inode设置了inode编号。

在命令行当中输入ls -i,即可显示当前目录下各文件的inode编号。
在这里插入图片描述

注意: 无论是文件内容还是文件属性,它们都是存储在磁盘当中的。

磁盘分区与格式化介绍

磁盘通常被称为块设备,一般以扇区为单位,一个扇区的大小通常为512字节。我们若以大小为512G的磁盘为例,该磁盘就可被分为十亿多个扇区。

在这里插入图片描述
计算机为了更好的管理磁盘,于是对磁盘进行了分区。磁盘分区就是使用分区编辑器在磁盘上划分几个逻辑部分,盘片一旦划分成数个分区,不同的目录与文件就可以存储进不同的分区,分区越多,就可以将文件的性质区分得越细,按照更为细分的性质,存储在不同的地方以管理文件,例如在Windows下磁盘一般被分为C盘和D盘两个区域。

命令:ls /dev/vda* -l 查看磁盘分区信息

在这里插入图片描述

在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/在这里插入图片描述
注意:

  1. 其他块组当中可能会存在冗余的Super Block,当某一Super Block被破坏后可以通过其他Super Block进行恢复。
  2. 磁盘分区并格式化后,每个分区的inode个数就确定了。

如何理解创建一个空文件?

  1. 通过遍历inode位图的方式,找到一个空闲的inode。
  2. 在inode表当中找到对应的inode,并将文件的属性信息填充进inode结构中。
  3. 将该文件的文件名和inode指针添加到目录文件的数据块中。

如何理解对文件写入信息?

  1. 通过文件的inode编号找到对应的inode结构。
  2. 通过inode结构找到存储该文件内容的数据块,并将数据写入数据块。
  3. 若不存在数据块或申请的数据块已被写满,则通过遍历块位图的方式找到一个空闲的块号,并在数据区当中找到对应的空闲

说明:
一个文件使用的数据块和inode结构的对应关系,是通过一个数组进行维护的,该数组一般可以存储15个元素,其中前12个元素分别对应该文件使用的12个数据块,剩余的三个元素分别是一级索引、二级索引和三级索引,当该文件使用数据块的个数超过12个时,可以用这三个索引进行数据块扩充。

如何理解删除一个文件?

  1. 将该文件对应的inode在inode位图当中置为无效。
  2. 将该文件申请过的数据块在块位图当中置为无效。

因为此操作并不会真正将文件对应的信息删除,而只是将其inode号和数据块号置为了无效,所以当我们删除文件后短时间内是可以恢复的。
为什么说是短时间内呢,因为该文件对应的inode号和数据块号已经被置为了无效,因此后续创建其他文件或是对其他文件进行写入操作申请inode号和数据块号时,可能会将该置为无效了的inode号和数据块号分配出去,此时删除文件的数据就会被覆盖,也就无法恢复文件了。

为什么拷贝文件的时候很慢,而删除文件的时候很快?

因为拷贝文件需要先创建文件,然后再对该文件进行写入操作,该过程需要先申请inode号并填入文件的属性信息,之后还需要再申请数据块号,最后才能进行文件内容的数据拷贝,而删除文件只需将对应文件的inode号和数据块号置为无效即可,无需真正的删除文件,因此拷贝文件是很慢的,而删除文件是很快的。

软硬链接

软链接

我们可以通过以下命令创建一个文件的软连接。

 ln -s test test.soft.link

在这里插入图片描述
通过ls -i -l命令我们可以看到,软链接文件的inode号与源文件的inode号是不同的,并且软链接文件的大小比源文件的大小要小得多。
在这里插入图片描述
软链接又叫做符号链接,软链接文件相对于源文件来说是一个独立的文件,该文件有自己的inode号,但是该文件只包含了源文件的路径名,所以软链接文件的大小要比源文件小得多。软链接就类似于Windows操作系统当中的快捷方式.

在这里插入图片描述

注意:但是软链接文件只是其源文件的一个标记,当删除了源文件后,链接文件不能独立存在,虽然仍保留文件名,但却不能执行或是查看软链接的内容了。

硬链接

我们可以通过以下命令创建一个文件的硬连接。

 ln test test.hard.link

在这里插入图片描述
通过ls -i -l命令我们可以看到,硬链接文件的inode号与源文件的inode号是相同的,并且硬链接文件的大小与源文件的大小也是相同的,特别注意的是,当创建了一个硬链接文件后,该硬链接文件和源文件的硬链接数都变成了2。
在这里插入图片描述
硬链接文件就是源文件的一个别名,一个文件有几个文件名,该文件的硬链接数就是几,这里inode号为2235074的文件有test和test.hard.link两个文件名,因此该文件的硬链接数为2。

注意:与软连接不同的是,当硬链接的源文件被删除后,硬链接文件仍能正常执行,只是文件的链接数减少了一个,因为此时该文件的文件名少了一个。

软硬链接的区别

  • 软链接是一个独立的文件,有独立的inode,而硬链接没有独立的inode。
  • 软链接相当于快捷方式,硬链接本质没有创建文件,只是建立了一个文件名和已有的inode的映射关系,并写入当前目录。

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

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

相关文章

混合专家系统(MoE)概述

MoE概述 神经网络的学习能力受限于它的参数规模&#xff0c;因此寻找更有效的方法来增加模型的参数已成为深度学习研究的趋势。混合专家系统 (MoE) 可以大幅增加模型参数规模且不会等比例地增加模型计算量&#xff0c;对于单个样本&#xff0c;神经网络只有某些部分被激活。在混…

基于JAVA+ springboot实现的抗疫物质信息管理系统

基于JAVA springboot实现的抗疫物质信息管理系统设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 …

手机ip地址获取失败是什么原因

在移动互联网时代&#xff0c;手机的IP地址不仅是设备在网络中的唯一标识&#xff0c;还关系到我们的网络体验与数据安全。然而&#xff0c;有时我们在使用手机时可能会遇到IP地址获取失败的情况。这种情况不仅会影响我们的在线活动&#xff0c;还可能引发一系列问题。本文将探…

【动态规划】二维费用的背包问题

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;折纸花满衣 &#x1f3e0;个人专栏&#xff1a;题目解析 &#x1f30e;推荐文章&#xff1a;【LeetCode】winter vacation training 目录 &#x1f449;&#x1f3fb;一和零 &#x1f449;&#x1f3fb;一…

智慧城市的新引擎:物联网技术引领城市创新与发展

目录 一、引言 二、物联网技术与智慧城市的融合 三、物联网技术在智慧城市中的应用 1、智慧交通管理 2、智慧能源管理 3、智慧环保管理 4、智慧公共服务 四、物联网技术引领城市创新与发展的价值 五、挑战与前景 六、结论 一、引言 随着科技的日新月异&#xff0c;物…

国家妇女节放假是法定的假日

在这个充满活力和希望的春天&#xff0c;我们迎来了一个特殊的节日——国家妇女节。这是一个属于所有女性的节日&#xff0c;是一个庆祝女性成就、关爱女性权益的时刻。在这个特殊的日子里&#xff0c;我们不禁要问&#xff1a;国家妇女节放假是法定假日吗&#xff1f;让我们一…

北斗卫星引领智能油气管线革新

北斗卫星引领智能油气管线革新 现代化的油气管线系统已成为国家经济发展的重要基础设施&#xff0c;而北斗卫星则为这些管线注入了新的活力。北斗卫星作为中国自主研发的卫星导航定位系统&#xff0c;其准确度和稳定性在全球范围内享有盛誉。在智能化时代的背景下&#xff0c;…

Pytorch线性回归实现(原理)

设置梯度 直接在tensor中设置 requires_gradTrue&#xff0c;每次操作这个数的时候&#xff0c;就会保存每一步的数据。也就是保存了梯度相关的数据。 import torch x torch.ones(2, 2, requires_gradTrue) #初始化参数x并设置requires_gradTrue用来追踪其计算历史 print(x…

炼石入选国家互联网应急中心CNCERT首批数据安全支撑单位

2024年2月22日&#xff0c;国家计算机网络应急技术处理协调中心&#xff08;以下简称CNCERT&#xff09;公示发布了第十届CNCERT网络安全应急服务支撑单位遴选结果&#xff0c;炼石成功入选首批“数据与软件安全评测领域”应急服务支撑单位&#xff01;本次遴选根据申报单位综合…

MySQL学习笔记(一)数据库事务隔离级别与多版本并发控制(MVCC)

一、数据库事务隔离级别 数据库事务的隔离级别有4种&#xff0c;由低到高分别为Read uncommitted &#xff08;读未提交&#xff09;、Read committed&#xff08;读提交&#xff09; 、Repeatable read&#xff08;可重复读&#xff09; 、Serializable &#xff08;串行化&a…

世界的尽头是sql注入漏洞

sql注入漏洞大家都了解吧&#xff1f;但是人类也会有类似sql注入型的漏洞存在&#xff01; sql注入本质是数据内容被当做命令执行。 举个简单的例子&#xff1a; 某国面临全国性战争&#xff0c;发起全国性的捐款捐物&#xff0c;基本流程是&#xff1a; 居民填写自愿捐助单由军…

连接kafka报错:java.io.IOException: Can‘t resolve address:

修改电脑host文件:C:\Windows\System32\drivers\etc\hosts 加上一行 192.168.1.XXX MHA_SLAVE2&#xff08;192.168.1.XXX 这个是安装kafka 的服务器地址&#xff0c;MHA_SLAVE2是kafka的容器id&#xff09;

基于深度学习的驾驶员分心驾驶行为(疲劳+危险行为)预警系统使用YOLOv5+Deepsort实现驾驶员的危险驾驶行为的预警监测

人物专注性检测 项目快速预览 主要不同地方为&#xff1a; 1、疲劳检测中去掉了点头行为的检测&#xff0c;仅保留闭眼检测和打哈欠检测。 2、Yolov5的权重进行了重新训练&#xff0c;增加了训练轮次。 3、前端UI进行了修改&#xff0c;精简了部分功能。 项目介绍 该项目…

数字时代下的内部审计蜕变:探索数字化转型的七大关键领域

写在前面 内部审计是一种独立的、客观的确认和咨询活动&#xff0c;包括鉴证、识别和分析问题以及提供管理建议和解决方案。狭义的数字化转型是指将企业经营管理和业务操作的各种行为、状态和结果用数字的形式来记录和存储&#xff0c;据此再对数据进行挖掘、分析和应用。广义…

企业上了BI,做了很多报表,老板为什么还是不满意?

上次讲了企业有了ERP为什么还要上BI&#xff0c;但是部分企业在部署商业智能BI后&#xff0c;没有感受到商业智能BI的高价值&#xff0c;让很多企业老板感觉不太满意。 经过分析后我们发现&#xff0c;很多企业是冲着商业智能BI的火热部署的&#xff0c;并不清楚商业智能BI的具…

AWTK 开源串口屏开发(12) - 记事本应用

记事本是一个很常用的应用&#xff0c;用来编辑和查看文本文件非常方便。在传统的的串口屏中&#xff0c;开发一个记事本应用&#xff0c;即使可能&#xff0c;也是非常麻烦的事情。在 AWTK 串口屏中&#xff0c;内置文件模型和文件选择对话框&#xff0c;实现一个简单的记事本…

Enzo Life Sciences Cortisol(皮质醇) ELISA kit

皮质醇又称为氢化可的松&#xff0c;是一种由胆固醇合成的类固醇激素。它是肾上腺皮质产生和分泌的主要糖皮质激素。皮质醇在血液中以游离皮质醇的形式存在&#xff0c;或与皮质类固醇结合球蛋白(CBG)结合。皮质醇水平在早上7点左右最高&#xff0c;晚上最低。皮质醇可以调节新…

docker部署springboot jar包项目

docker部署springboot jar包项目 前提&#xff0c;服务器环境是docker环境&#xff0c;如果服务器没有安装docker&#xff0c;可以先安装docker环境。 各个环境安装docker&#xff1a; Ubuntu上安装Docker&#xff1a; ubuntu离线安装docker: CentOS7离线安装Docker&#xff1…

类和对象 02【C++】

文章目录 一、 构造函数(初始化列表)1. 初始化列表2. explicit 关键字3. static成员 二、 友元1. 友元函数2.友元类 三、 内部函数四、 匿名对象五、 拷贝对象时的一些编译器优化 一、 构造函数(初始化列表) 进一步理解构造函数&#xff0c;我们知道创建对象时&#xff0c;编译…

昇腾芯片解析:华为自主研发的人工智能处理器全面分析

在当今科技发展的浪潮中&#xff0c;昇腾芯片作为一种新兴的处理器&#xff0c;正引起广泛的关注和讨论。升腾芯片究竟是由哪家公司生产的&#xff1f;这个问题一直困扰着许多人。下面小编将全面介绍、分析升腾芯片的生产商及各类参数、应用&#xff0c;以便读者对其有更全面的…