我有一个二进制文件,我希望在进一步处理之前删除第一个n
个字符。我有文件指针作为输入。
我尝试使用ftruncate
,但为此我必须创建另一个我不想要的文件指针。我试过下面的代码,但没有用。
#include <stdio.h>
#include <unistd.h>
int main(void) {
FILE*f,ftemp;
f=fopen("./temp","a");
scanf("%d",&n);
fseek(f,n,SEEK_SET);
ftruncate(fileno(f),/*end of file*/ );
ftemp=f;
return 0;
}
请以任何其他方式提出建议。
实际上前n个字节是二进制的,部分的其余部分就像asn。
由于
答案 0 :(得分:2)
这是一个程序,它会删除 ./ temp 的第一个 N 字节,离开原始文件为 ./ temp-old 。 它假定文件适合内存。 您可以在命令行中指定 N 。
/*
* THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
* EITHER EXPRESSED OR IMPLIED.
*/
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#define ERR (-1)
int main (
int argc,
char ** argv
) {
int fdin;
int fdout;
unsigned long n;
struct stat st;
size_t sz;
ssize_t ssz;
char * data;
if (argc != 2) {
fprintf(stderr, "usage: %s nbytes\n", argv[0]);
return 1;
}
n = strtoul(argv[1], NULL, 10);
if (errno) {
fprintf(stderr, "nbytes (%s) is suspect\n", argv[1]);
return 1;
}
fdin = open("./temp", O_RDONLY, 0);
if (fdin == ERR) {
fprintf(stderr, "open input: %s\n", strerror(errno));
return 1;
}
if (fstat(fdin, &st) == ERR) {
fprintf(stderr, "stat input: %s\n", strerror(errno));
return 1;
}
sz = st.st_size;
if (sz < n) {
fprintf(stderr, "file is not that big\n");
return 1;
}
data = malloc(sz);
if (data == NULL) {
fprintf(stderr, "insufficient memory\n");
return 1;
}
ssz = read(fdin, data, sz);
if (ssz < 0) {
fprintf(stderr, "read input: %s\n", strerror(errno));
return 1;
}
if ((size_t)ssz != sz) {
fprintf(stderr, "read was short\n");
return 1;
}
(void)close(fdin);
fdout = open("./temp-new", O_CREAT|O_EXCL|O_WRONLY, st.st_mode);
if (fdout == ERR) {
fprintf(stderr, "open output: %s\n", strerror(errno));
return 1;
}
sz -= n;
ssz = write(fdout, data + n, sz);
if (ssz < 0) {
fprintf(stderr, "write output: %s\n", strerror(errno));
return 1;
}
if ((size_t)ssz != sz) {
fprintf(stderr, "write was short\n");
return 1;
}
if (close(fdout) == ERR) {
fprintf(stderr, "write close: %s\n", strerror(errno));
return 1;
}
if (link("./temp", "./temp-old") == ERR) {
fprintf(stderr, "link input: %s\n", strerror(errno));
return 1;
}
if (rename("./temp-new", "./temp") == ERR) {
fprintf(stderr, "rename output: %s\n", strerror(errno));
return 1;
}
return 0;
}
我仔细地写了它,但是,当然你应该在使用之前制作文件的备份副本,以防万一......
答案 1 :(得分:1)
使用dd
实用程序。一种方法是将块大小设置为等于要删除的字节数,然后告诉dd
在输入文件中找到一个块:
# N is number of bytes to delete: wherever N is seen
# substitute this value.
dd if=infile of=outfile bs=N seek=1
现在outfile
是infile
的副本,但删除了前N个字节。
以下命令也可以使用;不幸的是,它会执行1个字节read
和write
系统调用,因为块大小是1个字节:
# N is number of bytes to delete
dd if=infile of=outfile bs=1 seek=N
如果N太小而不能成为一个好的缓冲因子,我们可以使用单独的输入和输出块大小(ibs
和obs
),这样至少我们可以写入更大的块:
# read N at a time, skipping first N; write 64 kB at a time:
dd if=infile of=outfile ibs=N obs=65536 seek=1
我们可以通过将outfile
重命名为infile
来模拟就地删除。
应该可以实际执行此操作。以下几乎有效:
dd if=inoutfile of=inoutfile bs=N conv=notrunc skip=1
唯一的问题是没有conv=notrunc
选项,文件会立即截断为零长度。内容消失了! with 该选项,文件在写入后根本不会被截断。
GNU Coreutils有truncate
命令可以使用:
dd if=inoutfile of=inoutfile bs=N conv=notrunc skip=1
truncate -s -N inoutfile
-
中size参数的truncate
前缀表示“将该字符数减少很多字节”。