【linux】重定向+缓冲区

news2024/11/26 3:42:52

重定向+缓冲区

  • 1.重定向
    • 1.1重定向本质
    • 1.2重定向接口
    • 1.3重定向分类
      • 1.3.1>输出重定向
      • 1.3.2>>追加重定向
      • 1.3.3<输入重定向
  • 2.理解 >, >>, <
  • 3.如何理解linux下一切皆文件
  • 4.缓冲区
    • 4.1理解缓冲区问题
      • 4.1.1为什么要有缓冲区
      • 4.1.2缓冲区刷新策略的问题
      • 4.1.3缓冲区在哪里,指的是什么缓冲区
      • 4.1.4如何解释fork问题
  • 5.缓冲区该如何理解
    • 5.1myStdio.h
    • 5.2myStdio.c
      • 5.2.1_fopen
      • 5.2.2_fwrite
      • 5.2.3_fflush
      • 5.2.4_fclose
    • 5.3main.c
  • 6.缓冲区和OS的关系

自我名言只有努力,才能追逐梦想,只有努力,才不会欺骗自己。在这里插入图片描述
喜欢的点赞,收藏,关注一下把!在这里插入图片描述

1.重定向

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<sys/types.h>
  4 #include<sys/stat.h>
  5 #include<fcntl.h>
  6 #include<unistd.h>
  7 #include<stdlib.h>
  8 
  9 int main()
 10 {
 11    // close(0);
 12    // close(2);
 13     close(1);                                                                                                                                                    
 14     umask(0);                                                         
 15     int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);             
 16     if(fd == -1)                                                      
 17     {                                                                 
 18         perror("open");                                               
 19         exit(1);                                                      
 20     }                                                                 
 21     printf("fd:%d\n",fd);                                             
 22                                                                       
 23     close(fd);                                                        
 24                                                                       
 25     return 0;                                                         
 26 }  

在这里插入图片描述

close(1),为什么没有打印新建文件fd呢?

printf(“%d\n”,fd); printf会把内容打印到stdout文件中。
但是close(1)关闭标准输出stdout—>显示器,int fd=open();新打开的文件fd是1。
stdout–>fd–>1,虽然我们手动关闭了stdout,但是系统并不知道,还以为fd为1的位置是stdout,但是这个位置现在已经被新打开的文件占用了,所以打印到了新打开的文件里。

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<sys/types.h>
  4 #include<sys/stat.h>
  5 #include<fcntl.h>
  6 #include<unistd.h>
  7 #include<stdlib.h>
  8 
  9 int main()
 10 {
 11    // close(0);
 12    // close(2);
 13     close(1);
 14     umask(0);
 15     int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
 16     if(fd == -1)
 17     {
 18         perror("open");
 19         exit(1);
 20     }
 21     printf("fd:%d\n",fd);
 22     
 23     //这里必须刷新一下,不然log.txt里面没有内容,这里和缓冲区有关,下面讲                                                                                                                  
 24     fflush(stdout);      
 25     close(fd);           
 26                          
 27     return 0;            
 28 } 

在这里插入图片描述

本来应该打印到显示器文件中,但是却写到文件里了。------>重定向

1.1重定向本质

在这里插入图片描述

1.2重定向接口

在这里插入图片描述
这个主要介绍dup2函数。

int dup2(int oldfd, int newfd);

在这里插入图片描述
那怎么使用dup2来实现刚才的效果,把打印到显示器内容,写入到"log.txt"
在这里插入图片描述
是上面那样写的,还是下面那样写的,我们分析分析。
在这里插入图片描述
画图分析
在这里插入图片描述
在这里插入图片描述
因此正确写法如下
在这里插入图片描述

  4 #include<sys/stat.h>
  5 #include<fcntl.h>
  6 #include<unistd.h>
  7 #include<stdlib.h>
  8 
  9 int main()
 10 {
 11    // close(0);
 12    // close(2);
 13    // close(1);
 14     umask(0);
 15     int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
 16     if(fd == -1)
 17     {
 18         perror("open");
 19         exit(1);
 20     }
 21     //重定向                                                                                                                                                     
 22     dup2(fd,1);                                                                                                               
 23     printf("fd:%d\n",fd);                                                                                                     
 24                                                                                                                               
 25     //这里必须刷新一下,不然log.txt里面没有内容                                                                               
 26     fflush(stdout);                                                                                                           
 27     close(fd);                                                                                                                
 28                                                                                                                               
 29     return 0;                                                                                                                 
 30 }  

在这里插入图片描述

1.3重定向分类

1.3.1>输出重定向

上面内容就是输出重定向,把新打开文件的fd重定向到fd为1(默认为显示器)的位置。

1.3.2>>追加重定向

    1 #include<stdio.h>
    2 #include<string.h>
    3 #include<sys/types.h>
    4 #include<sys/stat.h>
    5 #include<fcntl.h>
    6 #include<unistd.h>
    7 #include<stdlib.h>
    8 
    9 int main()
   10 {
   11    // close(0);
   12    // close(2);
   13    // close(1);
   14     umask(0);
   15    // int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
   16     int fd=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);
   17     if(fd == -1)
   18     {
   19         perror("open");
   20         exit(1);
   21     }
   22     //重定向
   23     dup2(fd,1);
   24     printf("你好\n");
   25     printf("吃了吗\n");                                                                                                                                           
   26                                                                                                                           
   27     //这里必须刷新一下,不然log.txt里面没有内容                                                                           
   28     fflush(stdout);                                                                                                       
   29     close(fd);                                                                                                            
   30                                                                                                                           
   31     return 0;                                                                                                             
   32 } 

在这里插入图片描述

1.3.3<输入重定向

#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
     
int main()    
{    
   // close(0);    
   // close(2);    
   // close(1);    
    umask(0);    
   // int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);    
   // int fd=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);    
    int fd=open("log.txt",O_RDONLY);    
    if(fd == -1)    
    {      
        perror("open");      
        exit(1);      
    }      
    //输入重定向    
    dup2(fd,0);                                                                                                                                                      
    char outbuffer[64];        
    while(1)                   
    {                          
        printf("<");                                                     
        if(fgets(outbuffer,sizeof(outbuffer),stdin) == NULL) break;      
        printf("%s",outbuffer);                                                                                                                        
    }
    return 0;
 }   

在这里插入图片描述

2.理解 >, >>, <

在前面实现过一个自己的shell,现在我们给这个shell增加重定向功能来理解重定向。
在这里插入图片描述

//增加一个分割指令和文件名的函数                                                                                                                               
commandstrtok(lineCommand);

分割的时候,我们需要知道重定向是什么类型,文件是什么名字,因此增加两个全局变量来记录。

  //重定向类型    
  //第一个为初始重定向     
  #define DEFAULT_REDIR 0    
  #define INPUT_REDIR 1  
  #define OUTPUT_REDIR 2    
  #define ERROR_EDIRR 3    
      
  //重定向类型+文件名    
  int redirType=DEFAULT_REDIR;    
  char* redirFile=NULL;    

分割函数

  //这里找文件名没有写成函数,而写个宏
 #define trimSpace(start) do{\
      while(isspace(*start)) ++start;\
  }while(0)
  
  void commandstrtok(char* cmd)
  {
      assert(cmd);
      char* start=cmd;
      char* end=cmd+strlen(cmd);

      while(start < end)
      {
          if(*start == '<')
          {
              *start=0;
              ++start;
              //这里可能 ls -a -l >      log.txt,
              trimSpace(start);
              redirType=INPUT_REDIR;
              redirFile=start;
              break;
          }
          else if(*start == '>')                                                                                                                                 
          {                                                                                                                                                      
              *start=0;                                                                                                                                          
              ++start;                                                                                                                                           
              if(*start == '>')                                                                                                                                  
              {                                                                                                                                                  
                  redirType=APPEND_REDIR;                                                                                                                        
                  ++start;                                                                                                                                       
              }                                                                                                                                                  
              else                                                                                                                                               
              {                                                                                                                                                  
                  redirType=OUTPUT_REDIR;                                                                                                                        
              }                                                                                                                                                  
              trimSpace(start);                                                                                                                                  
              redirFile=start;                                                                                                                                       
              break;                                                                                                                                             
          }                                                                                                                                                      
          else
          {                                                                                                                                                      
              ++start;
          }
      }

因为命令是子进程执行的,真正重定向的功能一定是由子进程来完成的,
但是如何重定向是父进程要告知给子进程的。

//创建子进程
pid_t id = fork();
assert(id != -1);
if(id == 0)
{             
   switch(redirType)
   {
    	case INPUT_REDIR:
         {
             int fd=open("log.txt",O_RDONLY);
             if(fd <0)
              {
                  perror("open");
                  return 1;
               }
               //重定向文件已经打开了
                dup2(fd,0);
           }
           	 break;
           case OUTPUT_REDIR:
           case APPEND_REDIR:
           {
                umask(0);
                int flags=O_WRONLY|O_CREAT;
                if(redirType == OUTPUT_REDIR) flags|=O_CREAT;
                else flags|=O_APPEND;                                                                                                                     
                int fd=open("log.txt",flags,0666);
                if(fd < 0)
                {
                 	perror("open");
                    return 1;
                 }
                  dup2(fd,1);     
             }
               break;
             default:
             printf("bug?\n");
               break;
     }
      //程序替换
      execvp(myargv[0],myargv);
      exit(1);
}

在这里插入图片描述

shell完整代码

问:子进程重定向会影响父进程吗?

不会
在这里插入图片描述

问:指向程序替换的时候,会不会影响曾经进程打开的重定向文件呢?

不会
在这里插入图片描述

3.如何理解linux下一切皆文件

Linux下一切皆文件,那键盘,显示器,磁盘,网卡等硬件在linux下都是文件吗?
可以这样说的。
在这里插入图片描述
在这里插入图片描述

站在struct file上层看来,所有的设备和文件,统一都是struct file--------->Linux下一切皆文件。

在这里插入图片描述

这里可能有这样一个问题,如果同一个文件被多个指针指向,但是某个进程把这个文件关了,会不会影响其他进程对这个文件的操作呢?

其实并不会,一个被打开的文件有引用计数
在这里插入图片描述
表明有几个指针指向这个文件,这样做是因为一个文件可能被多个指针指向。如果某个进程关闭文件,影响到其他进程,就不能保证进程的独立性。close关闭文件,其实并不是真正关闭文件,只是把引用计数减1,当只有一个指针指向这个文件,close关闭文件才是真正关闭这个文件。

4.缓冲区

先看一种现象。

  1 #include<stdio.h>  
  2 #include<string.h>                                                        
  3 #include<sys/types.h>  
  4 #include<sys/stat.h>  
  5 #include<fcntl.h>  
  6 #include<unistd.h>  
  7 #include<stdlib.h>  
  8   
  9 int main()  
 10 {  
 11     printf("hello printf\n");  
 12     fprintf(stdout,"%s\n","hello fprintf");  
 13   
 14   
 15     const char* output="hello write\n";  
 16     write(1,output,strlen(output));  
 17   
 18                                                                                                                                                                  
 19     return 0;  
 20 }     

在这里插入图片描述

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<sys/types.h>
  4 #include<sys/stat.h>
  5 #include<fcntl.h>
  6 #include<unistd.h>
  7 #include<stdlib.h>
  8 
  9 int main()
 10 {
 11     printf("hello printf\n");
 12     fprintf(stdout,"%s\n","hello fprintf");
 13 
 14 
 15     const char* output="hello write\n";
 16     write(1,output,strlen(output));
 17 
 18     fork();                                                                                                                                                      
 19     return 0;                                                                                                                           
 20 }    

在这里插入图片描述
对比两张图片,第二段代码补充fork(创建子进程),重定向之后,C接口的函数,被打印了两次,系统调用的接口前面都只是打印了一次。

这是什么原因?现在只是知道肯定是fork函数有关。
其实这里也和缓冲区有关。

4.1理解缓冲区问题

缓冲区本质就是一段内存!!!

4.1.1为什么要有缓冲区

这里讲一个小故事,帮助理解。

在四川的张三要给远在北京的李四送一个键盘。
在这里插入图片描述
张三为了节省时间,选择2;
现实中快递行业的意义?
节省发送者的时间。

进程把数据打包给磁盘,是一个很慢的过程,如果让进程一直等着显然不太好。因此我们也需要一个快速的方式----->缓冲区

在这里插入图片描述
缓冲区的意义是什么呢?

节省进程进行数据IO的时间。

但是我们在用文件写的接口时,并没有专门拷贝数据啊?(以fwrite为例)

其实与其理解fwrite是写入到文件的函数,倒不如理解fwrie是拷贝函数,将数据从进程拷贝到"缓冲区"或者“外设”中。

4.1.2缓冲区刷新策略的问题

把东西给顺丰之后,那顺丰什么时候发货呢?

张三第二天在想寄一个鼠标给李四,当走到快递站点发现自己昨天的快递还没有发走,就问快递人员,快递人员说,我们的快递都是用大货车和飞机发送的,就这一个快递不可能马上就发走,等到满足发送件货才发。

缓冲区的刷新策略:
在这里插入图片描述
不同外设IO访问速度是不同的。
缓冲区结合具体的设备,定制自己的刷新策略。(3策略,2特殊)

3策略
a.立即刷新 ----> 无缓冲
b.行刷新 ----> 行缓存 ----> 显示器 (显示器是给人看的,如果一次给很多信息,人看着不舒服)
c.缓冲区满 ----> 全缓存 ----> 磁盘文件(显示器除外)

2特例
1:用户强制刷新 (fflush)
2:进程退出 (进程退出要刷新缓冲区)

4.1.3缓冲区在哪里,指的是什么缓冲区

C接口打印了两次,系统调用接口打印了一次,这种现象一定和缓冲区有关。
虽然现在不知道缓冲区在哪里,但是我们知道缓冲区一定不在内核中
因为C接口底层调用的是系统调用接口,如果缓冲区在内核中,write也应该打印两次。

那缓冲区到底在哪?

我们之前谈论的所有缓冲区,都指的是用户级语言层面给我们提供的缓冲区
还记得C程序默认给我们打开stdin,stdout,stderr都是------->FILE*------>指向FILE结构体,结构体包含-------> fd,其实还包含一个缓冲区

因此,缓冲区在FILE结构体中。

所以当我们自己要强制刷新:fflush(文件指针),关闭:fclose(文件指针)传的都是FILE*。因为缓存区在FILE结构体中。

4.1.4如何解释fork问题

在这里插入图片描述
代码结束之前,创建子进程。

1.我们没有进行>输出重定向,看到了三条信息。

stdout默认使用的是行刷新,在fork之前,两条C函数已经将数据打印输出到到显示器上,你的FILE内部,进程内部不存在对应的数据了。这时创建子进程,等到子进程,父进程退出的时,都要刷新缓冲区,但是这时缓冲区已经没有内容可以刷新了。因此C函数打印两条信息。

2.>输入重定向之后,C接口打印两次

当我们进行>,写入文件就不再是显示器,而是普通文件,采用的刷新策略是全缓存,之前2条C打印函数,虽然带了\n,但是不足与将stdout缓冲区写满,数据并没有被刷新。
fork的时候,stdout属于父进程,创建子进程紧跟着就是进程退出,谁先退出,一定要进行缓冲区刷新(缓存区刷新---->就是修改)
这时就有了写时拷贝!! 因此C接口,数据最终会显示两份。

3.write为什么前后只打印一次

上面过程都是write无关,write没有FILE,而用的是fd,就没有C提供的缓冲区。

5.缓冲区该如何理解

自己写一个简易的缓冲区,来帮助理解"数据刷新策略"+“数据如何缓存”

5.1myStdio.h

  1 #pragma once  
  2 #include<errno.h> 
  3 #include<stdio.h>      
  4 #include<string.h>      
  5 #include<sys/types.h>      
  6 #include<sys/stat.h>      
  7 #include<fcntl.h>      
  8 #include<unistd.h>      
  9 #include<stdlib.h> 
 10   
 11 #define SIZE 1024    
 12 #define SYNC_NOW 1    
 13 #define SYNC_LINE 2      
 14 #define SYNC_FULL 3     
 15                      
 16 typedef struct _FILE{  
 17     int flags;//刷新方式  
 18     int fileno;  //文件描述符
 19     int capacity;//buffer容量  
 20     int size;//buffer当前使用量  
 21     char buffer[SIZE]; //缓冲区
 22 }_FILE;              
 23   
 24                      
 25 _FILE* _fopen(const char* path_name,const char* mode);  
 26 void _fwrite(const void* ptr,int num,_FILE* fp);                                                                                                                 
 27 void _fclose(_FILE* fp);  
 28 void _fflush(_FILE* fp);  

5.2myStdio.c

5.2.1_fopen

 _FILE* _fopen(const char* path_name,const char* mode)
{
    assert(path_name);
    int flags=0;
    int defaultmode=0666;

    if(strcmp(mode,"r") == 0)
    {
        flags|=O_RDONLY;
    }
    else if(strcmp(mode,"w") == 0)
    {
        flags|=(O_WRONLY|O_CREAT|O_TRUNC);
    }
    else if(strcmp(mode,"a") == 0)
    {
        flags|=(O_WRONLY|O_CREAT|O_APPEND);
    }

    
    int fd=0;

    if(flags & O_RDONLY)
    {
        fd=open(path_name,flags);
    }
    else
    {
        fd=open(path_name,flags,defaultmode);                                                                                                                        
    }
    if(fd < 0)
    {
        const char*err=strerror(errno);
        write(2,err,strlen(err));
		return NULL;//这就是为什么创建文件失败,返回NULL
    }

    _FILE* fp=(_FILE*)malloc(sizeof(_FILE));
    assert(fp);

    fp->flags=SYNC_LINE;
    fp->fileno=fd;
    fp->capacity=SIZE;
    fp->size=0;
    memset(fp->buffer,0,SIZE);

    return fp;
}

5.2.2_fwrite

void _fwrite(const void* ptr,int num,_FILE* fp)                                                                                       
{                                                                                   
                                                                                                                                                                     
    //写到缓冲区里                                                                                                                  
    memcpy(fp->buffer+fp->size,ptr,num); //这里没有考虑缓冲区溢出问题                                                                                           
    fp->size+=num;                                                                                                                  
                                                                                                                                    
    //判断是否要刷新                                                                                                                
    if(fp->flags & SYNC_NOW)                                                                                                        
    {                                                                                                                               
        write(fp->fileno,fp->buffer,fp->size);                                                                                       
        fp->size=0;//清空缓冲区                                                                                                     
    }                                                                                                                               
    else if(fp->flags & SYNC_LINE)                                                                                                  
    {                                                                                                                               
        if(fp->buffer[fp->size-1] == '\n')  //这里也没有考虑abc\ndef这种形式,如果是这样的可以用for循环                                                                                        
        {                                                                                                                            
            write(fp->fileno,fp->buffer,fp->size);                                                                                       
            fp->size=0;                                                                                                             
        }                                                                                                                           
    }                                                                                                                               
    else if(fp->flags & SYNC_FULL)                                                                                                  
    {                                                                                                                               
        if(fp->size == fp->capacity)                                                                                                
        {                                                                                                                            
            write(fp->fileno,fp->buffer,fp->size);                                                                                       
            fp->size=0;                                                                                   
        }                                                                                                                           
    }                                                                                                                               
}     

5.2.3_fflush

void _fflush(_FILE* fp)                                                                                       
{                                                                                       
    if(fp->size > 0) write(fp->fileno,fp->buffer,fp->size);                                                                                       
    fsync(fp->fileno); //把数据强制从内核缓冲区刷新到磁盘                                                                                     
    fp->size=0;                                                                                                                                                      
} 

这里引入了内核缓冲区,下面解释。

5.2.4_fclose

void _fclose(_FILE* fp)                                                                                       
{                                                                                       
    _fflush(fp);  
    close(fp->fileno);                                                                                                                                               
}    

5.3main.c

行刷新

  1 #include"myStdio.h"
  2 
  3 
  4 int main()
  5 {
  6     _FILE* fp=_fopen("log.txt","w");
  7     if(fp == NULL)
  8     {
  9         perror("_fopen");
 10         return 1;
 11     }
 12 
 13     int cnt=10;
 14     const char* msg="hello linux\n";
 15     while(1)
 16     {
 17         _fwrite(msg,strlen(msg),fp);
 18         sleep(1);
 19         printf("count:%d\n",cnt--);
 20         if(cnt == 0) break;
 21     }                                                                       
 22     _fclose(fp);
 23 
 24     return 0;
 25 }

在这里插入图片描述

退出刷新

    1 #include"myStdio.h"
    2 
    3 
    4 int main()
    5 {
    6     _FILE* fp=_fopen("log.txt","w");
    7     if(fp == NULL)
    8     {
    9         perror("_fopen");
   10         return 1;
   11     }
   12 
   13     int cnt=10;
   14     const char* msg="hello linux";
   15     while(1)
   16     {
   17         _fwrite(msg,strlen(msg),fp);
   18         sleep(1);
   19         printf("count:%d\n",cnt--);                                       
   20         if(cnt == 0) break;
   21     }                    
   22     _fclose(fp);         
   23                          
   24     return 0;            
   25 }  

在这里插入图片描述
立即刷新

  1 #include"myStdio.h"
  2 
  3 
  4 int main()
  5 {
  6     _FILE* fp=_fopen("log.txt","w");
  7     if(fp == NULL)
  8     {
  9         perror("_fopen");
 10         return 1;
 11     }
 12 
 13     int cnt=10;
 14     const char* msg="hello linux";
 15     while(1)
 16     {
 17         _fwrite(msg,strlen(msg),fp);
 18         _fflush(fp);                                                        
 19         sleep(1);
 20         printf("count:%d\n",cnt--);
 21         if(cnt == 0) break;
 22     }          
 23     _fclose(fp);
 24                
 25     return 0;  
 26 }   

在这里插入图片描述

6.缓冲区和OS的关系

在这里插入图片描述
这里是由write函数,直接把数据写到磁盘上的文件中吗?
其实并不是这样的。
在这里插入图片描述
在这里插入图片描述
write并不是直接把缓冲区里的内容刷新到文件中,在打开文件对应的struct file{}结构体中其他有一个方法指针,还有一个指向内核缓冲区的指针,系统会把FILE结构体里面缓冲区内容通过struct file{}找到内核缓冲区,再由write()拷贝到内核缓冲区,然后再由这个内核缓冲区把内容刷新到文件中区,至于如何刷新和用户毫无关系,我们所知道的行刷新等,这是由语言层面所分类的,而内核缓冲区刷新由OS自主决定。

那么我们该如何证明有这个内核缓冲区呢?
超级大佬可以证明,这里证明不了,但是我们可以看到接口。
在这里插入图片描述
还有一个问题,如果OS突然宕机了会发生什么情况?
数据肯定会丢失。如果还是按照OS规定的内核缓冲区刷新策略肯定是不行的。
我们希望可以在用户层就告知OS,内核缓冲区不要再给我缓存了,赶紧把数据刷新到磁盘中。

这里介绍fsync函数

在这里插入图片描述
强制性把该文件对应的内核缓冲区数据持久到磁盘。就是OS不要给我缓存了,赶紧把数据给我更新到磁盘上。

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

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

相关文章

php获取10年内的年份并加入下拉列表

要实现的效果 在html中内嵌php循环将数组中的年份加入下拉列表 <div class="form-group"><label>年份:</label><div class="input-group"><div class="input-group-prepend"><span class="input-group-te…

7天狂揽 1.3w star 的 MetaGPT,他们的目标让软件公司为之一惊

在 AI 产品爆炸的今天&#xff0c;拥有各种本领的 AI 产品层出不穷&#xff0c;但 MetaGPT 的出现仍然显的格外耀眼&#xff0c;其可以实现只输入单一 prompt&#xff0c;就可以输出需求分析、需求文档、技术架构、最终代码等等产物&#xff0c;这相当于一个开发团队的输出成果…

012 Spring Boot + Vue 电影购票系统

部分代码地址&#xff1a; https://github.com/XinChennn/xc012-movie Spring Boot Vue 电影购票系统 一、项目结构 网上购票后台管理客服模块 二、环境介绍 后端&#xff1a;SpringBoot SpringSecurity MyBatis-Plus前端&#xff1a;Vue ElementUi数据库&#xff1a;…

mongodb如何多表查询,如同时查询店铺以及里面对应的商品

多表查询场景介绍 一种很常见的场景&#xff0c;比如电商首页中&#xff0c;需要同时展示最近比较火热的店铺&#xff0c;以及直接展示店铺里对应的商品。或者用户下单之后购物车里可以看到所选的商品以及对应的店铺。如果不知道如何用mongodb自带的查询语句快速查询的话&#…

有限差分法

目录 1.原理介绍 1.1 有限差分法介绍 1.2 有限差分法步骤 2.案例分析 2.1 问题重述 2.2 问题求解 1.原理介绍 1.1 有限差分法介绍 有限差分法是一种常用的数值计算方法&#xff0c;用于求解偏微分方程或常微分方程的数值解。它的基本思想是将连续的空间区域离散化为有限…

mac电脑安装雷蛇管理软件,实现调整鼠标dpi,移动速度,灯光等

雷蛇官网只给了win版本驱动 mac版本驱动到这里下载: GitHub - 1kc/razer-macos: Color effects manager for Razer devices for macOS. Supports High Sierra (10.13) to Monterey (12.0). Made by the community, based on openrazer. 安装后会显示开发者不明,请丢弃到垃圾桶.…

Java:SpringBoot整合Spring Batch示例

目录 文档基础概念Tasklet方式示例Chunk方式示例参考文章 文档 https://docs.spring.io/spring-batch/docs/4.3.9/reference/html/index.html 基础概念 JobLauncher&#xff1a;作业启动器&#xff0c;启动作业的入口。对应的实现类为SimpleJobLauncher。Job&#xff1a;作业…

PLC通过Modbus转Profinet网关连接变频器控制电机配置案例

在本案例中&#xff0c;通过使用Modbus转Profinet网关&#xff08;XD-MDPN100&#xff09;&#xff0c;PLC可以通过Profinet协议与变频器进行通信和控制。这样&#xff0c;PLC可以实现对电机的转速调节、启停控制等功能。 同时&#xff0c;通过Modbus转Profinet&#xff08;XD-…

你还在为协同办公烦恼吗?试试视频协同办公吧!

在这个信息化、数字化的时代&#xff0c;协同办公已经成为了企业、团队的必备工具。然而&#xff0c;尽管传统的协同办公工具有诸多优点&#xff0c;但在实际使用中&#xff0c;仍会遇到各种各样的问题。你是否还在为这些问题而烦恼&#xff1f;别担心&#xff0c;让我们一起探…

【C++】函数重载 引用 内联函数

目录 一&#xff0c;函数重载 1&#xff0c;函数重载的概念 2&#xff0c;C支持函数重载的原理 二&#xff0c;引用 1&#xff0c;引用概念 2&#xff0c;引用特性 3&#xff0c;常引用 4&#xff0c;做参数 5&#xff0c;做返回值 6&#xff0c;传值、传引用效率比较…

【LeetCode(LeetCode刷题经典一百题)】:移动零

给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输入: nums [0] 输出: [0] 方…

python二次开发CATIA:全约束草图

​约束的创建需要用到 Sketch 下面 Constraints 这个 Collection 的 Add 方法。该对象创建约束有三个方法&#xff1a;AddMonoEltCst&#xff0c; AddBiEltCst&#xff0c; AddTriEltCst&#xff0c;对应的功能分别为为单个元素创建约束&#xff08;如固定 a&#xff09; 、为两…

RHCE8 资料整理(一)

RHCE8 资料整理 第一篇 基本配置第1章 安装RHEL8第2章 基本命令的使用2.1 终端设置2.2 输入命令的语法2.3 介绍shell2.4 用户切换 第3章 了解linux分区及常用命令3.1 路径3.2 创建和删除目录3.3 cd3.4 拷贝和剪切3.5 常见命令归纳filewctouchlnalias/unaliascat/tac/nlmore/les…

世界粮食日:宏工科技有对策,赋能食品生产高效可持续发展

10月16日是世界粮食日。随着全球人口的增长&#xff0c;人们对高品质食品的需求也越来越大&#xff0c;如何实现“更好生产、更好营养”成为了食品生产与供应的重要话题。15年来&#xff0c;宏工科技专注物料处理自动化领域&#xff0c;提供食品物料处理一站式解决方案以提高生…

数字孪生技术如何提高化工生产安全性?

随着科技的不断进步&#xff0c;数字孪生技术已经渗透到了各个领域&#xff0c;为化工行业带来了翻天覆地的变革。这一技术的应用不仅在生产效率方面发挥了积极作用&#xff0c;还在安全性、创新、环保和可持续性等多个方面作出了巨大的贡献。 化工行业常常涉及危险品和复杂的生…

网络安全行业需要考哪些证书

一、NISP国家信息安全水平证书 国家信息安全水平考试&#xff08;National Information Security Test Program&#xff0c;简称NISP&#xff09;&#xff0c;是由中国信息安全测评中心实施培养国家网络空间安全人才的项目。由国家网络空间安全人才培养基地运营/管理&#xff…

vue3 电子签名实现

vue电子签名可以通过vue-esign插件来实现: 第一步安装&#xff1a; npm install vue-esign 引用方式&#xff1a; 全局&#xff1a; 局部&#xff1a; // .vue 文件 import vueEsign form vue-esign 使用方式&#xff1a; <template><!-- 使用这个签名组件 --&…

WampServer下载安装并结合cpolar内网穿透实现本地服务的公网访问

文章目录 前言1.WampServer下载安装2.WampServer启动3.安装cpolar内网穿透3.1 注册账号3.2 下载cpolar客户端3.3 登录cpolar web ui管理界面3.4 创建公网地址 4.固定公网地址访问 前言 Wamp 是一个 Windows系统下的 Apache PHP Mysql 集成安装环境&#xff0c;是一组常用来…

爬虫ip如何加入到代码里实现自动化数据抓取

以下是一个使用HTTP:Tiny和www.weibo.com的音频爬虫程序的示例。这个示例使用了https://www.duoip.cn/get_proxy来获取爬虫IP。请注意&#xff0c;这个示例可能需要根据你的实际需求进行调整。 #!/usr/bin/perluse strict; use warnings; use HTTP::Tiny; use LWP::UserAgent; …

智能垃圾桶丨悦享便捷生活

垃圾桶是人们日常生活所必不可少的必需品&#xff0c;它让生活中所产生的垃圾有了一个正确的存放地方。随着生产技术的迅速发展&#xff0c;垃圾桶也得以更新换代。由最初的简单式的圆筒式垃圾桶&#xff0c;到现在出现的感应式垃圾桶、智能语音控制垃圾桶&#xff0c;垃圾桶也…