什么是“稀疏文件”("sparse file"),可以識別它們嗎?


環境

  • 紅帽企業版Linux 5、6和7

問題

  • 文件的ls和df之間的文件大小不一致。
  • 該文件報告較大(128Gb),但文件系統甚至沒有那么大。這怎么可能?

    # ls -lah datafile
     -rw------- 1 root root 137438953440 May 28 10:05 datafile 
    
    # df -h 
    Filesystem Size Used Avail Use% Mounted on 
    /dev/sda     20G 9.8G 9.0G 53%     /         

     

決議

  • 有問題的文件可能是稀疏文件
  • 稀疏文件是指其元數據報告一個大小的文件,但是文件的實際數據消耗的大小不同。
  • 稀疏文件是有效使用磁盤空間的常用方法。
  • 您可以使用ls -lsh命令查看稀疏文件。這提供了兩個大小列:

    $ ls -lsh datafile
     12G -rw-r----- 1 root root 24G 2010-01-10 19:55 data 
     ^ - - - - - - - - - - - - - ^ 

     

  • 第一列是實際使用的磁盤空間。該文件實際上消耗了12Gb的空間。

  • 第二個大小列提供文件元數據的大小。該文件的元數據報告它是24Gb文件。

稀疏文件的使用

  • 要復制稀疏文件,必須使用能夠識別稀疏文件的命令。

  •     cp --sparse=always /source/filename /destination/filename
        dd if=/source/filename of=/destination/filename conv=sparse
        rsync -S /source/filename root@hostname:/destination/filename

     

  • 使用scp實用程序復制文件將導致“非稀疏”文件擴展為完整大小。

根本原因

  • 在稀疏文件中,與那些區域保存非零數據時相比,文件全為0x00的部分被壓縮以占用更少的空間。

診斷步驟

可以使用truncate命令輕松創建稀疏文件:

 
# truncate --size=1G sparsefile.bin 

我們可以使用ls -lsh查看稀疏文件的大小:

 
# ls -lsh sparsefile.bin 
0 -rw-r--r-- 1 root root 1.0G Nov 6 09:00 sparsefile.bin 

 

該文件占用0字節的空間,但是其元數據報告文件大小為1Gb。

我們可以將1Mb寫入該文件:

 
# for i in {1..1048576}; do echo -n "a" >> sparsefile.bin; done 

 

然后再次檢查其大小:

 
 # ls -lsh sparsefile.bin 
1.0M -rw-r--r-- 1 root root 1.1G Nov 6 09:01 sparsefile.bin

 

該文件現在消耗了1Mb的實際空間,但是元數據報告的使用量為1.1Gb。元數據的輕微增長是由於分配了文件系統塊來存儲文件的數據。

將此文件與相同大小的完全分配的文件進行比較:

 
 # dd if=/dev/zero of=fullfile.bin bs=1M count=1024 conv=fsync 
# ls -lsh fullfile.bin 
1.1G -rw-r--r-- 1 root root 1.0G Nov 6 09:05 fullfile.bin 

 

該文件實際消耗了1Gb以上的空間,其元數據報告的文件大小也為1Gb。

我們可以使用stat命令從這兩個文件中獲取更多信息:

# stat sparsefile.bin
 File: `sparsefile.bin'
 Size: 1074790400 Blocks: 2048 IO Block: 4096 regular file 
Device: fd00h/64768d Inode: 134154 Links: 1 
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) 

# stat fullfile.bin
 File: `fullfile.bin'
 Size: 1048576000 Blocks: 2048008 IO Block: 4096 regular file 
Device: fd00h/64768d Inode: 134403 Links: 1 
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) 

 

在上方,我們看到稀疏文件比完整文件消耗更少的文件系統塊。

我們可以使用filefrag命令收集文件系統分配信息:

 
# filefrag sparsefile.bin 
sparsefile.bin: 1 extent found

# filefrag fullfile.bin
fullfile.bin: 29 extents found

 

上面我們可以看到,稀疏文件已在一個較小的范圍內分配,而完整文件已在多個范圍內分配。

可以使用以下基本示例在C中創造稀疏文件:

#include <stdio.h>

int main() {
    FILE *fp;

    fp = fopen("hello.txt", "w+");
    fseek(fp, 1048576, SEEK_CUR);
    fputs("Hello\n", fp);
    fclose(fp);

    return 0;
}

 

這將創建一個1 MB的文件,放入“ Hello”寫入其中。在strace系統調用跟蹤器下運行以上命令顯示:

09:00:20 open("hello.txt", O_RDWR|O_CREAT|O_TRUNC, 0666) = 3 <0.000056>
09:00:20 fstat(3, {st_dev=makedev(253, 2), st_ino=20188301, st_mode=S_IFREG|0664, st_nlink=1, st_uid=1000, st_gid=1000, st_blksize=4096, st_blocks=0, st_size=0, st_atime=2014/11/08-09:00:20, st_mtime=2014/11/08-09:00:20, st_ctime=2014/11/08-09:00:20}) = 0 <0.000005>
09:00:20 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f469d042000 <0.000007>
09:00:20 lseek(3, 1048576, SEEK_CUR)    = 1048576 <0.000005>
09:00:20 write(3, "Hello\n", 6)         = 6 <0.000018>
09:00:20 close(3)                       = 0 <0.000006>

 

我們可以看到我們的文件是稀疏創建的,它報告的大小為1Mb,但僅消耗一個4kb的文件系統塊:

$ ls -ls hello.txt 
4 -rw-rw-r--. 1 username username 1048582 Nov  8 09:00 hello.txt

 

 
        


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM