文章插图
剧本起因无意间用 vim 打开了一个 10 G 的文件 。改了一行内容 。:w 保存了一下 。慢的我哟 。耗费的时间够泡几杯茶了 。这引起了我的奇怪 。vim 打开和保存到底做了啥?
vim — 写器之神
vim 号称写器之神 。以极其厉害的扩展性和功能闻名 。vi/vim 作为标准的写器存在于 Linux 的几乎每一种发行版里 。vim 的学习曲线有那么一点陡峭的 。前期一定有一个磨炼的过程 。
vim 是一个终端写器 。在可视化的写器横行的今天 。怎么 vim 还如此重要?
因为一些场景非它不可 。例如线上服务器终端 。除 vi/vim 这种终端写器 。你别无选择 。
vim 的简史很悠久 。Github 有个文档归纳了 vim 的简史进程:vim 简史 。Github 开源代码:代码仓库 。
笔者今天不讲 vim 的用法 。这种文章网络随便搜一大把 。笔者将从 vim 的存储 IO 原理的角度来剖析下 vim 这种神器 。
思考几个小问题 。读者如果有兴趣 。应该继续往下读哦:
vim 写文件的原理是啥 。用了啥黑科技吗?
vim 打开一个 10G 的大型文件 。怎么怎么这么慢 。里面做了啥?
vim 改写一个 10G 的大型文件 。:w 保存的时候 。感觉更慢了?怎么?
vim 貌似会发生多余的文件?~ 文件 ?.swp 文件 ?都是做啥的呢?
划重要时机:由于 vim 的功能过于厉害 。一篇共享开始说不完 。本文文章聚焦 IO 。从存储的角度剖析 vim 原理 。
vim 的 io 原理声明 。系统和 Vim 版本如下:操作面板系统版本:Ubuntu 16.04.6 LTSVIM 版本:VIM – Vi IMproved 8.2 (2019 Dec 12, compiled Jul 25 2021 08:44:54)测试文件名:test.txt
vim 只是一个二进制程序而已 。读者朋友也应该 Github 安装 。编译 。自己调试哦 。效果更优质 。
往往一般使用 vim 写文件很无脑 。只要 vim 后面跟文件名就可:
vim test.txt这样就打开了文件 。并且应该进行写 。这种命令敲下去 。往往一般状态下 。我们就能很快在终端很观看到的文件的内容了 。
Linux 写器之神 vim 的 IO 存储原理
这种过程发生了什么?先明确下 。vim test.txt 到底是啥意思?
本质只是运行一个叫做 vim 的程序 。argv[1] 参数是 test.txt 嘛 。跟你曾经写的 helloworld 程序没啥不一样 。只不过 vim 这种程序应该终端人机交互 。
所以这种过程无非只是一个进程初始化的过程 。由 main 开始 。到 main_loop(后台循环监听) 。
1 vim 进程初始化vim 有一个 main.c 的入口文件 。main 函数就定义在这里 。首先会做一下操作面板系统有关的初始化( mch 是 machine 的缩写):
mch_early_init();
之后会 。做一下赋值参数 。全局变量的初始化:
/*
* Various initialisations shared with tests.
*/
common_init(?ms);
举个举例 test.txt 这样的参数必定要赋值到全局变量中 。因为未来是要总是使用的 。
另外类似于命令的 map 表 。是静态定义好了的:static struct cmdname
{
char_u*cmd_name;// name of the command
ex_func_T cmd_func;// function for this command
long_ucmd_argt;// flags declared above
cmd_addr_T cmd_addr_type; // flag for address type
} cmdnames [] = {
EXCMD(CMD_write, "write", ex_write,
EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_FILE1|EX_ARGOPT|EX_DFLALL|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
ADDR_LINES),
}
划重要时机::w 。:write 。:saveas 这样的 vim 命令 。其实是对应到定义好的 c 回调函数:ex_write。ex_write 函数是资料写入的核心函数 。再例如 。:quit 对应 ex_quit。用来退出的回调 。
换句话说 。vim 里面支持的类似 :w。的命令 。其实在初始化的时候就确认了 。人为的交互只是输入字符串 。vim 进程从终端读到字符串之后 。寻找对应的回调函数 。执行就可 。再来 。会初始化一些 home 目录 。目前目录等变量 。
init_homedir(); // find real value of $HOME
// 保存交互参数
set_argv_var(paramp->argv, paramp->argc);
配置一下跟终端窗口展现有关的东西 。这部分往往一般是一些终端库有关的:
// 初始化终端一些配置
termcapinit(params.term); // set terminal name and get terminal
// 初始化光标地点
screen_start(); // don't know where cursor is now
// 获取终端的一些消息
ui_get_shellsize(); // inits Rows and Columns
再来会加载 .vimrc 这样的配置文件 。让你的 vim 与众不一样 。
// Source startup scripts.
source_startup_scripts(?ms);
推荐阅读
- 茄子有什么做法少油又美味的吗?
- 准备换手机,现在哪款手机待机时间长,掉电慢?
- 想吃辣白菜,有哪些推荐?
- 2021年做什么生意比较赚钱好做 2021年最有机会挣钱的几个行业
- 大家都来说说配备4000毫安电池的手机一般续航时间有多久?哪个品牌的优化的比较省电?
- 头条里,你关注了别人,有人也会关注你,而有的不会,原因何在?
- 白茶品牌排行榜前十名单 十大白茶排行榜前十名品牌
- 哪款手机待机时间长,求推荐?
- 中国女排能够再创辉煌,是郎平的作用大还是朱婷的作用大?