The simplest way is to use the binary
option. From :help binary
:
This option should be set before editing a binary file. You can also
use the -b Vim argument. When this option is switched on a few
options will be changed (also when it already was on):
'textwidth' will be set to 0
'wrapmargin' will be set to 0
'modeline' will be off
'expandtab' will be off
Also, 'fileformat' and 'fileformats' options will not be used, the
file is read and written like 'fileformat' was "unix" (a single <NL>
separates lines).
The 'fileencoding' and 'fileencodings' options will not be used, the
file is read without conversion.
[..]
When writing a file the <EOL> for the last line is only written if
there was one in the original file (normally Vim appends an <EOL> to
the last line if there is none; this would make the file longer). See
the 'endofline' option.
If you don't do this, and your environment is using a multibyte encoding (e.g.
UTF-8, as most people use), Vim tries to encode the text as such, usually
leading to file corruption.
You can verify this by opening a file, and just using :w
. It is now
changed.
If you set LANG
and LC_ALL
to C
(ASCII), Vim doesn't convert anything and
the files stay the same (it still adds a newline, though) since Vim won't need
to do any multibyte encoding.
I personally also prefer to disable set wrap
for binary, although others
might prefer to enable it. YMMV.
Another useful thing to do is :set display=uhex
. From :help 'display'
:
uhex Show unprintable characters hexadecimal as <xx>
instead of using ^C and ~C.
And as a last tip, you can show the hex value of the character under the cursor
in the ruler with %B
(:set rulerformat=0x%B
).
More advanced: xxd
You can use the xxd(1)
tool to convert a file to more readable format, and
(this is the important bit), parse the edited "readable format" and write it
back as binary data. xxd
is part of vim
, so if you have vim
installed you
should also have xxd
.
To use it:
$ xxd /bin/ls | vi -
Or if you've already opened the file, you can use:
:%!xxd
Now make your changes, you need to do that on the left-hand side of the display
(the hex numbers), changes to the right-hand side (printable representation) are
ignored on write.
To save it, use xxd -r
:
:%!xxd -r > new-ls
This will save the file to new-ls
.
Or to load the binary in the current buffer:
:%!xxd -r
From xxd(1)
:
-r | -revert
reverse operation: convert (or patch) hexdump into binary. If
not writing to stdout, xxd writes into its output file without
truncating it. Use the combination -r -p to read plain hexadeci‐
mal dumps without line number information and without a particu‐
lar column layout. Additional Whitespace and line-breaks are
allowed anywhere.
And then just use :w
to write it. (beware: you want to set the binary
option before you write to the file, for the same reasons outline above).
Complementary keybinds to make this a bit easier:
" Hex read
nmap <Leader>hr :%!xxd<CR> :set filetype=xxd<CR>
" Hex write
nmap <Leader>hw :%!xxd -r<CR> :set binary<CR> :set filetype=<CR>
This is also available from the menu if you're using gVim, under 'Tools ➙
Convert to HEX' and 'Tools ➙ Convert back'.
The vim tips wiki has a page with more
information and some helper scripts. Personally, I think you're probably better
off using a real hex editor if you're editing binary files that often. Vim can
sort of do the job, but it's obviously not designed for it, and if you ever
write without :set binary
Vim might destroy your binary files!