当我截断正在使用的文件时会发生什么?

当我截断正在使用的文件时会发生什么?

网上很多人说你可以使用> filenametruncate -s0 filename当文件开始使用时截断文件

我知道每次一个进程写入一个文件时,该进程都会使用一个偏移量来写入文件,并使用这样的脚本进行测试。

#!/usr/bin/env python

import os, time

with open("passwd","w") as f: #copy of passwd file in my current directory
        f.seek(0)
        for x in xrange(1,1000):
                f.write("hello world \n" + time.ctime() + "\n")
                f.flush()
                time.sleep(2)

每次我的脚本进行写入系统调用时,/proc/pid_number/fdinfo/3 pos字段中的偏移量都会发生变化,但是当我尝试使用上面列出的方法截断文件时,在我的文件中,当我使用或更少^@打开文件时,我会看到许多这样的字符 ,文件类型从更改为,而当我使用时,大小没有改变vim-uASCII textdatals -l filename

因此,当截断文件时,文件的偏移量不会报告,我在Centos 7和中对此进行了测试Redhat 5,因此我可以判断,当文件正在被进程使用时更改了文件大小,不会释放空间并弄脏我的文件。

所以我的问题是,如果我的进程中打开了一个文件pos 1000并且我确实这样做了truncate -s0 filename,如果截断有效,那么在下一个进程写入时会发生什么?

strace truncate -s0 passwd
open("passwd", O_WRONLY|O_CREAT|O_NONBLOCK, 0666) = 3
ftruncate(3, 0)                         = 0
close(3)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?

 ls -l passwd 
 -rw-rw-r--. 1 user91 users 13832 Feb 23 17:16 passwd

正如你所见,我的文件没有被截断

如果我打开附加模式(例如使用此代码),则不会发生此问题。

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>


int main(){
        int range = 1000;
        int x; x = open("passwd", O_WRONLY|O_CREAT|O_APPEND);
        int i = 0;
        for( i = 0; i <= range; range++)
                write(x,"hello world\n",12);
                sleep(2);
}

答案1

请注意,尽管系统调用被称为截断,但实际上最好将其解释为“让我的文件报告这么多字节的大小”。根据系统调用手册页:

truncate() 和 ftruncate() 函数导致由路径命名或由 fd 引用的常规文件被截断为精确长度字节的大小。

如果文件之前大于此大小,则多余数据将丢失。如果文件之前较短,则文件将扩展,扩展部分将读取为空字节 ('\0')。

因此,可以截断文件并使其变大,而不是变小。

所以我的问题是,如果我的进程在 pos 1000 中打开了一个文件,并且我确实截断了 -s0 文件名,如果截断有效,那么下一个进程写入时会发生什么?

  • 您已截断。此阶段的文件大小为 0 字节。偏移量为 1000。
  • 在位置 1001 处发生写入。
  • 文件大小为 1002 字节。字节 0-1000 包含“\0”(空)。字节 1001+ 包含写入的数据。

当你从大于文件本身的位置写入文件时,文件末尾和新写入之间的数据将成为空字节,并且这两点之间的文件数据被称为

事实上,您可以执行以下操作并产生相同的效果。

import os, sys

f = open('data.txt','w')
f.seek(1048576)
f.write('a')
f.flush()
f.close()

您还提到,以追加模式打开可以避免这种行为。这是真的,因为在这种情况下,您正在指示内核“每次都写入文件的实际末尾”。如果您截断,则文件末尾会发生变化。在追加中,您无法重新定位文件指针。

这是一个示例程序,演示了被截断的文件、偏移量和文件中的数据会发生什么情况。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <err.h>

#define FPATH "/tmp/data.txt"
#define FSIZE 65536

int main() {
  int a,b;
  char buf[FSIZE];
  char byte;
  struct stat st;
  memset(buf, 'A', FSIZE);

  a = open(FPATH, O_WRONLY|O_CREAT);
  b = open(FPATH, O_RDONLY);

  if (a < 0 || b < 0)
    errx(EXIT_FAILURE, "Could not open file");

  printf("Writing %d * 'A' into file\n", FSIZE);
  /* Write some bytes */
  if(write(a, buf, FSIZE) != FSIZE)
    errx(EXIT_FAILURE, "Couldn't write complete size out");

  /* Seek to a  new position in the file */
  lseek(b, FSIZE/2, SEEK_SET);

  printf("Current position of handle 'a': %d\n", lseek(a, 0, SEEK_CUR));
  printf("Current position of handle 'b': %d\n", lseek(b, 0, SEEK_CUR));
  stat(FPATH, &st);
  printf("Reported size on filesystem of %s: %d\n", FPATH, st.st_size);

  /* OK -- now, read the byte at the position */
  if (read(b, &byte, 1) < 0)
    err(EXIT_FAILURE, "Could not read file");
  printf("Character at current position of handle 'b': '%c'\n", byte);

  /* Truncate the file in the 'a' handle */
  printf("Performing truncate...\n");
  if (ftruncate(a, 0) < 0)
    err(EXIT_FAILURE, "Cannot truncate file");

  printf("Current position of handle 'a': %d\n", lseek(a, 0, SEEK_CUR));
  printf("Current position of handle 'b': %d\n", lseek(b, 0, SEEK_CUR));
  stat(FPATH, &st);
  printf("Reported size on filesystem of %s: %d\n", FPATH, st.st_size);

  printf("Writing one byte via handle 'a'\n");
  if (write(a, buf, 1) < 0)
    err(EXIT_FAILURE, "Cannot perform second write");

  printf("Current position of handle 'a': %d\n", lseek(a, 0, SEEK_CUR));
  printf("Current position of handle 'b': %d\n", lseek(b, 0, SEEK_CUR));
  stat(FPATH, &st);
  printf("Reported size on filesystem of %s: %d\n", FPATH, st.st_size);

  if (read(b, &byte, 1) < 0)
    err(EXIT_FAILURE, "Could not read file");
  printf("Character at current position of handle 'b': '%c'\n", byte);


  close(a);
  close(b);
  exit(0);
}

这导致以下输出;

Writing 65536 * 'A' into file
Current position of handle 'a': 65536
Current position of handle 'b': 32768
Reported size on filesystem of /tmp/data.txt: 65536
Character at current position of handle 'b': 'A'
Performing truncate...
Current position of handle 'a': 65536
Current position of handle 'b': 32769
Reported size on filesystem of /tmp/data.txt: 0
Writing one byte via handle 'a'
Current position of handle 'a': 65537
Current position of handle 'b': 32769
Reported size on filesystem of /tmp/data.txt: 65537
Character at current position of handle 'b': ''

相关内容