![如何删除二进制文件的一部分而不复制](https://linux22.com/image/61466/%E5%A6%82%E4%BD%95%E5%88%A0%E9%99%A4%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%96%87%E4%BB%B6%E7%9A%84%E4%B8%80%E9%83%A8%E5%88%86%E8%80%8C%E4%B8%8D%E5%A4%8D%E5%88%B6.png)
我需要删除 6MB 文件的前 2 个字节。然而,这是一个嵌入式 Linux,只有 32 MB RAM 和不到 1 MB 可用闪存。
我尝试使用 dd,如下所示:
1 - #dd bs=1 skip=2 count=1022 if=input of=ouput_1
2 - #dd bs=1024 skip=1 if=input of=ouput_2
3 - #rm -rf input
4 - #(dd if=ouput_1 ; dd if=ouput_2) > ouput
5 - #rm -rf ouput_1 ouput_2
对于 /tmp 下的所有文件(作为 tmpfs 安装在 RAM 上),我的问题是在第 3 行和第 5 行之前,所需的内存为 12 Mbyte (2x6MB),并且该过程有时会失败并给出“内存不足”错误。
有没有办法可以删除前 2 个字节而不分配文件大小的两倍?我可以使用 dd (或任何其他)“就地”剪切二进制文件吗?
答案1
我认为这应该有效:
$ # Create test file
$ echo "Hello, World" > h.data
$
$ # Move contents up by 2 bytes
$ # Note if= and of= are the same for in-place editing
$ dd bs=2 if=h.data skip=1 seek=0 conv=notrunc of=h.data
5+1 records in
5+1 records out
11 bytes (11 B) copied, 0.000598796 s, 18.4 kB/s
$
$ # Note 11 bytes were moved above
$ # Truncate the file after byte 11
$ dd bs=11 if=h.data skip=1 seek=1 count=0 of=h.data
0+0 records in
0+0 records out
0 bytes (0 B) copied, 0.000338852 s, 0.0 kB/s
$
$ # Display edited file:
$ cat h.data
llo, World
$
将这一切包装在一个脚本中,您可能会得到如下所示的内容:
#!/bin/bash
size=$(stat -c %s "$2")
dd bs=$1 if="$2" skip=1 seek=0 conv=notrunc of="$2"
dd bs=$((size - $1)) if="$2" skip=1 seek=1 count=0 of="$2"
将此称为:
./truncstart.sh 2 file.dat
其中2
是从开头开始删除的字节数file.data
正如 @Gilles 指出的那样,该解决方案在意外中断的情况下并不稳健,这可能会在dd
处理过程中发生;在这种情况下,文件将被损坏。
答案2
根据@DigitalTrauma 的回答,这最终对我有用:
size=$(stat -c %s file)
dd bs=2 if=file skip=1 seek=0 conv=notrunc count=511 of=file
dd if=file ibs=1024 skip=1 of=file conv=notrunc obs=1022 seek=1
truncate file $(( size - 2 ))
删除前两个字节需要两个dd
步骤来加快速度,并且truncate
是一个用于截断文件最后几个字节的小实用程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char **argv)
{
if (argc != 3 ) {
printf ("Usage: %s <file> <bytes>\n", argv[0]);
exit(1);
}
if (truncate(argv[1], atoi(argv[2]))) {
printf (" Error ! \n");
exit(1);
}
return(0);
}