故事起因
無(wú)意間用 vim 打開(kāi)了一個(gè) 10 G 的文件,改了一行內(nèi)容,:w 保存了一下,慢的我喲,耗費(fèi)的時(shí)間夠泡幾杯茶了。這引起了我的好奇,vim 打開(kāi)和保存究竟做了啥?
vim — 編輯器之神
vim 號(hào)稱編輯器之神,以極其強(qiáng)大的擴(kuò)展性和功能聞名。vi/vim 作為標(biāo)準(zhǔn)的編輯器存在于 Linux 的幾乎每一種發(fā)行版里。vim 的學(xué)習(xí)曲線比較陡峭的,前期必須有一個(gè)磨煉的過(guò)程。
vim 是一個(gè)終端編輯器,在可視化的編輯器橫行的今天,為什么 vim 還如此重要?
因?yàn)?strong>有些場(chǎng)景非它不可,比如線上服務(wù)器終端,除 vi/vim 這種終端編輯器,你別無(wú)選擇。
vim 的歷史很悠久,Github 有個(gè)文檔歸納了 vim 的歷史進(jìn)程:vim 歷史,Github 開(kāi)源代碼:代碼倉(cāng)庫(kù)。
筆者今天不講 vim 的用法,這種文章網(wǎng)上隨便搜一大把。筆者將從 vim 的存儲(chǔ) IO 原理的角度來(lái)剖析下 vim 這個(gè)神器。
思考幾個(gè)小問(wèn)題,讀者如果感興趣,可以繼續(xù)往下讀哦:
vim 編輯文件的原理是啥,用了啥黑科技嗎?
vim 打開(kāi)一個(gè) 10G 的大型文件,為什么這么慢,里面做了啥?
vim 修改一個(gè) 10G 的大型文件,:w 保存的時(shí)候,感覺(jué)更慢了?為什么?
vim 好像會(huì)產(chǎn)生多余的文件?~ 文件 ?.swp 文件 ?都是做啥的呢?
劃重點(diǎn):由于 vim 的功能過(guò)于強(qiáng)大,一篇分享根本說(shuō)不完,本篇文章聚焦 IO,從存儲(chǔ)的角度剖析 vim 原理。
vim 的 io 原理
聲明,系統(tǒng)和 Vim 版本如下:
操作系統(tǒng)版本:Ubuntu 16.04.6 LTSVIM 版本:VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Jul 25 2021 0854)測(cè)試文件名:test.txt
vim 就是一個(gè)二進(jìn)制程序而已。讀者朋友也可以 Github 下載,編譯,自己調(diào)試哦,效果更佳。
一般使用 vim 編輯文件很簡(jiǎn)單,只需要 vim 后面跟文件名即可:
vimtest.txt
這樣就打開(kāi)了文件,并且可以進(jìn)行編輯。這個(gè)命令敲下去,一般情況下,我們就能很快在終端很看到文件的內(nèi)容了。
這個(gè)過(guò)程發(fā)生了什么?先明確下,vim test.txt 到底是啥意思?
本質(zhì)就是運(yùn)行一個(gè)叫做 vim 的程序,argv[1] 參數(shù)是 test.txt 嘛。跟你以前寫(xiě)的 helloworld 程序沒(méi)啥不一樣,只不過(guò) vim 這個(gè)程序可以終端人機(jī)交互。
所以這個(gè)過(guò)程無(wú)非就是一個(gè)進(jìn)程初始化的過(guò)程,由 main 開(kāi)始,到 main_loop(后臺(tái)循環(huán)監(jiān)聽(tīng))。
1vim 進(jìn)程初始化
vim 有一個(gè) main.c 的入口文件,main 函數(shù)就定義在這里。首先會(huì)做一下操作系統(tǒng)相關(guān)的初始化( mch 是 machine 的縮寫(xiě)):
mch_early_init();
然后會(huì),做一下賦值參數(shù),全局變量的初始化:
/* *Variousinitialisationssharedwithtests. */ common_init(¶ms);
舉個(gè)例子 test.txt 這樣的參數(shù)必定要賦值到全局變量中,因?yàn)橐院笫且?jīng)常使用的。
另外類(lèi)似于命令的 map 表,是靜態(tài)定義好了的:
staticstructcmdname { char_u*cmd_name;//nameofthecommand ex_func_Tcmd_func;//functionforthiscommand long_ucmd_argt;//flagsdeclaredabove cmd_addr_Tcmd_addr_type;//flagforaddresstype }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), }
劃重點(diǎn)::w,:write,:saveas 這樣的 vim 命令,其實(shí)是對(duì)應(yīng)到定義好的 c 回調(diào)函數(shù):ex_write 。 ex_write 函數(shù)是數(shù)據(jù)寫(xiě)入的核心函數(shù)。再比如,:quit 對(duì)應(yīng) ex_quit ,用于退出的回調(diào)。
換句話說(shuō),vim 里面支持的類(lèi)似 :w ,的命令,其實(shí)在初始化的時(shí)候就確定了。人為的交互只是輸入字符串,vim 進(jìn)程從終端讀到字符串之后,找到對(duì)應(yīng)的回調(diào)函數(shù),執(zhí)行即可。再來(lái),會(huì)初始化一些 home 目錄,當(dāng)前目錄等變量。
init_homedir();//findrealvalueof$HOME //保存交互參數(shù) set_argv_var(paramp->argv,paramp->argc);
配置一下跟終端窗口顯示相關(guān)的東西,這部分主要是一些終端庫(kù)相關(guān)的:
//初始化終端一些配置 termcapinit(params.term);//setterminalnameandgetterminal //初始化光標(biāo)位置 screen_start();//don'tknowwherecursorisnow //獲取終端的一些信息 ui_get_shellsize();//initsRowsandColumns
再來(lái)會(huì)加載 .vimrc 這樣的配置文件,讓你的 vim 與眾不同。
//Sourcestartupscripts. source_startup_scripts(¶ms);
還會(huì)加載一些 vim 插件 source_in_path ,使用 load_start_packages 加載 package 。
下面這個(gè)就是第一個(gè)交互了,等待用戶敲下 enter 鍵:
wait_return(TRUE);
我們經(jīng)??匆?jiàn)的:“Press ENTER or type command to continue“ 就是在這里執(zhí)行的。確認(rèn)完,就說(shuō)明你真的是要打開(kāi)文件,并顯示到終端了。
怎么打開(kāi)文件?怎么顯示字符到終端屏幕?
這一切都來(lái)自于 create_windows 這個(gè)函數(shù)。名字也很好理解,就是初始化的時(shí)候創(chuàng)建終端窗口來(lái)著。
/* *Createtherequestednumberofwindowsandeditbuffersinthem. *Alsodoesrecoveryif"recoverymode"set. */ create_windows(¶ms);
這里其實(shí)涉及到兩個(gè)方面:
把數(shù)據(jù)讀出來(lái),讀到內(nèi)存;
把字符渲染到終端;
怎么把數(shù)據(jù)從磁盤(pán)上讀出來(lái),就是 IO。怎么渲染到終端這個(gè)我們不管,這個(gè)使用的是 termlib 或者 ncurses 等終端編程庫(kù)來(lái)實(shí)現(xiàn)的,感興趣的可以了解下。
這個(gè)函數(shù)會(huì)調(diào)用到我們的第一個(gè)核心函數(shù):open_buffer ,這個(gè)函數(shù)做兩個(gè)時(shí)間:
create memfile:創(chuàng)建一個(gè) memory + .swp 文件的抽象層,讀寫(xiě)數(shù)據(jù)都會(huì)過(guò)這一層;
read file:讀原始文件,并解碼(用于顯示到屏幕);
函數(shù)調(diào)用棧:
->readfile ->open_buffer ->create_windows ->vim_main2 ->main
真正干活的是 readfile 這個(gè)函數(shù),吐槽一下,readfile 是一個(gè) 2533 行的函數(shù)。。。。。。
readfile 里面會(huì)擇機(jī)創(chuàng)建 swp 文件(以前有的話,可以用于恢復(fù)數(shù)據(jù)),調(diào)用的是 ml_open_file 這個(gè)函數(shù),文件創(chuàng)建好之后,size 占用 4k,里面主要是一些特定的元數(shù)據(jù)(用來(lái)恢復(fù)數(shù)據(jù)用的)。
劃重點(diǎn):.{文件名}.swp 這個(gè)隱藏文件是有格式的,前 4k 為 header,后面的內(nèi)容也是按照一個(gè)個(gè)block 組織的。
再往后走,會(huì)調(diào)用到 read_eintr 這個(gè)函數(shù),讀取數(shù)據(jù)的內(nèi)容:
long read_eintr(intfd,void*buf,size_tbufsize) { longret; for(;;){ ret=vim_read(fd,buf,bufsize); if(ret>=0||errno!=EINTR) break; } returnret; }
這是一個(gè)最底層的函數(shù),是系統(tǒng)調(diào)用 read 的一個(gè)封裝,讀出來(lái)之后。這里回答了一個(gè)關(guān)鍵問(wèn)題:vim 的存儲(chǔ)原理是啥?
劃重點(diǎn):本質(zhì)上調(diào)用 read,write,lseek 這樣樸素的系統(tǒng)調(diào)用,而已。
readfile 會(huì)把二進(jìn)制的數(shù)據(jù)讀出來(lái),然后進(jìn)行字符轉(zhuǎn)變編碼(按照配置的模式),編碼不對(duì)就是亂碼嘍。每次都是按照一個(gè)固定 buffer 讀數(shù)據(jù)的,比如 8192 。
劃重點(diǎn):readfile 會(huì)讀完文件。這就是為什么當(dāng) vim 打開(kāi)一個(gè)超大文件的時(shí)候,會(huì)非常慢的原因。
這里提一點(diǎn)題外話:memline 這個(gè)封裝是文件之上的,vim 修改文件是修改到內(nèi)存 buffer ,vim 按照策略來(lái) sync memfile 到 swp 文件,一個(gè)是防止丟失未保存的數(shù)據(jù),第二是為了節(jié)省內(nèi)存。
mf_write 把內(nèi)存數(shù)據(jù)寫(xiě)到文件。在 .test.txt.swp 中的就是這樣的數(shù)據(jù)結(jié)構(gòu):
block 0 的 header 主要標(biāo)識(shí):
vim 的版本;
編輯文件的路徑;
字符編碼方式;
這里實(shí)現(xiàn)提一個(gè)重要知識(shí)點(diǎn):swp 文件里存儲(chǔ)的是 block,block 的管理是以一個(gè)樹(shù)形結(jié)構(gòu)進(jìn)行管理的。block 有 3 種類(lèi)型:
block0:頭部 4k ,主要是存儲(chǔ)一些文件的元數(shù)據(jù),比如路徑,編碼模式,時(shí)間戳等等;
pointer block:樹(shù)形內(nèi)部節(jié)點(diǎn);
data block:樹(shù)形葉子節(jié)點(diǎn),存儲(chǔ)用戶數(shù)據(jù);
2敲下 :w 背后的原理
進(jìn)程初始化我們講完了,現(xiàn)在來(lái)看下 :w 觸發(fā)的調(diào)用吧。用戶敲下 :w 命令觸發(fā) ex_write 回調(diào)(初始化的時(shí)候配置好的)。所有的流程皆在 ex_write ,我們來(lái)看下這個(gè)函數(shù)做了什么。
先撇開(kāi)代碼實(shí)現(xiàn)來(lái)說(shuō),用戶敲下 :w 命令其實(shí)只是想保存修改而已。
那么第一個(gè)問(wèn)題?用戶的修改在哪里?
在 memline 的封裝,只要沒(méi)執(zhí)行過(guò) :w 保存,那么用戶的修改就沒(méi)修改到原文件上(注意哦,沒(méi)保存之前,一定沒(méi)修改原文件哦),這時(shí)候,用戶的修改可能在內(nèi)存,也可能在 swp 文件。存儲(chǔ)的數(shù)據(jù)結(jié)構(gòu)為 block 。所以,:w 其實(shí)就是把 memline 里面的數(shù)據(jù)刷到用戶文件而已。怎么刷?
重點(diǎn)步驟如下(以 test.txt 舉例):
創(chuàng)建一個(gè) backup 文件( test.txt~ ),把原文件拷貝出來(lái);
把原文件 test.txt truancate 截?cái)酁?0,相當(dāng)于清空原文件數(shù)據(jù);
從 memline (內(nèi)存 + .test.txt.swp)拷貝數(shù)據(jù),重新寫(xiě)入原文件 test.txt;
刪除備份文件 test.txt~;
以上就是 :w 做的所有事情了,下面我們看下代碼。
觸發(fā)的回調(diào)是 ex_write ,核心的函數(shù)是 buf_write ,這個(gè)函數(shù) 1987 行。
在這函數(shù),會(huì)使用 mch_open 創(chuàng)建一個(gè) backup 文件,名字后面帶個(gè) ~ ,比如 test.txt~ ,
bfd=mch_open((char*)backup
拿到 backup 文件的句柄,然后拷貝數(shù)據(jù)(就是一個(gè)循環(huán)嘍), 每 8K 操作一次,從 test.txt 拷貝到 test.txt~ ,以做備份。
劃重點(diǎn):如果是 test.txt 是超大文件,那這里就慢了哦。
backup 循環(huán)如下:
//buf_write while((write_info.bw_len=read_eintr(fd,copybuf,WRITEBUFSIZE))>0) { if(buf_write_bytes(&write_info)==FAIL) //如果失敗,則終止 //否則直到文件結(jié)束 } }
我們看到,干活的是 buf_write_bytes ,這是 write_eintr 的封裝函數(shù),其實(shí)也就是系統(tǒng)調(diào)用 write 的函數(shù),負(fù)責(zé)寫(xiě)入一個(gè) buffer 的數(shù)據(jù)到磁盤(pán)文件。
longwrite_eintr(intfd,void*buf,size_tbufsize){ longret=0; longwlen; while(ret(long)bufsize)?{ ????????//?封裝的系統(tǒng)調(diào)用?write? ????????wlen?=?vim_write(fd,?(char?*)buf?+?ret,?bufsize?-?ret); ????????if?(wlen?0)?{ ????????????if?(errno?!=?EINTR) ????????????break; ????????}?else ????????????ret?+=?wlen; ????} ????return?ret; }
backup 文件拷貝完成之后,就可以準(zhǔn)備動(dòng)原文件了。
思考:為什么要先文件備份呢?
留條后路呀,搞錯(cuò)了還有的恢復(fù),這個(gè)才是真正的備份文件。
修改原文件之前的第一步,ftruncate 原文件到 0,然后,從 memline (內(nèi)存 + swp)中拷貝數(shù)據(jù),寫(xiě)回原文件。
劃重點(diǎn):這里又是一次文件拷貝,超大文件的時(shí)候,這里可能巨慢哦。
for(lnum=start;lnum<=?end;?++lnum) { ????//?從?memline?中獲取數(shù)據(jù),返回一個(gè)內(nèi)存?buffer(?memline?其實(shí)就是內(nèi)存和?swap?文件的一個(gè)封裝) ????ptr?=?ml_get_buf(buf,?lnum,?FALSE)?-?1; ????//?將這個(gè)內(nèi)存?buffer?寫(xiě)到原文件 ????if?(buf_write_bytes(&write_info)?==?FAIL) ????{ ????????end?=?0;????????//?write?error:?break?loop ????????break; ????} ????//?... }
劃重點(diǎn):vim 并不是調(diào)用 pwrite/pread 這樣的調(diào)用來(lái)修改原文件,而是把整個(gè)文件清空之后,copy 的方式來(lái)更新文件。漲知識(shí)了。
這樣就完成了文件的更新啦,最后只需要?jiǎng)h掉 backup 文件即可。
//Removethebackupunless'backup'optionissetortherewasa //conversionerror. mch_remove(backup);
這個(gè)就是我們數(shù)據(jù)寫(xiě)入的完整流程啦。是不是沒(méi)有你想的那么簡(jiǎn)單!
簡(jiǎn)單小結(jié)下:當(dāng)修改了 test.txt 文件,調(diào)用 :w 寫(xiě)入保存數(shù)據(jù)的時(shí)候發(fā)生了什么?
人機(jī)交互,:w 觸發(fā)調(diào)用 ex_write 回調(diào)函數(shù),于 do_write -> buf_write 完成寫(xiě)入 ;
具體操作是:先備份一個(gè) test.txt~ 文件出來(lái)(全拷貝);
接著,原文件 test.txt 截?cái)酁?0,從 memline( 即 內(nèi)存最新數(shù)據(jù) + .test.txt.swap 的封裝)拷貝數(shù)據(jù),寫(xiě)入 test.txt (全拷貝) ;
數(shù)據(jù)組織結(jié)構(gòu)
之前講的太細(xì)節(jié),我們從數(shù)據(jù)組織的角度來(lái)解釋下。vim 針對(duì)用戶對(duì)文件的修改,在原文件之上,封裝了兩層抽象:memline,memfile 。分別對(duì)應(yīng)文件 memline.c ,memfile.c 。
先說(shuō) memline 是啥?
對(duì)應(yīng)到文本文件中的每一行,memline 是基于 memfile 的。
memline 基于 memfile,那 memfile 又是啥?
這個(gè)是一個(gè)虛擬內(nèi)存空間的實(shí)現(xiàn),vim 把整個(gè)文本文件映射到內(nèi)存中,通過(guò)自己管理的方式。這里的單位為 block,memfile 用二叉樹(shù)的方式管理 block 。block 不定長(zhǎng),block 由 page 組成,page 為定長(zhǎng) 4k 大小。
這是一個(gè)典型虛擬內(nèi)存的實(shí)現(xiàn)方案,編輯器的修改都體現(xiàn)為對(duì) memfile 的修改,修改都是修改到 block 之上,這是一個(gè)線性空間,每個(gè) block 對(duì)應(yīng)到文件的要給位置,有 block number 編號(hào),vim 通過(guò)策略會(huì)把 block 從內(nèi)存中換出,寫(xiě)入到 swp 文件,從而節(jié)省內(nèi)存。這就是 swap 文件的名字由來(lái)。
block 區(qū)分 3 種類(lèi)型:
block 0 塊:樹(shù)的根,文件元數(shù)據(jù);
pointer block:樹(shù)的分支,指向下一個(gè) block;
data block:樹(shù)的葉子節(jié)點(diǎn),存儲(chǔ)用戶數(shù)據(jù);
swap 文件組織:
block 0 是特殊塊,結(jié)構(gòu)體占用 1024 個(gè)字節(jié)內(nèi)存,寫(xiě)到文件是按照 1 個(gè)page 對(duì)齊的,所以是 4096 個(gè)字節(jié)。如下圖:
block 其他兩種類(lèi)型:
pointer 類(lèi)型:這個(gè)是中間的分支節(jié)點(diǎn),指向 block 的;
data 類(lèi)型:這個(gè)是葉子節(jié)點(diǎn);
#defineDATA_ID(('d'<8)?+?'a')???//?data?block?id #define?PTR_ID????????(('p'?<8)?+?'t')???//?pointer?block?id
這個(gè) ID 相當(dāng)于魔數(shù),在 swp 文件中很容易識(shí)別出來(lái),比如在下面的文件中第一個(gè) 4k 存儲(chǔ)的是 block0,第二個(gè) 4k 存儲(chǔ)的是 pointer 類(lèi)型的 block。
第三,第四個(gè) 4k 存儲(chǔ)的是一個(gè) data 類(lèi)型的 block ,里面存儲(chǔ)了原文件數(shù)據(jù)。
當(dāng)用戶修改一行的時(shí)候,對(duì)應(yīng)到 memline 的一個(gè) line 的修改,對(duì)應(yīng)到這行 line 在哪個(gè) block 的修改,從而定期的刷到 swap 文件。
vim 特殊的文件 ~ 和 .swp ?
假設(shè)原文件名稱:test.txt 。
1test.txt~ 文件
test.txt~ 文件估計(jì)很多人都沒(méi)見(jiàn)過(guò),因?yàn)橄У奶炝恕_@個(gè)文件在修改原文件之前生成,修改原文件之后刪除。作用于只存在于 buf_write ,是為了安全備份的。
劃重點(diǎn):test.txt~ 和 test.txt 本質(zhì)是一樣的,沒(méi)有其他特定格式,是用戶數(shù)據(jù)。
讀者朋友試試 vim 一個(gè) 10 G的文件,然后改一行內(nèi)容,:w 保存,應(yīng)該很容易發(fā)現(xiàn)這個(gè)文件(因?yàn)閭浞莺突貙?xiě)時(shí)間巨長(zhǎng) )。
2.test.txt.swp 文件
這個(gè)文件估計(jì)絕大多數(shù)人都見(jiàn)過(guò),.swp 文件生命周期存在于整個(gè)進(jìn)程的生命周期,句柄是一直打開(kāi)的。很多人認(rèn)為 .test.txt.swp 是備份文件,其實(shí)準(zhǔn)確來(lái)講并不是備份文件,這是為了實(shí)現(xiàn)虛擬內(nèi)存空間的交換文件,test.txt~ 才是真正的備份文件。swp 是 memfile 的一部分,前面 4k 為 header 元數(shù)據(jù),后面的為 一個(gè)個(gè) 4k 的數(shù)據(jù)行封裝。和用戶數(shù)據(jù)并不完全對(duì)應(yīng)。
memfile = 內(nèi)存 + swp 才是最新的數(shù)據(jù)。
思考解答
1vim 存儲(chǔ)原理是啥?
沒(méi)啥,就是用的 read,write 這樣的系統(tǒng)調(diào)用來(lái)讀寫(xiě)數(shù)據(jù)而已。
2vim 的過(guò)程有兩種冗余的文件?
test.txt~ :是真正的備份文件,誕生于修改原文件之前,消失于修改成功之后;.test.txt.swp :swap 文件,由 block 組成,里面可能由用戶未保存的修改,等待:w 這種調(diào)用,就會(huì)覆蓋到原文件;
3vim 編輯超大文件的時(shí)候?yàn)槭裁绰?/strong>
一般情況下,你能直觀感受到,慢在兩個(gè)地方:
vim 打開(kāi)的時(shí)候;
修改了一行內(nèi)容,:w 保存的時(shí)候;
先說(shuō)第一個(gè)場(chǎng)景:vim 一個(gè) 10G 的文件,你的直觀感受是啥?
我的直觀感受是:命令敲下之后,可以去泡杯茶,等茶涼了一點(diǎn),差不多就能看到界面了。為什么?
在進(jìn)程初始化的時(shí)候,初始化窗口之前,create_windows -> open_buffer 里面調(diào)用 readfile 會(huì)把整個(gè)文件讀一遍(完整的讀一遍),在屏幕上展示編碼過(guò)的字符。
劃重點(diǎn):初始化的時(shí)候,readfile 會(huì)把整個(gè)文件讀一遍。 10 G的文件,你可想而知有多慢。我們可以算一下,按照單盤(pán)硬件 100 M/s 的帶寬來(lái)算,也要 102 秒的時(shí)間。
再說(shuō)第二個(gè)場(chǎng)景:喝了口茶,改了一個(gè)單詞,:w 保存一下,媽呀,命令敲下之后,又可以去泡杯茶了?為什么?
先拷貝出一個(gè) 10G 的 test.txt~ 備份文件,102 秒就過(guò)去了;
test.txt 截?cái)酁?0,再把 memfile( .test.txt.swp )拷貝回 test.txt ,數(shù)據(jù)量 10 G,102 秒過(guò)去了(第一次可能更慢哦);
4vim 編輯大文件的時(shí)候,會(huì)有空間膨脹?
是的,vim 一個(gè) test.txt 10 G 的文件,會(huì)存在某個(gè)時(shí)刻,需要 >=30 G 的磁盤(pán)空間。
原文件 test.txt 10 G
備份文件 test.txt~ 10G
swap 文件 .test.txt.swp >10G
總結(jié)
vim 編輯文件并不沒(méi)有用黑魔法,還是用的 read,write,樸實(shí)無(wú)華;
vim 編輯超大文件,打開(kāi)很慢,因?yàn)闀?huì)讀一遍文件( readfile ),保存的時(shí)候很慢,因?yàn)闀?huì)讀寫(xiě)兩遍文件(backup 一次,memfile 覆蓋寫(xiě)原文件一次);
memfile 是 vim 抽象的一層虛擬存儲(chǔ)空間(物理上由內(nèi)存 block 和 swp 文件組成)對(duì)應(yīng)一個(gè)文件的最新修改,存儲(chǔ)單元由 block 構(gòu)成。:w 保存的時(shí)候,就是從 memfile 讀,寫(xiě)到原文件的過(guò)程;
memline 是基于 memfile 做的另一層封裝,把用戶的文件抽象成“行”的概念;
.test.txt.swp 文件是一直 open 的,memfile 會(huì)定期的交換數(shù)據(jù)進(jìn)去,以便容災(zāi)恢復(fù);
test.txt~ 文件才是真正的備份文件,誕生于 :w 覆蓋原文件之前,消失于成功覆寫(xiě)原文件之后;
vim 基本都是整個(gè)文件的處理,并不是局部處理,大文件的編輯根本不適合 vim ,話說(shuō)回來(lái),正經(jīng)人誰(shuí)會(huì)用 vim 編輯 10 G 的文件?vim 就是個(gè)文本編輯器呀;
一個(gè) readfile 函數(shù) 2533 行,一個(gè) buf_write 函數(shù) 1987 行代碼。。。不是我打擊各位的積極性,這。。。反正我不想再看見(jiàn)它了。。。
后記
對(duì)于 vim 的好奇讓筆者擼了一遍源碼,學(xué)習(xí)了下其中的 IO 知識(shí),不想被動(dòng)輒幾千行一個(gè)的函數(shù)教育了一番。我再也不想擼它了。。你學(xué) fei 了嗎?
編輯:hfy
-
存儲(chǔ)
+關(guān)注
關(guān)注
13文章
4233瀏覽量
85595 -
Linux
+關(guān)注
關(guān)注
87文章
11215瀏覽量
208749
原文標(biāo)題:Linux 編輯器之神 vim 的 IO 存儲(chǔ)原理
文章出處:【微信號(hào):gh_3980db2283cd,微信公眾號(hào):開(kāi)關(guān)電源芯片】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論