Làm cách nào để chỉnh sửa tập tin nhị phân với Vim?


77

Có cách nào để chỉnh sửa các tệp nhị phân trong một số loại chế độ thập lục phân không?

Ví dụ: nếu tôi có một số dữ liệu nhị phân được hiển thị bởi xxdhoặc hexdump -Cnhư thế này:

$ 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  ................

Nếu tôi muốn thay đổi giá trị tại một vị trí cụ thể, loại chế độ xem này sẽ giúp tìm đúng vị trí, ví dụ: khi vị trí cần thay đổi ở gần một số chuỗi đã biết.

Câu trả lời:


89

Cách đơn giản nhất là sử dụng binarytùy chọn. Từ :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.

Nếu bạn không làm điều này và môi trường của bạn đang sử dụng mã hóa đa bào (ví dụ UTF-8, như hầu hết mọi người sử dụng), Vim cố gắng mã hóa văn bản như vậy, thường dẫn đến hỏng tệp.

Bạn có thể xác minh điều này bằng cách mở một tệp và chỉ cần sử dụng :w. Bây giờ nó đã được thay đổi.
Nếu bạn đặt LANGLC_ALLthành C(ASCII), Vim sẽ không chuyển đổi bất cứ thứ gì và các tệp vẫn giữ nguyên (tuy nhiên nó vẫn thêm một dòng mới) vì Vim sẽ không cần thực hiện bất kỳ mã hóa đa bào nào.

Cá nhân tôi cũng thích vô hiệu hóa set wrap nhị phân, mặc dù những người khác có thể thích kích hoạt nó. YMMV. Một điều hữu ích để làm là :set display=uhex. Từ :help 'display':

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

Và như một mẹo cuối cùng, bạn có thể hiển thị giá trị hex của ký tự dưới con trỏ trong thước kẻ với %B( :set rulerformat=0x%B).

Nâng cao hơn: xxd

Bạn có thể sử dụng xxd(1)công cụ để chuyển đổi một tệp thành định dạng dễ đọc hơn và (đây là bit quan trọng), phân tích "định dạng có thể đọc" đã chỉnh sửa và ghi lại dưới dạng dữ liệu nhị phân. xxdlà một phần của vim, vì vậy nếu bạn đã vimcài đặt, bạn cũng nên có xxd.

Để dùng nó:

$ xxd /bin/ls | vi -

Hoặc nếu bạn đã mở tệp, bạn có thể sử dụng:

:%!xxd

Bây giờ thực hiện các thay đổi của bạn, bạn cần thực hiện điều đó ở phía bên trái của màn hình (các số hex), các thay đổi ở phía bên phải (biểu diễn có thể in) được bỏ qua khi ghi.

Để lưu nó, sử dụng xxd -r:

:%!xxd -r > new-ls

Điều này sẽ lưu các tập tin vào new-ls.

Hoặc để tải nhị phân trong bộ đệm hiện tại:

:%!xxd -r

Từ 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.

Và sau đó chỉ cần sử dụng :wđể viết nó. ( hãy cẩn thận : bạn muốn đặt binary tùy chọn trước khi ghi vào tệp, vì những lý do tương tự như đã nêu ở trên).

Bàn phím bổ sung để làm điều này dễ dàng hơn một chút:

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

Điều này cũng có sẵn từ menu nếu bạn đang sử dụng gVim, trong 'Công cụ Chuyển đổi sang HEX' và 'Công cụ Chuyển đổi trở lại'.

Các mẹo vim wiki có một trang với nhiều thông tin hơn và một số tập lệnh trợ giúp. Cá nhân, tôi nghĩ rằng có lẽ bạn nên sử dụng trình soạn thảo hex thực sự nếu bạn thường xuyên chỉnh sửa các tệp nhị phân. Vim có thể thực hiện công việc, nhưng rõ ràng nó không được thiết kế cho nó và nếu bạn từng viết mà không có :set binaryVim có thể phá hủy các tệp nhị phân của bạn!


4
Câu trả lời đáng yêu, nhưng có lẽ nên bắt đầu bằng "Đừng thử điều này ở nhà, trẻ em!"
msw

Nếu tôi cần loại bỏ một số byte thì sao? ví dụ ở giữa nhị phân.
Anton K

Tôi không biết Vim đang làm gì, nhưng nó đã thêm 95KB văn bản vào tệp nhị phân 200KB mặc dù tôi không thay đổi gì. Ngay cả với :set binary noeol fenc=utf-8. Trong thực tế, nó làm điều đó ngay lập tức khi mở tệp trước khi nó nói [noeol] [converted]. Tại sao vim cần phải làm cho bộ đệm lớn hơn 150%? Làm thế nào để tôi ngăn chặn nó làm hỏng các tập tin như vậy?
Braden hay nhất

Điều duy nhất hoạt động là :r !xxd <file>(hoặc $ xxd <file> | vim -) để đọc và :w !xxd -r > <file>viết, nhưng điều này không lý tưởng.
Braden hay nhất

Câu trả lời tuyệt vời. Lưu ý rằng url cho phước lành không hoạt động; Tôi đã tìm thấy nó (tôi nghĩ) trên github tại github.com/bwrsandman/Bless .
sonofagun

19

Để xem nội dung của tệp nhị phân trong chế độ xem hex, hãy mở tệp, bật chế độ nhị phân và lọc bộ đệm thông qua xxdlệnh:

:set binary
:%!xxd

Bạn có thể thực hiện thay đổi ở khu vực bên trái (chỉnh sửa số hex) và khi sẵn sàng, hãy lọc qua xxd -rvà cuối cùng lưu tệp:

:%!xxd -r
:w

Nếu bước lọc sau khi mở và trước khi đóng có vẻ tẻ nhạt và bạn thường làm điều này với các tệp có .binphần mở rộng, bạn có thể thêm bước này vào vimrc của mình để thực hiện quy trình tự động:

" 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

Nếu tôi làm theo những hướng dẫn này (mở tập tin nhị phân, :%!xxd, :%!xxd -r, :w, didnt thực hiện bất kỳ thay đổi!) Sau đó các tập tin nhị phân bằng văn bản là không giống như bản gốc ... Đây có phải là trường hợp của bạn (Tôi đã thử nghiệm với /bin/ls). Tôi cần sử dụng :set binarytrước khi lưu (cũng xem câu trả lời của tôi giải thích tại sao) ... Có lẽ đó là thứ gì đó trong vimrc của tôi? Nhưng bất kể, tôi sẽ luôn sử dụng set binarycho an toàn ...
Martin Tournoij

1
Thay vào đó, bạn có thể thêm augrouptập lệnh vào ~/.vim/plugin/binary.vimnếu bạn không muốn làm lộn xộn.vimrc
thom_nic

Nếu bạn đang cài đặt ở nước ngoài, augroup Binarydanh sách đó được đặt tại :help hex-editinghoặc :help using-xxdtrong bất kỳ Vim nào kể từ 5.5 (tháng 9 năm 1999).
bb010g

6

Sử dụng trình chỉnh sửa "bvi". http://bvi.sourceforge.net/ (Nó có trong mọi kho lưu trữ 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
Thay thế nâng cao hơn là bviplus, có điều khiển vim.
Anton K


3

TL; DR Trả lời

Mở tệp bằng Vim ở chế độ nhị phân:

vim -b <file_to_edit>

Trong Vim, hãy vào chế độ chỉnh sửa hex như vậy:

:%!xxd -p

Để tiết kiệm:

:%!xxd -p -r
:w

Điều này sẽ chuyển đổi bộ đệm trở lại từ chế độ hex và sau đó lưu tệp như bình thường.

Lưu ý tùy chọn -p. Điều này tránh tất cả các lông tơ có thể in và địa chỉ bổ sung và chỉ hiển thị cho bạn hex. Chỉ cần bỏ qua -p nếu bạn muốn bối cảnh thêm.

Hãy cẩn thận mở tệp bằng Vim không ở chế độ nhị phân, vì nó sẽ nối một ký tự LF (thường là ngoài ý muốn) vào cuối tệp khi bạn lưu tệp.


Điều này không thực sự thêm bất cứ điều gì không có trong các câu trả lời khác.
Herb Wolfe

5
TL; DR thực sự :h using-xxdđã tồn tại và tồn tại từ đó v7.0001và có lẽ lâu hơn. Trang web này sẽ ít hoạt động hơn nếu mọi người tìm kiếm các tài liệu.
Tommy A

1

Đây trông giống như một plugin vim nhỏ tiện dụng thực hiện công việc bằng cách sử dụng một tệp tạm thời mà nó tự động ghi lại cho bạn.

Vài năm trước tôi đã tìm thấy một plugin tương tự mà tôi đã điều chỉnh và cải thiện để sử dụng riêng. Tôi đã bao gồm các mã có liên quan cho điều đó ở đây, trong trường hợp bất cứ ai muốn nó. Nó cũng dựa trên công cụ xxd. Tôi chắc chắn rằng phiên bản GitHub mà tôi liên kết ở trên hoạt động tốt hơn, nhưng tôi thực sự đã không sử dụng nó, vì vậy tôi nghĩ rằng tôi cũng sẽ đăng phiên bản này mà tôi biết chắc chắn hoạt động.

Nguồn cho phiên bản khác này là vim wikia, cụ thể là trang này .

Đây là mã:

"-------------------------------------------------------------------------------  
" 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.