5

是否可以从 C 中的文件开头删除 N 个字节?

N 仅为 30 个字节。

我无法复制文件,因为它们非常大(有时甚至 100 GB)

4

2 回答 2

2

在 Linux 上,您可以创建指向另一个文件中的偏移量的环回设备。这是unix.stackexchange 中的一个示例:

#!/bin/bash
for ((i=0;i<10000;i++)); do
    printf "%7d\n" $i
done >/var/tmp/file
losetup -v -f -o 512 --sizelimit 512 /var/tmp/file
losetup -a
head -2 /var/tmp/file
echo ...
tail -2 /var/tmp/file
echo ===
head -2 /dev/loop0
echo ...
tail -2 /dev/loop0 
printf "I was here" > /dev/loop0
grep here /var/tmp/file
losetup -d /dev/loop0

输出:

loop device: /dev/loop0
/dev/loop0: [0808]:136392 (/var/tmp/file), offset 512, size 512
      0
      1
...
   9998
   9999
===
     64
     65
...
    126
    127
I was here   65
于 2012-12-02T19:37:22.397 回答
1

您不能从文件开头删除 30 个字节,但没有什么能阻止您覆盖文件(至少,在大多数 Unix 文件系统上)。就其花费的时间而言,这相当于一个副本,但它不会耗尽您的可用磁盘空间。

这里有一个可能会有所帮助的小功能,尽管我没有彻底测试它。

一个警告:它曾经off_t是一个 32 位有符号整数,因此 pread、pwrite 和 ftruncate 不能用于大于 2GB 的文件。在 Linux 上,情况不再如此。但是,可能需要使用 pread64、pwrite64 和 ftruncate64。在您确认它确实可以在您的操作系统上运行之前,不要在您关心的非常大的文件上尝试此操作。

int fshift(int fd, off_t to, off_t from) {
  if (from <= to) {
    fprintf(stderr, "%s\n", "Unimplemented: fshift can only shift left");
    errno = ERANGE;
    return -1;
  }
  char buffer[BUFFER_SIZE];
  for (;;) {
    ssize_t n_read = pread(fd, buffer, BUFFER_SIZE, from);
    if (n_read < 0) {
      int tmp = errno;
      perror("fshift: could not read file");
      errno = tmp;
      return -1;
    }
    from += n_read;
    if (n_read == 0) {
      int rc = ftruncate(fd, to);
      if (rc < 0) {
        int tmp = errno;
        perror("fshift: could not truncate file");
        errno = tmp;
      }
      return rc;
    }
    for (char* p = buffer, *lim = &buffer[n_read]; p < lim;) {
      ssize_t n_write = pwrite(fd, p, lim - p, to);
      if (n_write < 0) {
        int tmp = errno;
        perror("fshift: could not write file");
        errno = tmp;
        return -1;
      }
      p += n_write;
      to += n_write;
    }
  }
}
于 2012-12-02T21:23:33.930 回答