Webの周りでは、ファイルの使用開始時に> filename
またはtruncate -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
以下の-u
を使用してファイルを開き、ファイルタイプがASCII text
からdata
に変更され、ls -l filename
を使用するとサイズが異なります。 tが変更されました
したがって、ファイルを切り捨てると、ファイルのオフセットがレポートされない場合、これを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);
}
システムコールは切り捨てと呼ばれますが、実際には「ファイルにこの数バイトのサイズを報告させる」と解釈する方が適切です。システムコールのマンページによると:
Truncate()およびftruncate()関数を使用すると、pathで指定された、またはfdで参照された通常のファイルが、正確な長さのバイトのサイズに切り捨てられます。
以前にファイルがこのサイズよりも大きかった場合、余分なデータは失われます。以前にファイルが短かった場合、ファイルは拡張され、拡張された部分はnullバイト( '\ 0')として読み取られます。
したがって、ファイルを切り捨てて、小さくするのではなく大きくすることができます。
だから私の質問は、私のプロセスがpos 1000で開いているファイルを持っていて、-s0ファイル名を切り捨てた場合、切り捨てが機能する場合、次のプロセスの書き込みで何が起こるかということです。
ファイル自体よりも大きい位置からファイルに書き込む場合、ファイルの終わりと新しい書き込みの間のデータはnullバイトになり、これら2つのポイントの間のファイルデータはsparseと呼ばれます。 。
確かに、あなたは次のことをして同じ効果を生み出すことができます。
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': ''