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!
:set binary noeol fenc=utf-8. In fact, it's doing it immediately upon opening the file before it says[noeol] [converted]. Why does vim need to make the buffer 150% bigger? How do I prevent it from corrupting files like that? – Braden Best Apr 01 '18 at 19:35:r !xxd <file>(or$ xxd <file> | vim -) to read, and:w !xxd -r > <file>to write, but this is not ideal. – Braden Best Apr 01 '18 at 19:46