How do I read from and write to files directly in Vimscript without shelling out to external commands?
Answer
readfile() and writefile()
Explanation
readfile({path}) reads a file and returns its contents as a list of lines, and writefile({list}, {path}) writes a list of lines back to disk. Together they let you load, transform, and persist data entirely within Vimscript — no external commands needed.
How it works
" Read a file into a list of lines
let lines = readfile(expand('~/.vim/wordlist.txt'))
" Modify the list
call filter(lines, 'v:val !~ "^#"') " strip comment lines
" Write the modified list back
call writefile(lines, expand('~/.vim/wordlist.clean.txt'))
Key signatures:
readfile(path)— returns aListof strings, one per linereadfile(path, 'b')— binary mode (no line-ending conversion)writefile(list, path)— overwrites the filewritefile(list, path, 'a')— appends to the file
Example
Save the current session's open file paths for later reference:
let bufs = filter(range(1, bufnr('$')), 'buflisted(v:val)')
let paths = map(bufs, 'bufname(v:val)')
call writefile(paths, '/tmp/vim_session_files.txt')
" Later, restore from another session:
for f in readfile('/tmp/vim_session_files.txt')
execute 'edit ' . fnameescape(f)
endfor
Tips
- Always check existence first:
if filereadable(path)before callingreadfile() writefile()creates the file if it doesn't exist, but not intermediate directories — usemkdir(fnamemodify(path, ':h'), 'p')if needed- In Neovim Lua:
vim.fn.readfile(path)andvim.fn.writefile(list, path)are identical - For JSON data, combine with
json_decode(join(readfile(path)))andwritefile([json_encode(data)], path)(Vim 8+/Neovim)