基础IO(上)——Linux

news2024/11/27 8:34:27

文章目录

  • 1.储备知识
  • 2. 文件描述符
    • 2.1 c接口
    • 2.2 直接使用系统接口
    • 2.3 open函数返回值
    • 2.4 文件描述符fd
    • 2.5 周边文件
  • 3. 重定向
    • 3.1 输出重定向
    • 3.2 输出重定向
    • 3.3 追加重定向
    • 3.4 dup
  • 4. 如何理解一切皆文件?

1.储备知识

对文件的操作范畴:
在系统角度理解文件
文件 = 内容 + 属性(也是数据)
创建一个空文件也占空间
对文件的所有操作无外乎两种:对内容和对属性

c、c++程序会默认打开三个文件流:
标准输入:键盘 extern FILE *stdin;
标准输出:显示器 extern FILE *stdout;
标准错误:显示器 extern FILE *stderr;

linux下一切皆文件
感性认识:
曾经理解的文件:read、write
键盘和显示器可以被看做文件吗?可以
我从来没有打开过键盘和显示器文件,但是依旧能够直接使用scanf,fgets,printf,cout…
是因为c、c++程序会默认打开三个文件流

磁盘是硬件,只有操作系统才能真正的访问磁盘
文件在磁盘上放着,我们访问文件,需要先写代码然后编译生成exe最后运行,那么访问文件本质是谁在访问文件呢?
进程
进程访问文件是需要接口的
之前我们学习的接口是语言类的接口

  1. 要向硬件上写入,只有谁才有权利呢?(代码上)
    操作系统
  1. 如果普通用户也想向硬件写入呢?
    必须让OS提供接口
    提供文件类的系统调用接口

为什么文件类的系统调用接口之前从未接触过?
1). 因为之前学的是C语言,文件类的系统调用接口,比较难掌握,语言上对这些接口做一下封装,让接口更好被使用——>语言类接口
每个语言都会做封装,就会导致了不同的语言有不同的语言级别文件访问接口。但是底层用的都是系统接口。
为什么要学习os层面的接口?
linux中这样的接口只有一套
(os只有一个)
 

2). 跨平台:把所有平台的代码都实现一遍,条件编译,动态裁剪
如果语言不提供对文件的系统接口的封装,是不是所有访问文件的操作,都必须直接使用OS的接口?
是的
面对语言的客户,要不要访问文件呢?

一旦使用系统接口,编写所谓的文件代码,无法在其他平台中直接运行了。不具备跨平台性!
显示器和磁盘写入没有区别

什么叫做文件?
站在系统的角度,可以被input读取,或者能够output写出的设备就叫做文件
狭义文件:普通的磁盘文件
广义文件:显示器,键盘,网卡,声卡,显卡,磁盘……几乎所有的外设,都可以称之为文件。

 
 

2. 文件描述符

2.1 c接口

makefile

   myfile:myfile.c
     gcc -o $@ $^
   .PHONY:clean
     rm -f myfile                                  

w:从文件开始写
a:从结尾开始写

  1 #include <stdio.h>
  2 
  3 int main()
  4 {
  5   FILE *fp = fopen("log.txt","w");
  6   if(fp == NULL)
  7   {
  8     perror("fopen");
  9     return 1;
 10   }
 11   //进行文件操作
 12                                                                                
 13 
 14 
 15   fclose(fp);            
 16   return 0;
 17 }

此时在当前路径下,是否存在文件log.txt?——还没有,需要运行程序之后,log.txt才会被创建
log.txt是谁创建的?——os
会在哪里创建?——当前路径
当前路径:当一个进程运行起来的时候,每个进程都会记录自己当前所处的工作路径
在这里插入图片描述
 
写文件的接口

  1 #include <stdio.h>
  2 #include<unistd.h>
  3 #include<string.h>
  4           
  5 int main()
  6 {         
  7   FILE *fp = fopen("log.txt","w");
  8   if(fp == NULL)
  9   {       
 10     perror("fopen");
 11     return 1;
 12   }       
 13   //进行文件操作
 14   const char *s1 = "hello fwrite";
 15   fwrite(s1,strlen(s1),1,fp);
 16           
 17   const char *s2 = "hello fprintf";
 18   fprintf(fp,"%s",s2);
 19           
 20   const char *s3 = "hello fputs";
 21   fputs(s3,fp);
 22                                                                                
 23  
 24              
 25   fclose(fp);
 26   return 0;
 27 }

先删掉之前的log.txt,再运行程序
在这里插入图片描述

 const char *s1 = "hello fwrite\n";
   fwrite(s1,strlen(s1),1,fp);

要不要+1?fwrite(s1,strlen(s1)+1,1,fp);
不要。
\0结尾是C语言的规定,文件不用遵守
如果+1打印出来就会多了一个乱码
文件保存的是有效数据,/n只是标志结尾的标识符

fopen:

  1. 当以写(w)方式打开文件时,会先清空文件。
    用重定向方式写入:echo helloworld > log.txt
    想要清空:>log.txt
    在这里插入图片描述

2.以a方式打开文件是追加重定向,不会清空之前的内容
r
按行读取
fgets是C语言提供的接口 s(string)会自动在字符结尾添加\0

char line[64];
while(fgets(line,sizeof(line),fp) != NULL)
{
    fprintf(stdout,"%s",line);
}

三个标准输入输出流:
stdout
标准输入:键盘 extern FILE *stdin;
标准输出:显示器 extern FILE *stdout;
标准错误:显示器 extern FILE *stderr;
都叫做文件指针
一切皆文件

 
命令行参数:

int main(int argc,char *argv[])

 

2.2 直接使用系统接口

c库函数: fopen fclose fread fwrote
系统调用:open close read write
两者关系:上面的c库函数底层都是系统调用

宏定义:全大写
如何给函数传递标志位

 6 #define ONE 0x1//0000 0001
    7  #define TWO 0x2//0000 0010
    8  #define THREE 0x4//0000 0100
W>  9  
   10  
   11 void show(int flags)
   12 {
   13   if(flags & ONE) printf("hello one\n");
   14   if(flags & TWO) printf("hello two\n");    
   15   if(flags & THREE)  printf("hello three\n");    
   16 }                                                      
   17                                                        
   18 int main()                                             
   19 {                                                      
   20   show(ONE);                                           
   21   show(TWO);                                           
   22   show(ONE | TWO);                                     
   23   show(ONE | TWO | THREE);                             
   24   return 0;                                                                  
   25     

 

2.3 open函数返回值

file descriptor:文件描述符
返回值:成功:新打开的文件描述符失败:-1
 
接口介绍
open man 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_TRUNC:写之前清空文件
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR : 读,写打开
这三个常量,必须指定一个且只能指定一个
O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_APPEND: 追加写
mode_t理解:直接 man 手册,比什么都清楚。open 函数具体使用哪个,和具体应用场景相关,如目标文件不存在,需要open创建,则第三个参数表示创建文件的默认权限,否则,使用两个参数的open
write read close lseek ,类比C文件相关接口

 

2.4 文件描述符fd

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;
}
FILE *fopen(const char *path,const char *mode);

FILE是一个struct的结构体,由c标准库提供
结构体内部会有多种成员
而在系统角度只认fd。
所以FILE结构体必定封装了fd
_fileno

 

2.5 周边文件

fd是什么?
之前说过进程要访问文件,必须先打开文件。
那么一个进程可以打开多个文件吗?
一般而言,进程:打开的文件 = 1:n

文件要被访问,前提是要被加载到内存中,才能直接被访问
进程:打开的文件 = 1:n 如果是多个进程都打开直接的文件呢?
系统中就会存在大量的被打开的文件,所以OS要把如此之多的文件管理起来:
先描述,再组织!

文件的属性从哪里来?
一部分在对应的磁盘中
所以在内核中,OS内部要管理每一个被打开的文件,需要构建结构体

struct file
{
    struct file * next;
    struct file * prev;
    //包含了一个被打开的文件的几乎所有的内容(不仅仅包含属性)
}

创建struct file的对象,充当一个被打开的文件。如果有很多再用双链表组织起来
文件对象里面包含了文件的所有内容
fd在内核中,本质是一个数组下标!

文件:
1.被进程在内存中打开的文件(执行你的代码的一定是CPU)
2.没有被打开的文件(在磁盘上,文件=内容+属性)(磁盘文件)
进程控制块:PCB struct task_struct

fopen——open——fd——FLIE——FILE*
fwrite()——FILE*——fd——write——write(fd,…)——自己执行操作系统内部的write方法——能找到进程的task_struct——*fs——file_struct——fd_arry[fd]——structfile——内存文件被找到了——操作

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

 
 

3. 重定向

3.1 输出重定向

 1 myfile:myfile.c
  2   gcc -o $@ $^
  3 .PHONY:clean
  4 clean:                                                                         
  5   rm -f myfile
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>
int main()
{
int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC);
if (fd < 0)
{
perror("open");
return 1;
}
printf("fd: %d\n", fd);

close(fd);
return 0;
}

此时fd是3
因为012已结被提前占用了

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>
int main()
{
int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);
if (fd < 0)
{
perror("open");
return 1;
}
printf("fd: %d\n", fd);

close(fd);
return 0;
}
fd:也是3
close(0);

fd:0
close(2)
fd:2
结论:
fd在系统层面的分配规则是:最小的,没有被占用的文件描述符

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

close(fd);
return 0;
}

不显示了

处理:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>
int main()
{
close(1);

int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);
if (fd < 0)
{
perror("open");
return 1;
}
printf("fd: %d\n", fd);
printf("fd: %d\n", fd);
printf("fd: %d\n", fd);
printf("fd: %d\n", fd);
printf("fd: %d\n", fd);

//close(fd);
return 0;
}

printf默认是往stdout
运行./myfile时依旧不显示
但是cat log.txt时有内容,打印了fd:1
确实是之前所说的fd分配原则

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>
int main()
{
close(1);

int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);
if (fd < 0)
{
perror("open");
return 1;
}
printf("fd: %d\n", fd);
printf("fd: %d\n", fd);
printf("fd: %d\n", fd);
printf("fd: %d\n", fd);
printf("fd: %d\n", fd);
fprintf(stdout, "hello fprintf\n");
const char *s = "hello fwrite\n";
fwrite(s, strlen(s), 1, stdout);

fflush(stdout);

close(fd);
return 0;
}

这些接口都应该是往显示器(标准输出)打印的
但是下面的内容都写入(显示)到了log.txt
这就叫做输出重定向

重定向的本质:
就是在OS内部更改fd对应的内容的指向

 

3.2 输出重定向

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>


int main()
{
int fd = open("log.txt", O_RDONLY);
if (fd < 0)
{
perror("open");
return 1;
}
printf("fd: %d\n", fd);

char buffer[64];
fgets(buffer, sizeof buffer, stdin);

printf("%s\n", buffer);

return 0;
}

fd:3
输入hello
输出hello

close(0);

fd:0
aaaaaaaaaaaaaa
本来应该从键盘读取的内容,却直接读取log.txt中的内容
这是输入重定向

 

3.3 追加重定向

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>


int main()
{
close(1);
int fd = open("log.txt", O_WRONLY | O_TRUNC | O_CREAT);
if (fd < 0)
{
perror("open");
return 1;
}
fprintf(stdout, "you can see me, success\n");

return 0;
}

./myfile
cat log.txt
you can see me,success
再运行,打印也只有一行

int main()
{
close(1);
//int fd = open("log.txt", O_WRONLY | O_TRUNC | O_CREAT);
int fd = open("log.txt", O_WRONLY | O_APPEND | O_CREAT);
if (fd < 0)
{
perror("open");
return 1;
}
fprintf(stdout, "you can see me, success\n");

return 0;
}

./myfile
./myfile
./myfile
./myfile
you can see me,success
you can see me,success
you can see me,success
you can see me,success
运行几次,追加几次 这就是追加重定向

 

3.4 dup

oldfd copu to newfd
最终要和oldfd一样,那么newfd就没有意义了,就可以关闭了

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>


int main(int argc, char *argv[])
{
if (argc != 2)
{
return 2
}
int fd = open("log.txt", O_WRONLY | O_TRUNC | O_CREAT);
if (fd < 0)
{
perror("open");
return 1;
}

fprintf(stdout, "%s\n", argv[1]);
return 0;
}

退出码:2
./myfile 105
105

int main(int argc, char *argv[])
{
if (argc != 2)
{
return 2
}
int fd = open("log.txt", O_WRONLY | O_TRUNC | O_CREAT);
if (fd < 0)
{
perror("open");
return 1;
}

dup2(fd, 1);
fprintf(stdout, "%s\n", argv[1]);
return 0;
}

./myfile hello
不显示
cat log.txt
hello
想显示的内容都会被打印到文件中而不是在显示器中

int main(int argc, char *argv[])
{
if (argc != 2)
{
return 2
}
//int fd = open("log.txt", O_WRONLY | O_TRUNC | O_CREAT);
int fd = open("log.txt", O_WRONLY | O_APPEND | O_CREAT);
if (fd < 0)
{
perror("open");
return 1;
}

dup2(fd, 1);
fprintf(stdout, "%s\n", argv[1]);
return 0;
}

./myfile
./myfile aaa
./myfile bbb
cat log.txt
aaa
bbb
追加

int main(int argc, char *argv[])
{
if (argc != 2)
{
return 2
}
//int fd = open("log.txt", O_WRONLY | O_TRUNC | O_CREAT);
int fd = open("log.txt", O_WRONLY | O_APPEND | O_CREAT);
if (fd < 0)
{
perror("open");
return 1;
}

dup2(fd, 1);
fprintf(stdout, "%s\n", argv[1]);
close(fd);
return 0;
}

依旧可以显示
这是dup2的一种特性,与缓冲区有关

 
 

4. 如何理解一切皆文件?

理性理解:
这是linux的设计哲学,体现在os的软件设计层面
 
linux是用C语言写的,那么如何用C语言实现面向对象,甚至是运行时多态?
类:所有事物与属性的结合
成员属性+成员方法
struct:可以包含成员属性,但是在纯C语言中不包含成员方法
但是我想让struct中包含成员方法呢?
可以定义函数指针,指向函数,去调用就可以了

底层不同的硬件,一定对应的是不同的操作方法
但是上面的设备都是外设,所以每一个设备的核心访问函数都可以是read、write(I、O)
所有的设备都可以有自己的read和write,但是代码的实现一定不一样!
设计一个struct,打开一个磁盘文件的时候,创建一个struct file
各自指向各自的
在这一层上面看,没有任何的硬件差别了,看待所有文件的方式,都统一成为了struct file
所以就有了linux下一切皆文件的说法
VFS虚拟文件技术

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

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

相关文章

R语言生物群落数据统计分析

R 语言作的开源、自由、免费等特点使其广泛应用于生物群落数据统计分析。生物群落数据多样而复杂&#xff0c;涉及众多统计分析方法。本教学以生物群落数据分析中的最常用的统计方法回归和混合效应模型、多元统计分析技术及结构方程等数量分析方法为主线&#xff0c;通过多个来…

中医-通过舌象判断身体状况

本文分享通过舌象判断身体的整体状况&#xff08;中医角度&#xff09;&#xff0c;得出一个可供辨证的参考&#xff0c;并且可以根据舌象做出相关的饮食调整&#xff0c;本文主讲理论&#xff0c;相关舌象图片易引人不适&#xff0c;如需找相关图片&#xff0c;可根据本文中的…

【SpringBoot】一文了解SpringBoot配置高级

文章目录前言ConfigurationProperties使用场景小结宽松绑定/松散绑定&#x1f315;博客x主页&#xff1a;己不由心王道长&#x1f315;! &#x1f30e;文章说明&#xff1a;SpringBoot配置高级&#x1f30e; ✅系列专栏&#xff1a;SpringBoot &#x1f334;本篇内容&#xff1…

javaweb JavaScript快速入门 对象 BOM DOM 事件监听

JavaScript 引入方式 1.内部脚本&#xff1a;将 JS代码定义在HTML页面中 2.外部脚本&#xff1a;将 JS代码定义在外部 JS文件中&#xff0c;然后引入到 HTML页面中 JavaScript 基础语法 windows.alert可以省略windows var: 1.作用域为全局变量 2.变量可以重复定义 &#xf…

半桥LLC谐振变换器及同步整流MATLAB仿真(一)

在开关电源中&#xff0c;LLC谐振变换器是最常见的DC-DC变换器之一。 LLC谐振电路早在上世纪80年代就已经提出&#xff0c;到如今仍有广泛的应用&#xff0c;可见其优越性。其优点表现在&#xff1a; 1.LLC的开关器件能实现软开关&#xff0c;开关损耗小 2.效率高、功率密度大 …

[附源码]计算机毕业设计JAVA 宠物医院管理系统

[附源码]计算机毕业设计JAVA 宠物医院管理系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybati…

计算结构体大小(内存对齐原则)struct、union、class

这篇博客详细的介绍结构体的大小sizeof&#xff1a;union、struct、class。 一、不同数据类型所占的内存大小&#xff1a; 二、union联合体的结构体大小 1、关注点&#xff1a; &#xff08;1&#xff09;联合体的大小为所有成员变量中所占字节数最大的&#xff1b; &#xf…

【Redis 常用五大数据类型】

常用五大数据类型 官方获取redis常见数据类型操作命令&#xff1a; http://www.redis.cn/commands.html 1.Redis键(key) keys * 查看当前库所有key (匹配&#xff1a;keys *1) exists key 判断某个key是否存在 type key 查看你的key是什么类型 del key 删除指定的key数据 unli…

springmvc1:初探springmvc

一.springmvc简介 1.springmvc是什么&#xff1f; ①mvc解释 m&#xff1a;模型层&#xff08;javabean处理数据&#xff09;例如pojo类 Service或Daov&#xff1a;视图层&#xff08;页面展示数据&#xff09;c&#xff1a;控制层&#xff08;接受请求和响应浏览器&#xf…

python基于PHP+MySQL 校园二手闲置商品交易系统

每年我国都有几百万的学生参加高考,当学生接到高校的录入通知书的那一刻就要学会独立生活了,大多数学生一般都要奔袭到离家几百设置几千公里之外的地方进行求学,这对初次离开父母远离家乡求学的学子来说是人生的一次挑战。为了能够更好的适应高校的环境,他们的入校之初或者在日…

【Qt】QMainWindow |QDialog对话框

文章目录1、QMainWindow1.1 菜单栏1.2 工具栏1.3 状态栏1.4 停靠部件1.5 核心部件&#xff08;中心部件&#xff09;1.6 使用UI文件创建窗口1.6.1 UI设计窗口介绍1.6.2 菜单1.1.6.1 添加/删除菜单栏1.1.6.2 添加菜单1.1.6.3 添加菜单项1.1.6.4 添加多级菜单1.6.3 工具1.1.6.1 添…

机器学习入门(六)神经网络初识

目录 一、模型解释 1.1 用人脑解释 1.2 用模型解释 二、通过异或门的神经网络理解偏置量、神经网络的传播 2.1 与门的神经网络表示 2.2 或门的神经网络表示 2.3 异或门的神经网络表示 三、多物体分类 一、模型解释 1.1 用人脑解释 神经网络是模拟人的神经元&#…

Windows上的实用CMD命令

Windows上的实用CMD命令查看系统信息是x64位查看电脑基本诊断信息检查电脑支持的最大运行内存查看内存信息查看Windows电脑上次的启动时间查看显卡信息查看电脑当前的用户名查看当前的用户是不是电脑的管理员用户查看路由信息 route print查看Windows 的version申明&#xff1a…

从心灰意冷到自学Java3个月顺利拿到offer,多亏这份文档

跳槽时时刻刻都在发生&#xff0c;但是我建议大家跳槽之前&#xff0c;先想清楚为什么要跳槽。切不可跟风&#xff0c;看到同事一个个都走了&#xff0c;自己也盲目的开始面试起来&#xff08;期间也没有准备充分&#xff09;&#xff0c;到底是因为技术原因&#xff08;影响自…

Allegro172版本Shape避让方形盘不出现弧形操作指导

Allegro172版本Shape避让方形盘不出现弧形操作指导 Allegro172版本避让方形焊盘的时候,不会像166版本一样避让成方形,如下图 只需要按照下面的操作就可以实现和166版本方形避让一样的效果 打开shape Global dynamic parameter 选择Void Controls Rectangle pad viod cor…

java常见题

1.数组和链表结构简单对比&#xff1f;&#xff08;ArrayList和linkedList&#xff09; 数组是一段连续的空间。 大小固定 可能大小不够用或者有浪费 数组查询比较方便&#xff0c;根据下标就可以直接找到元素&#xff0c;时间复杂度O(1)&#xff1b;增加和删除比较复杂&…

“双11”来了!企企通B2B商城助力打造供销一体数字化解决方案

今年的“双11”&#xff0c;比往年来得更早。10月20日晚上8点&#xff0c;双11第一波预售开启。电商平台的竞争愈发激烈&#xff0c;直播卖货的崛起更是加重了行业的竞争压力。但淘宝、天猫、京东这类传统的电商平台因其完善且成熟的供应链&#xff0c;使得双11淘宝系主场格局不…

Redis进行RCE利用总结

https://www.cnblogs.com/loongten/p/15838580.html 0x00 简要说明 百度百科&#xff1a;Redis&#xff08;Remote Dictionary Server )&#xff0c;即远程字典服务&#xff0c;是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库&am…

什么才是好代码?

定义代码质量高低&#xff0c;本来就是主观的&#xff0c;更多的是出于判断。为了做出更客观的评判&#xff0c;我个人 认为有益的做法是后退一步&#xff0c;考虑一下编写代码时真正试图实现的目标。在我看来&#xff0c;帮助我实现这些目标的代码就是高质量的&#xff0c;而产…

ECMAScript 6 语法 1 —— 块作用域构造let 和 const

Javascript 的作用域存在的两种情况 情况一&#xff1a;函数内部 function enterYourChoice(flag){// var有变量提升的作用&#xff0c;相当于在此处写了一个 let choice;if(flag){var choice "yes";}else {console.log(choice); // undefined 并没有报错哦&#…