Як редагувати двійкові файли за допомогою Vim?


77

Чи є спосіб редагувати двійкові файли в якомусь шістнадцятковому режимі?

Наприклад , якщо у мене є деякі двійкові дані , показані xxdабо hexdump -Cяк це:

$ hexdump -C a.bin | head -n 5
00000000  cf fa ed fe 07 00 00 01  03 00 00 80 02 00 00 00  |................|
00000010  12 00 00 00 40 05 00 00  85 00 20 00 00 00 00 00  |....@..... .....|
00000020  19 00 00 00 48 00 00 00  5f 5f 50 41 47 45 5a 45  |....H...__PAGEZE|
00000030  52 4f 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |RO..............|
00000040  00 00 00 00 01 00 00 00  00 00 00 00 00 00 00 00  |................|

$ xxd a.bin | head -n 5
0000000: cffa edfe 0700 0001 0300 0080 0200 0000  ................
0000010: 1200 0000 4005 0000 8500 2000 0000 0000  ....@..... .....
0000020: 1900 0000 4800 0000 5f5f 5041 4745 5a45  ....H...__PAGEZE
0000030: 524f 0000 0000 0000 0000 0000 0000 0000  RO..............
0000040: 0000 0000 0100 0000 0000 0000 0000 0000  ................

Якщо я хочу змінити значення в певній позиції, такий вид перегляду допоможе знайти потрібне місце, наприклад, коли позиція для зміни знаходиться біля якоїсь відомої рядка.

Відповіді:


89

Найпростіший спосіб - використовувати binaryваріант. Від :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.

Якщо цього не зробити, а ваше середовище використовує багатобайтове кодування (наприклад, UTF-8, як це використовується більшість людей), Vim намагається кодувати текст як такий, що зазвичай призводить до пошкодження файлу.

Ви можете перевірити це, відкривши файл і просто скориставшись :w. Зараз це змінено.
Якщо ви встановили LANGі LC_ALLв C(ASCII), Вім нічого не конвертувати і файли залишаються тими ж (він все ще додає символ нового рядка, хоча) , так як Vim не потрібно буде робити якісь - або багатобайтове кодування.

Я особисто також вважаю за краще відключити set wrap бінарне, хоча інші, можливо, вважають за краще це ввімкнути . YMMV. Ще одна корисна річ - це :set display=uhex. Від :help 'display':

uhex            Show unprintable characters hexadecimal as <xx>
                instead of using ^C and ~C.

І як остання порада, ви можете показати шістнадцяткове значення символу під курсором у лінійці з %B( :set rulerformat=0x%B).

Більш просунуті: xxd

Ви можете використовувати xxd(1)інструмент для перетворення файлу у більш читабельний формат і (це важливий біт), проаналізуйте відредагований "читабельний формат" та запишіть його назад як бінарні дані. xxdє частиною vim, тому якщо ви vimвстановили, ви також повинні мати це xxd.

Щоб використовувати його:

$ xxd /bin/ls | vi -

Або якщо ви вже відкрили файл, ви можете використовувати:

:%!xxd

Тепер внесіть зміни, вам потрібно зробити це в лівій частині дисплея (шістнадцяткові номери), зміни в правій частині (зображення для друку) ігноруються під час запису.

Щоб зберегти його, використовуйте xxd -r:

:%!xxd -r > new-ls

Це збереже файл у new-ls.

Або завантажити двійковий файл у поточний буфер:

:%!xxd -r

Від 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.

А потім просто використовуйте :wдля його написання. ( будьте обережні : ви хочете встановити binary параметр перед тим, як записати у файл, з тих самих причин, як описано вище).

Додаткові клавіші, щоб зробити це трохи простіше:

" 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>

Це також доступне в меню, якщо ви використовуєте gVim, у розділі "Інструменти ➙ Перетворити в HEX" та "Інструменти ➙ Перетворити назад".

У вікі-підказках vim є сторінка з додатковою інформацією та деякими допоміжними сценаріями. Особисто я думаю, вам, мабуть, краще використовувати справжній шестигранний редактор, якщо ви часто редагуєте двійкові файли. Vim може якось виконати цю роботу, але вона, очевидно, не призначена для цього, і якщо ви коли-небудь пишете без :set binaryVim, це може знищити ваші бінарні файли!


4
Чудова відповідь, але, мабуть, слід почати з "Не намагайтеся цього вдома, діти!"
msw

Що робити, якщо мені потрібно видалити кілька байт? наприклад посеред двійкового.
Антон К

Я не знаю, що робить Vim, але він додає 95 КБ тексту до бінарного файлу 200 КБ, незважаючи на те, що я нічого не змінив. Навіть с :set binary noeol fenc=utf-8. Насправді це робиться відразу після відкриття файлу, перш ніж він каже [noeol] [converted]. Чому vim потрібно зробити буфер на 150% більшим? Як я запобігти зіпсування таких файлів?
Бреден Кращий

Єдине, що працює - це :r !xxd <file>(чи $ xxd <file> | vim -) читати та :w !xxd -r > <file>писати, але це не ідеально.
Бреден Кращий

Відмінна відповідь. Зауважте, що URL для благословення не працює; Я знайшов це (я думаю) на github на сайті github.com/bwrsandman/Bless .
сонофагун

19

Щоб переглянути вміст двійкового файлу в шестигранному вікні, відкрийте файл, увімкніть двійковий режим і відфільтруйте буфер за допомогою xxdкоманди:

:set binary
:%!xxd

Ви можете внести зміни в лівій області (відредагувати шістнадцяткові номери), і коли будете готові, процідіть xxd -rі, нарешті, збережіть файл:

:%!xxd -r
:w

Якщо крок фільтрування після відкриття та перед закриттям здається стомлюючим, і ви часто робите це з файлами з .binрозширенням, ви можете додати це до свого vimrc, щоб зробити процес автоматичним:

" for hex editing
augroup Binary
  au!
  au BufReadPre  *.bin let &bin=1
  au BufReadPost *.bin if &bin | %!xxd
  au BufReadPost *.bin set ft=xxd | endif
  au BufWritePre *.bin if &bin | %!xxd -r
  au BufWritePre *.bin endif
  au BufWritePost *.bin if &bin | %!xxd
  au BufWritePost *.bin set nomod | endif
augroup END

Якщо я дотримуватися цих інструкцій (відкрити бінарний файл, :%!xxd, :%!xxd -r, :w, не зробив ніяких змін!) , То бінарний файл , написаний є НЕ те ж саме, що і оригінал ... Є чи це справа для вас (я тестував з /bin/ls). Мені потрібно скористатися :set binaryперед збереженням (також дивіться мою відповідь, яка пояснює, чому) ... Можливо, це щось у моєму vimrc? Але незалежно, я б завжди використовував set binaryдля безпеки ...
Мартін Турноїй

1
Ви можете замість цього додати augroupсценарій, ~/.vim/plugin/binary.vimякщо не хочете захаращувати свій.vimrc
thom_nic

Якщо ви перебуваєте на закордонній установці, цей augroup Binaryсписок розміщений у :help hex-editingабо :help using-xxdв будь-якому Vim з 5.5 (вересень 1999 р.).
bb010g

6

Використовуйте редактор "bvi". http://bvi.sourceforge.net/ (Це є у кожному сховищі Linux.)

$ apt-cache show bvi
[snip]
Description-en: binary file editor
 The bvi is a display-oriented editor for binary files, based on the vi
 text editor. If you are familiar with vi, just start the editor and begin to
 edit! If you never heard about vi, maybe bvi is not the best choice for you.

1
Більш досконалою альтернативою є bviplus, який має vim-контроль.
Антон К


3

TL; Відповідь DR

Відкрийте файл з Vim у двійковому режимі:

vim -b <file_to_edit>

У Vim перейдіть до режиму шестигранного редагування так:

:%!xxd -p

Зберегти:

:%!xxd -p -r
:w

Це перетворить буфер назад із шестигранного режиму, а потім збереже файл як звичайний.

Зверніть увагу на опцію -p. Це дозволяє уникнути всіх надлишкових даних для друку та адреси та просто показує вам шістнадцятку. Просто опустіть -p, якщо потрібно додатковий контекст.

Будьте обережні, відкриваючи файл з Vim не у двійковому режимі, оскільки він додасть (зазвичай ненавмисний) символ LF до кінця файлу, коли ви збережете його.


Це насправді не додає нічого, чого немає в інших відповідях.
Герб Вулф

5
Справжній TL; DR існує :h using-xxdі існує вже з тих пір v7.0001і, ймовірно, довше. Цей сайт був би менш активним, якби люди шукали документи.
Томмі А

1

Це схоже на зручний маленький плагін Vim, який виконує завдання, використовуючи тимчасовий файл, який він записує автоматично та назад для вас.

Деякі роки тому я знайшов подібний плагін, який я адаптував і вдосконалив для власного використання. Тут я включив відповідний код для цього, якщо хтось цього захоче. Він також заснований на інструменті xxd. Я впевнений, що версія GitHub, яку я зв'язав вище, працює краще, але я її фактично не використовував, тому я зрозумів, що також опублікую цю, яку я точно знаю.

Джерелом для цієї іншої версії була vim wikia, зокрема ця сторінка .

Ось код:

"-------------------------------------------------------------------------------  
" Hexmode  
"-------------------------------------------------------------------------------  
" Creates an automatic hex viewing mode for vim by converting between hex dump  
" and binary formats. Makes editing binary files a breeze.  
"-------------------------------------------------------------------------------  
" Source: vim.wikia.com/wiki/Improved_Hex_editing  
" Author: Fritzophrenic, Tim Baker  
" Version: 7.1  
"-------------------------------------------------------------------------------  
" Configurable Options {{{1  
"-------------------------------------------------------------------------------  

" Automatically recognized extensions  
let s:hexmode_extensions = "*.bin,*.exe,*.hex"  

"-------------------------------------------------------------------------------
" Commands and Mappings {{{1
"-------------------------------------------------------------------------------

" ex command for toggling hex mode - define mapping if desired
command! -bar Hexmode call ToggleHex()
command! -nargs=0 Hexconfig edit $VIM\vimfiles\plugin\hexmode.vim | exe "normal 11G" | exe "normal zo"

nnoremap <C-H> :Hexmode<CR>
inoremap <C-H> <Esc>:Hexmode<CR>
vnoremap <C-H> :<C-U>Hexmode<CR>

"-------------------------------------------------------------------------------    
" Autocommands {{{1  
"-------------------------------------------------------------------------------  

if exists("loaded_hexmode")  
    finish  
endif  
let loaded_hexmode = 1  

" Automatically enter hex mode and handle file writes properly  
if has("autocmd")  
  " vim -b : edit binary using xxd-format  
  augroup Binary  
    au!  

    " set binary option for all binary files before reading them  
    exe "au! BufReadPre " . s:hexmode_extensions . " setlocal binary"

    " if on a fresh read the buffer variable is already set, it's wrong
    au BufReadPost *
          \ if exists('b:editHex') && b:editHex |
          \   let b:editHex = 0 |
          \ endif

    " convert to hex on startup for binary files automatically
    au BufReadPost *
          \ if &binary | Hexmode | endif

    " When the text is freed, the next time the buffer is made active it will
    " re-read the text and thus not match the correct mode, we will need to
    " convert it again if the buffer is again loaded.
    au BufUnload *
          \ if getbufvar(expand("<afile>"), 'editHex') == 1 |
          \   call setbufvar(expand("<afile>"), 'editHex', 0) |
          \ endif

    " before writing a file when editing in hex mode, convert back to non-hex
    au BufWritePre *
          \ if exists("b:editHex") && b:editHex && &binary |
          \  let oldro=&ro | let &ro=0 |
          \  let oldma=&ma | let &ma=1 |
          \  silent exe "%!xxd -r" |
          \  let &ma=oldma | let &ro=oldro |
          \  unlet oldma | unlet oldro |
          \ endif

    " after writing a binary file, if we're in hex mode, restore hex mode
    au BufWritePost *
          \ if exists("b:editHex") && b:editHex && &binary |
          \  let oldro=&ro | let &ro=0 |
          \  let oldma=&ma | let &ma=1 |
          \  silent exe "%!xxd" |
          \  exe "set nomod" |
          \  let &ma=oldma | let &ro=oldro |
          \  unlet oldma | unlet oldro |
          \ endif
  augroup END  
endif  

"-------------------------------------------------------------------------------
" Functions {{{1
"-------------------------------------------------------------------------------

" helper function to toggle hex mode
function! ToggleHex()
  " hex mode should be considered a read-only operation
  " save values for modified and read-only for restoration later,
  " and clear the read-only flag for now
  let l:modified=&mod
  let l:oldreadonly=&readonly
  let &readonly=0
  let l:oldmodifiable=&modifiable
  let &modifiable=1
  if !exists("b:editHex") || !b:editHex
    " save old options
    let b:oldft=&ft
    let b:oldbin=&bin
    " set new options
    setlocal binary " make sure it overrides any textwidth, etc.
    let &ft="xxd"
    " set status
    let b:editHex=1
    " switch to hex editor
    set sh=C:/cygwin/bin/bash
    %!xxd
  else
    " restore old options
    let &ft=b:oldft
    if !b:oldbin
      setlocal nobinary
    endif
    " set status
    let b:editHex=0
    " return to normal editing
    %!xxd -r
  endif
  " restore values for modified and read only state
  let &mod=l:modified
  let &readonly=l:oldreadonly
  let &modifiable=l:oldmodifiable
endfunction

" vim: ft=vim:fdc=2:fdm=marker
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.