跳掉檔案開頭數 bytes 的作法

假設有個大檔案 (e.g. 500MB) 在開頭存有 meta data, 後面存有內容, 要怎麼跳掉開頭的 meta data, 只留下內容呢?

命令列的作法

這裡看到兩個有效率的作法:

使用 subshell: 先用一個 dd 跳掉開頭 1131 bytes (block size=1131, read 1 block), 再用第二個 dd 用正常的 block size 讀寫檔, 這樣效率就和直接用 dd 複製檔案差不多了。

$ ( dd bs=1131 count=1 of=dev_null && dd bs=4K of=out.mp3 ) < 100827_MR029_LobbyControl.mp3

使用 pipe 配合 a group of commands: 概念差不多, 只是改用 pipe。

$ dd if=filtered.dump bs=512k | { dd bs=1131 count=1 of=/dev/null; dd bs=512k of=trimmed.dump; }

Python 不建立新檔的作法

產生新檔案的時間成本有點高, 可能會花到數秒。如果是 Python 程式內要用的話, 可以直接用 file object 然後想辦法跳掉開頭資料。

偷懶的作法是直接用 file object, 然後先呼叫 file.read(N) 跳掉開頭 N bytes。缺點是若 file object 會傳入 third-party lib 使用, 其它程式碼可能會用 seek() 回頭讀開頭的內容。

保險的作法是自訂一個 file object wrapper。這個 wrapper 行為和內建 file object 一模一樣, 只是讀不到開頭數個 bytes。這樣效率和一般的 file object 幾乎沒差。 程式碼見這裡, 另外這裡是測試碼。關鍵是覆寫和移動檔案位置有關的 seektell。然後用 Python 提供的 __getattr__(self, attr) 實作剩下沒改到的 method。

那麼, 要怎麼知道該覆寫那些 method 呢? 用 ipython 建一個 file object, 然後利用補字功能, 再一個個看 method 說明, 很快就知道該覆寫那些了。

以下是示意的操作過程:

$ ipython

In [1]: f = open('/etc/fstab')

In [2]: f.<TAB>
f.close       f.encoding    f.fileno      f.isatty      f.name        f.next        f.readinto    f.readlines   f.softspace   f.truncate    f.writelines
f.closed      f.errors      f.flush       f.mode        f.newlines    f.read        f.readline    f.seek        f.tell        f.write       f.xreadlines

In [2]: f.close?
Type:       builtin_function_or_method
Base Class: <type 'builtin_function_or_method'>
String Form:<built-in method close of file object at 0x1a9a660>
Namespace:  Interactive
Docstring:
close() -> None or (perhaps) an integer.  Close the file.

Sets data attribute .closed to True.  A closed file cannot be used for
further I/O operations.  close() may be called more than once without
error.  Some kinds of file objects (for example, opened by popen())
may return an exit status upon closing.

In [3]: f.encoding?

...

In [21]: f.seek?

Type:       builtin_function_or_method
Base Class: <type 'builtin_function_or_method'>
String Form:<built-in method seek of file object at 0x1a9a660>
Namespace:  Interactive
Docstring:
seek(offset[, whence]) -> None.  Move to new file position.

Argument offset is a byte count.  Optional argument whence defaults to
0 (offset from start of file, offset should be >= 0); other values are 1
(move relative to current position, positive or negative), and 2 (move
relative to end of file, usually negative, although many platforms allow
seeking beyond the end of a file).  If the file is opened in text mode,
only offsets returned by tell() are legal.  Use of other offsets causes
undefined behavior.
Note that not all file objects are seekable.

...

留言

這個網誌中的熱門文章

virtualbox 使用 USB 裝置

熟悉系統工具好處多多

如何 git merge 更改檔名的檔案