文件系统、描述符和缓冲区
目录
🏆一、文件系统
1、open
①对open接口的介绍
②接口使用
2、write接口
3、read接口
🏆二、深入理解文件描述符fd
1、fd具体实质
2、文件fd的分配规则
3、fd重定向
①输出重定向
②追加重定向
③输入重定向
④文件的引用计数
🏆三、缓冲区的理解
🏆一、文件系统
1、空文件,也要在磁盘占据空间。
2、文件=内容+属性。
3、文件操作=对内容 + 对属性 or 对内容和属性
4、标定一个文件,必须使用:文件路径+文件名 [唯一性]
5、如果没有指明对应的文件路径,默认是在当前路径下进行文件访问
对文件的操作本质是进程对文件的操作!
一个文件要被访问,就必须先被打开!
文件操作是十分重要的,不同的语言都有自己独特的文件操作接口。C、C++、Java、python、php、shell等语言都有自己独特的文件操作接口。如果我们要全部掌握这些接口成本是很高的!而如果我们重新考虑文件的位置,以及我们访问文件所必经的路径:
所以为了降低学习成本,就要掌握系统调用接口。
批量化注释的方式:
1、open
①对open接口的介绍
C语言中打开文件的函数是fopen。
而fopen底层是调用了系统的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: 追加写O_TRUNC:清空文件再写入
返回值:成功:新打开的文件描述符失败:-1
open接口的使用方式和fopen不太一样。首先在C语言中fopen成功返回FILE*指针,那是C中的概念,在操作系统中open接口调用成功则返回file descriptor(文件描述符),它是比C中指针更底层的东西。这一点文件描述符到底还有什么玄妙之处后续再详细介绍。
首先我们来关注open接口的第二个参数:flags,flags是标定打开文件的方式。它是用来作标记的,比如我们在C中常用bool值做标记,但是它只能标记true or false。如果文件显然打开方式有很多,只这两种是不满足我们的需求的。比如以只读、只写、读写、追加等方式打开。而我们要实现这一功能,需要对flags进行独特的设计。Linux借用int的特性,因为int是32个bit位,OS使用每一个bit位来做标记,那么它到底是怎么实现的呢?我们可以借助演示一段代码:
这里的宏ONE TWO THREE FOUR就是类似于一个个的选项。并且这里采用一个比特位表示一个选项,彼此位置不重叠。
我们在使用这些选项采用的是| 操作。
明白了这些,我们就可以简单使用一下open操作。
②接口使用
以只写方式打开一个不存在的文件。
我们发现以只写形式,系统不会自动创建文件,那是因为OS不会自己创建。C语言是经过了封装,如果我们想让它以只写形式的同时还要创建,要再 | 上创建选项。
然而这里的创建的log.txt是没法使用的,因为它的权限是随机的,我们在创建文件的时候要加上文件的权限。这一点也是open接口第三个参数的意义:权限。
所以我们也能理解了为什么OS准备了两套open接口 :
对于已经存在的文件打开时是不需要设置权限的。
同时,如果我们想修改创建文件的权限,可以修改umask值。
因为文件权限设置的方式是:
而umask默认权限是0002.
当然这里flags选项并没有讲完,它需要结合其他接口来演示效果更佳。
2、write接口
在了解了open是如何使用之后,我们再来看一下write的使用方式。老规矩,先来段演示代码:
write接口和fwrite是不一样的。我们在使用fwrite接口的时候,因为strlen不计入'\0',所以我们要+1,为'\0'预留一个位置。而我们在使用write接口的时候,是否需要也预留一个位置给'\0'呢?
那我们不妨打印输出一下:
显然+1结果并不如我们所愿。那么出现这种情况是因为,以'\0'作为字符串的结尾,是C语言的规定,和文件没有关系。而系统看来,它的文件并不需要'\0',它只要字符串的有效内容,所以使用系统接口write向文件写入字符串并不需要给'\0'留位置!!
我们再来看一段代码:
我们发现,我们以只写打开文件操作系统并没有为我们清空文件。这一点也是和C语言不同的。
C语言对这部分做了处理,会自动清空文件重写,而默认操作系统的文件写入是覆盖,它没有清空里面的内容。
如果我们想重写文件时先清空再写入,需要添加选项:O_TRUNC
至此,O_WRONLY选项是只写,如果文件不存在不会自动创建,而O_CREAT选项则是文件不存在就创建,默认情况下,对文件写入是覆盖,不会清空文件,所以O_TRUNC是清空文件选项。
那么如果我想实现追加呢? O_APPEND
3、read接口
ssize_t 是一种系统定制的类型,是有符合整数,可以等于0,大于0,小于0.
从特定的文件fd当中,将数据读到缓冲区里,期望读多少个,就是count。
演示:
至此,我们可以看一下语言对文件的操作本质就是对系统调用接口的封装。
🏆二、深入理解文件描述符fd
1、fd具体实质
我们再来理解一下文件。通过对系统调用接口open、write、read的认识,我们大概清楚文件操作的本质就是进程和被打开文件的关系。而系统中存在大量的文件,其中有的没被打开存储在磁盘上,而被打开的文件就要被OS管理起来。到底是如何管理的呢?
操作系统为了管理对应的打开文件,必定要为文件创建对应的内核数据结构标识文件:
struct file{} ,而这其中包含了文件的大部分属性。
结构体file里面有文件的属性,也有文件描述符。这样讲起来还是有点抽象,我们可以画个图更深入理解:
当文件被打开的时候,它的地址被计入到文件指针数组中,进程通过指针数组管理。而文件描述符本质上讲就是这个指针数组的下标。也就是标识打开文件在指针数组中的位置。而键盘、鼠标、显示器这些也是文件!
当然以上所述是结论,还是举些例子:
我们看到新打开文件的fd文件描述符从3开始,既然他们表示数组下标,为什么不是从0开始呢?这是因为默认打开了三个标准输入输出流:
那么他们的返回值不是文件描述符,而是结构体指针,说明结构体中包含了文件描述符。
验证:
果然他们的fd是0、1、2.所以我们打开的文件都是从3开始。
补充:FILE结构体:
在/usr/include/libio.h路径下:
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 0int _blksize;
#elseint _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
};
2、文件fd的分配规则
文件fd的分配规则是从指针数组下标,从小到大,按照顺序寻找最小的且没有被占用的下标fd。
举例说明:
再运行文件时,没有办法看到printf的内容。这是因为,按照有空插空的原则,这时fd数组下标为1的地方被文件myfile占用,而OS角度来看,它只会内容输出到fd为1(标准输出)的文件。这时就会出现无法打印到屏幕的现象。
3、fd重定向
本来应该输出到显示器,但是这里输出打印到log.txt,这称为重定向。
重定向的本质是:上层用的fd不变,在内核中更改fd对应的struct file*的地址。
这里的上层用的fd不变指的是在上层看来标准输入输出的文件描述符一直是0和1.
简单来说,OS不会去具体查看struct file* 的内容而是根据下标来执行。
①输出重定向
针对重定向,OS为我们提供了一个接口专门用于重定向。
把oldfd下标指向的内容拷贝到newfd下标指向。
②追加重定向
③输入重定向
这里我们要解决几个问题,子进程重定向会影响父进程吗?
我们知道,进程具有独立性,所以子进程不能影响父进程,所以说file*表父子进程是不一致的!
所以对于父子进程来说,子进程要拷贝父进程的进程管理,而如果对子进程进行重定向,那么就会file*表发生改变,而这一操作是不影响父进程的(进程具有独立性)。而文件是属于系统部分的,不需要拷贝给子进程。他们只是根据file*表对文件的处理不同。
所以说Linux的做法不是让子进程和父进程共享一张file_struct的表,而是拷贝一份父进程的表,这样不影响进程间的独立性。而执行进程程序替换的时候,不会影响曾经进程打开的重定向文件。因为你替换的是磁盘上拷贝下来的代码和数据,而重定向这些属于内核维护的数据结构,也就是说不影响pcb。
Linux下一切皆文件:
在OS看来它们都是struct file,没有什么不同,读写方法时直接调用对应的函数指针(多态的思想)。所有的设备和文件,统一都是struct file.
④文件的引用计数
我们close文件,是真的关闭了文件吗?如果真的关闭了文件,那么如果有多个进程打开同一个文件,我关闭了它而别的进程还在使用这样显然是不合适的。所以就有了文件的引用计数,在file结构体中,有一个f_count变量用于统计打开文件的个数。当f_count为0时文件才被关闭,因为当有引用文件,文件不会被关闭。
🏆三、缓冲区的理解
缓冲区本质就是一段内存。
缓冲区的意义是节省进程进行数据IO的时间,因为进程将数据存储到磁盘(访问外设)速度很慢,所以就有了进程先将数据放到缓冲区,缓冲区再将数据存储到磁盘。
而存放到缓冲区的数据,缓冲区有自己的刷新策略:
我们来段代码具体感受缓冲区的刷新策略:
我们发现在fork子进程之后,当重定位到文件中时,C接口的函数,前后打印了两次,而系统接口前后只打印了一次,这就和缓冲区有关。
所以我们知道一个信息,C语言中,存在缓冲区,而write在将数据拷贝到文件中的过程中并不存在缓冲区。但是我们的内核中是存在缓冲区的,这个缓冲区存在于将文件中的数据拷贝到磁盘上这个过程中。
所以说,如果我们使用C语言将数据拷贝到文件,再存储到磁盘,经历了两次将数据拷贝到缓冲区。而使用OS提供的写入,则只经历了一次将数据存入到内核缓冲区。
而内核缓冲区刷新数据到磁盘完全是由操作系统决定的。
那这里也衍生了一个问题,如果操作系统挂掉了,我们在内核缓冲区的数据该怎么办呢?
自己实现的一个迷你版shell命令行控制器:
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<assert.h>
#include<stdlib.h>
#include<ctype.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#define NUM 1024
#define OPT_NUM 64#define NONE_REDIR 0
#define INPUT_REDIR 1
#define OUTPUT_REDIR 2
#define APPEND_REDIR 3#define trimSpace(start) do{\while(isspace(*start)) ++start;\}while(0)
//do while(0) 包裹一个代码块
char lineCommand[NUM];
char *myargv[OPT_NUM];//指针数组
int lastCode=0;
int lastSig=0;
int redirType= NONE_REDIR;
char *redirFile=NULL;void commandCheck(char* commands)
{assert(commands);char * start=commands;char* end=commands+ strlen(commands);while(start<end){if(*start =='>'){*start='\0';++start;if(*start=='>'){redirType=APPEND_REDIR;}else{redirType=OUTPUT_REDIR;}//要么是输出要么是追加trimSpace(start);redirFile=start;break;}else if(*start=='<'){//拆分成两个//"cat < file.txt"*start='\0';start++;trimSpace(start);//////usrredirType=INPUT_REDIR;redirFile=start;break;}else{start++;}}
}
int main()
{while(1){redirType= NONE_REDIR;redirFile=NULL;//输出提示符printf("用户名@主机名 当前路径# ");fflush(stdout);char *s= fgets(lineCommand,sizeof(lineCommand)-1,stdin);//去除\0assert(s!=NULL);(void)s;//清除最后一个\n,abcd\n \n重置为\0lineCommand[strlen(lineCommand)-1]=0;//ls -a -l -i "ls" "-a" "-l" -i"//字符串切割//"ls -a -l -i" ->"ls" "-a" "-l" "-i"commandCheck(lineCommand);//strtokmyargv[0]=strtok(lineCommand," ");//如果没有子串了,strtok->NULL,myargv[end]=NULLint i=1;if(myargv[0]!=NULL&& strcmp(myargv[0],"ls")==0){myargv[i++]=(char*)"--color=auto";}//如果没有子串了,strtok->NULL,myargv[end]=NULLwhile(myargv[i++]=strtok(NULL," "));//如果是cd命令,不需要创建子进程,让shell自己执行对应的命令if(myargv[0]!=NULL&&strcmp(myargv[0],"cd")==0){if(myargv[1]!=NULL)chdir(myargv[1]);continue;}if(myargv[0]!=NULL && myargv[1]!=NULL && strcmp(myargv[0],"echo")==0){if(strcmp(myargv[1],"$?")==0){printf("%d,%d\n",lastCode,lastSig);}else{printf("%s\n",myargv[1]);}continue;}//测试是否成功,条件编译
#ifdef DEBUGfor(int i=0;myargv[i];i++){printf("myargv[%d]: %s\n",i,myargv[i]);}
#endif//#注释掉DEBUG//执行命令pid_t id =fork();assert(id !=-1);if(id==0){//因为命令是子进程执行的,真正重定向的工作一定要是子进程来完成//如何重定向,是父进程要给子进程提供信息的//这里重定向会影响父进程吗?switch(redirType){case NONE_REDIR://什么都不做break;case INPUT_REDIR:{int fd=open(redirFile,O_RDONLY);if(fd<0){perror("open");exit(errno);}//重定向的文件已经成功打开了dup2(fd,0);}break;case OUTPUT_REDIR:case APPEND_REDIR:{umask(0);int flags=O_WRONLY | O_CREAT;if(redirType==APPEND_REDIR) flags|=O_APPEND;else flags|=O_TRUNC;int fd=open(redirFile,flags,0666);if(fd<0){perror("open");exit(errno);}dup2(fd,1);}break;default:printf("bug\n");break;}execvp(myargv[0],myargv);exit(1);}int status=0;pid_t ret= waitpid(id,&status,0);assert(ret>0);(void)ret;lastCode=(status>>8)&0xFF;lastSig=(status&0x7F);}return 0;
}
相关文章:

文件系统、描述符和缓冲区
目录 🏆一、文件系统 1、open ①对open接口的介绍 ②接口使用 2、write接口 3、read接口 🏆二、深入理解文件描述符fd 1、fd具体实质 2、文件fd的分配规则 3、fd重定向 ①输出重定向 ②追加重定向 ③输入重定向 ④文件的引用计数 🏆三…...

java微服务商城高并发秒杀项目--009.流控规则和降级规则
线程流控(只要线程数达到了指定数量,访问就会被流控):warm up流控效果(慢慢增加QPS的数量,之后最后达到阈值,这种情况下,一开始会容易限流,后期就不会限流了)…...

php编写的脚本,如何才能在windows系统运行呢?
咱们要在Windows系统上运行PHP脚本,需要安装PHP解释器和Web服务器。 以下是基本的步骤,很简单: 下载PHP解释器:可以从官方网站 https://windows.php.net/download/ 下载Windows版本的PHP解释器。根据你的操作系统和需要的版本选…...

政务综合服务平台建设项目方案书
本资料来源公开网络,仅供个人学习,请勿商用,如有侵权请联系删除 目 录 第一章 项目整体概述 1.1. 项目名称 1.2. 建设单位 1.3. 编写依据 1.3.1 相关政策 1.3.2 技术标准 1.4. 建设目标、规模、内容、建设期 1.4.1 建设目标 1.4.2 …...

python好玩的短代码
Python语言是一种流行的编程语言,在 Python语言中有很多有趣的特性,比如: 1.变量可以定义为字符串,也可以定义为字符串对象 2.变量可以用来初始化一个函数或模块,函数或者模块可以定义成一个类,这个类被称为…...

会Python如何学习C#的几个关键点
Python和C#都是常用的编程语言,但两者之间存在一些重要的区别。如果你已经掌握了Python并希望学习C#,以下是几个关键点: 面向对象编程(OOP):C#是一种严格的面向对象编程语言,而Python则具有更灵…...

索引失效原则与查询优化
数据库调优的维度: 索引建立SQL优化(本文重点)my.cnf的调整(线程数,缓存等)分库分表 SQL查询优化的技术从大方向上可以分为 物理查询优化,逻辑查询优化 物理查询优化:即通过建立索…...

读完这篇文章你就彻底了解了什么是AES算法
目录 导论 介绍加密算法的定义和基本概念 解释加密算法在现代通信和存储系统中的重要性...

ArrayDeque类常用方法
数据结构 ArrayDeque类是 双端队列的线性实现类。 具有以下特征: ArrayDeque是采用数组方式实现的双端队列。ArrayDeque的出队入队是通过头尾指针循环,利用数组实现的。ArrayDeque容量不足时是会扩容的,每次扩容容量增加一倍。ArrayDeque可…...

Leetcode.130 被围绕的区域
题目链接 Leetcode.130 被围绕的区域 mid 题目描述 给你一个 m x n的矩阵 board,由若干字符 X和 O,找到所有被 X围绕的区域,并将这些区域里所有的 O用 X填充。 示例 1: 输入:board [[“X”,“X”,“X”,“X”],[“X…...

MySQL-四大类日志
目录 🍁MySQL日志分为4大类 🍁错误日志 🍃修改系统配置 🍁二进制日志 🍃查看二进制日志 🍃删除二进制日志 🍃暂时停止二进制日志的功能 🍁事务日志(或称redo日志) 🍁慢查…...

新加坡量子软件公司Horizon完成1810万美元A轮融资
(图片来源:网络) 近期,Horizon宣布已完成来自印度红杉资本、腾讯、SGInnovate、Pappas Capital和Expeditions Fund的1810万美元A轮投资。 Horizon是一家开发新一代编程工具的公司,总部位于新加坡,它致力…...

Spring学习(四):Scope的介绍及其失效解决方案
目录 一、spring当中有哪些scope 二、scope初始化与销毁演示 2.1 scope的初始化 2.2 scope的销毁 三、scope失效及其解决方案 3.1 scope失效演示 3.2 scope失效解决方案一:Lazy 3.3 scope失效解决方案二:设置proxyMode属性 3.4 scope失效解决…...

【学习集合--Set】
学习内容: Set集合概述Set集合实现—HashSet LinkedHashSet和TreeSet 学习产出: Set集合概述 Set中不存在值相同的节点。将两个对象e1.equals(e2),如果结果为true,或者(e1e2)内存地址相等,就认为两个对象…...

函数的参数
函数的默认实参 函数默认参数:函数的形参可以有默认值,如果我们自己传入参数,就用自己的数据,如果没有,那么用默认值 特别注意*: 如果某个位置有了默认参数,那么从这个位置往后,必…...

数组(八)-- LC[53][152] 最大子数组之和与乘积最大子数组
1 最大子数组之和 1.1 题目描述 题目链接:https://leetcode.cn/problems/maximum-subarray/ 1.2 求解思路 1. 暴力法 class Solution:def maxSubArray(self, nums: List[int]) -> int:length len(nums)max_sum float(-inf)for i in range(length):sum_sub_…...

docker2-zabbix
安装最新版docker yum remove docker docker-common docker-selinux docker-engine yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo yum makecache fast yum list docker-ce --showduplicates | sort -r yum install docke…...

ctcdecode安装
1.下载 https://pan.baidu.com/s/1sZMbzzYtBoT35zHtDifVqQ ,提取码:a05y。然后解压到ctcdecode文件夹中。 感谢 ctcdecode安装_huangneng0219的博客-CSDN博客 提供。 然后build.py文件中的compile_args [-O3, -DKENLM_MAX_ORDER6, -stdc11, -fPIC] …...

虚树学习小记
虚树是什么 虚树指在原树上选择需要的点和它们的LCALCALCA组成的一棵树。这样可以使在树DP时顶点数更少,从而减少时间复杂度。一般用于有多组数据且能保证所有数据访问的点的和不超过规定范围。 情景代入:SDOI2011消耗战 SDOI2011消耗战 题目大意 给…...

【C++】特殊类设计(单例模式)
文章目录一、设计模式概念二、设计一个不能被拷贝的类三、设计一个只能在堆上创建对象的类3.1 私有构造3.2 私有析构四、设计一个只能在栈上创建对象的类五、设计不能被继承的类六、单例模式❗️❗️6.1 饿汉模式6.2 懒汉模式6.2.1 线程安全问题6.2.2 新写法一、设计模式概念 …...

基于YOLOv5的水下海洋目标检测
摘要:水下海洋目标检测技术具有广泛的应用前景,可以用于海洋环境监测、海洋资源开发、海洋生物学研究等领域。本文提出了一种基于 YOLOv5 的水下海洋目标检测方法,使用数据增强方法进行了大量实验,并与其他方法进行了对比…...

磁盘这列(Raid)
RAID介绍 RAID技术通过把多个硬盘设备组合成一个容量更大的、安全性更好的磁盘阵列。把数据切割成许多区段后分别放在不同的物理磁盘上,然后利用分散读写技术来提升磁盘阵列整体的性能,同时把多个重要数据的副本同步到不同的物理设备上,从而…...

Oracle之PL/SQL存储过程与函数练习题(七)
1.创建一个存储过程,以员工号为参数,输出该员工的工资2.创建一个存储过程,以员工号为参数,修改该员工的工资。若该员工属于10号部门,则工资增加150;若属于20号部门,则工资增加200;若…...

C++入门教程||C++ 基本的输入输出||C++ 数据结构
C 基本的输入输出 C 基本的输入输出 C 标准库提供了一组丰富的输入/输出功能,我们将在后续的章节进行介绍。本章将讨论 C 编程中最基本和最常见的 I/O 操作。 C 的 I/O 发生在流中,流是字节序列。如果字节流是从设备(如键盘、磁盘驱动器、…...

线性表——顺序表
文章目录一:线性表二:顺序表1:概念与结构1:静态顺序表2:动态顺序表2:动态顺序表的代码实现1:结构2:接口实现1:初始化2:释放内存3:检查容量4&#…...

第六章 Vite4+Vue3+Vtkjs 模型颜色切换、漫反射曲面颜色
一、介绍 💥 💥 Vtk里面工具非常的齐全,但是相关的文档又少之又少,只能花大量时间去阅读源码。漫反射曲面颜色是什么意思呢,Vtk可以使用漫反射曲面颜色来模拟光线在表面反射时的颜色。漫反射是一种光线与表面发生碰撞后,被散射到各个方向的现象,这种现象可以用来解释物…...

【QT学习七】QTreeWidget
目录 一、QTreeWidget 概述 二、QTreeWidget 的基本使用 2.1、创建 QTreeWidget 控件 2.2、设置 QTreeWidget 的大小和位置 2.3、设置 QTreeWidget 的列数和列标题 2.4、添加节点 2.5、读取节点 2.6、设置节点数据 2.7、自定义节点样式 三、注意事项 四、完整示例 一…...

【Linux】组管理和权限管理
目录1 Linux组的基本介绍2 文件/目录所有者2.1 查看文件的所有者2.2 修改文件所有者3 组的创建3.1 基本指令3.2 应用实例4 文件/目录 所在组4.1 查看文件/目录所在组4.2修改文件/目录所在的组5 其他组6 改变用户所在组6.1 改变用户所在的组6.2 应用实例7 权限介绍8 rwx权限详解…...

从零到一发布 NPM 包
如果你负责前端的基础能力建设,发布各种功能/插件包犹如家常便饭,所以熟悉对 npm 包的发布与管理是非常有必要的,故此有了本篇总结文章。本篇文章一方面总结,一方面向社区贡献开箱即用的 npm 开发、编译、发布、调试模板ÿ…...

uniapp国际化配置
1、创建资源文件 创建一个locale文件夹,新增index.js,en.json,zh-hans.json 2.配置locale文件夹中的index.js文件 import Vue from vue import VueI18n from vue-i18n// v8.x import en from ./en.json import zhHans from ./zh-Hans.json import zhHant from .…...