曾经有几次,我用ls和du查看一个文件的大小,发现二者显示出来的大小并不一致,例如:

bl@d3:~/test/sparse_file$ ls -l fs.img
-rw-r--r-- 1 bl bl 1073741824 2012-02-17 05:09 fs.img
bl@d3:~/test/sparse_file$ du -sh fs.img
0 fs.img

这里ls显示出fs.img的大小是1073741824字节(1GB),而du显示出fs.img的大小是0。

原来一直没有深究这个问题,今天特来补上。

造成这二者不同的原因主要有两点:

  • 稀疏文件(sparse file)
  • ls和du显示出的size有不同的含义

先来看一下稀疏文件。稀疏文件只文件中有“洞”(hole)的文件,例如有C写一个创建有“洞”的文件:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h> int main(int argc, char *argv[])
{
int fd = open("sparse.file", O_RDWR|O_CREAT);
lseek(fd, , SEEK_CUR);
write(fd, "\0", ); return ;
}

从这个文件可以看出,创建一个有“洞”的文件主要是用lseek移动文件指针超过文件末尾,然后write,这样就形成了一个“洞”。

用Shell也可以创建稀疏文件:

$ dd if=/dev/zero of=sparse_file.img bs=1M seek=1024 count=0
0+0 records in
0+0 records out

使用稀疏文件的优点如下(Wikipedia上的原文):

The advantage of sparse files is that storage is only allocated when actually needed: disk space is saved, and large files can be created even if there is insufficient free space on the file system.

即稀疏文件中的“洞”可以不占存储空间。

再来看一下ls和du输出的文件大小的含义(Wikipedia上的原文):

The du command which prints the occupied space, while ls print the apparent size。

换句话说,ls显示文件的“逻辑上”的size,而du显示文件“物理上”的size,即du显示的size是文件在硬盘上占据了多少个block计算出来的。举个例子:

bl@d3:~/test/sparse_file$ echo -n 1 > 1B.txt
bl@d3:~/test/sparse_file$ ls -l 1B.txt
-rw-r--r-- 1 bl bl 1 2012-02-19 05:17 1B.txt
bl@dl3:~/test/sparse_file$ du -h 1B.txt
4.0K 1B.txt

这里我们先创建一个文件1B.txt,大小是一个字节,ls显示出的size就是1Byte,而1B.txt这个文件在硬盘上会占用N个 block,然后根据每个block的大小计算出来的。这里之所以用了N,而不是一个具体的数字,是因为隐藏在幕后的细节还很多,例如Fragment size,我们以后再讨论。

当然,上述这些都是ls和du的缺省行为,ls和du分别提供了不同参数来改变这些行为。比如ls的-s选项(print the allocated size of each file, in blocks)和du的--apparent-size选项(print  apparent  sizes,  rather than disk usage; although the apparent size is usually smaller, it may be larger due to holes in (`sparse') files, internal fragmentation, indirect blocks, and the like)。

此外,对于拷贝稀疏文件,cp缺省情况下会做一些优化,以加快拷贝的速度。例如:

strace cp fs.img fs.img.copy >log 2>&1

打开log文件,我们发现cp命令只是read和lseek,并没有write。

stat("fs.img.copy", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
stat("fs.img", {st_mode=S_IFREG|0644, st_size=1073741824, ...}) = 0
stat("fs.img.copy", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
open("fs.img", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=1073741824, ...}) = 0
open("fs.img.copy", O_WRONLY|O_TRUNC) = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
mmap(NULL, 532480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f90df965000
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 524288) = 524288
lseek(4, 524288, SEEK_CUR) = 524288
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 524288) = 524288
lseek(4, 524288, SEEK_CUR) = 1048576
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 524288) = 524288
lseek(4, 524288, SEEK_CUR) = 1572864

这和cp的关于sparse的选项有关,看cp的manpage:

By  default,  sparse  SOURCE files are detected by a crude heuristic and the corresponding DEST file is made sparse as well.  That is the behavior selected by --sparse=auto.  Specify --sparse=always to create a sparse DEST file whenever the SOURCE file contains a long enough sequence of  zero bytes.  Use --sparse=never to inhibit creation of sparse files.

看了一下cp的源代码,发现每次read之后,cp会判断读到的内容是不是都是0,如果是就只lseek而不write。

当然对于sparse文件的处理,对于用户都是透明的。

(转)为什么用ls和du显示出来的文件大小有差别?的更多相关文章

  1. 为什么用ls和du显示出来的文件大小有差别?【转】

    在使用Linux ls命令查看文件大小时,发现文件很大,足有100个G,而使用du命令查看则不超过10个G. [root@shanghai devicemapper]# ls -l 总用量 -rwxr ...

  2. Docker - docker images存储位置,引出ls和du命令的不同

    docker镜像存储位置 docker info | grep "Docker Root Dir" 例如我的driver是overlay2,则docker镜像的实际存储在/var/ ...

  3. Linux下df与du两个命令的差别?

    Linux下df与du两个命令的差别? 一.df显示文件系统的使用情况,与du比較,就是更全盘化. 最经常使用的就是 df -T,显示文件系统的使用情况并显示文件系统的类型. 举比例如以下: [roo ...

  4. Linux下用ls和du命令查看文件以及文件夹大小

    ls的用法 ls -l |grep "^-"|wc -l或find ./company -type f | wc -l  查看某文件夹下文件的个数,包括子文件夹里的. ls -lR ...

  5. Linux下用ls和du命令查看文件以及文件夹大小(转)

    转自:https://www.cnblogs.com/xueqiuqiu/p/7635722.html ls的用法 ls -l |grep "^-"|wc -l或find ./co ...

  6. QCOW2/RAW/qemu-img 概念浅析

    目录 目录 扩展阅读 RAW QCOW2 QEMU-COW 2 QCOW2 Header QCOW2 的 COW 特性 QCOW2 的快照 qemu-img 的基本使用 RAW 与 QCOW2 的区别 ...

  7. 转 由一次磁盘告警引发的血案:du 和 ls 的区别

    如果你完全不明白或者完全明白图片含义, 那么你不用继续往下看了. 否则, 这篇文章也许正是你需要的. 背景 确切地说,不是收到的自动告警短信或者邮件告诉我某机器上的磁盘满了,而是某同学人肉发现该机器写 ...

  8. Linux的磁盘系统和文件系统显示的文件大小为什么不一样(du指令和ls指令的区别)

    写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...

  9. ls命令

    ls(list) 命令可以说是Linux下最常用的命令之一 #ls -l;列出文件的详细信息 #ll 以上两个命令一样,ll是ls -l的简写 #ls -al;列出目录下的所有文件,包括以 . 开头的 ...

随机推荐

  1. Android菜鸟成长记14 -- AsnyTask

    本篇随笔将讲解一下Android的多线程的知识,以及如何通过AsyncTask机制来实现线程之间的通信. 一.Android当中的多线程 在Android当中,当一个应用程序的组件启动的时候,并且没有 ...

  2. CSS考试题目

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  3. angular 调试 js (分 karms protractor / test e2e unit )

    首页订阅 Protractor端到端的AngularJS测试框架教程 2014年01月18日 分类:教程, JavaScript, AngularJS Protractor是一个建立在WebDrive ...

  4. Mysql Communication link failure :1153 Got a packet bigger than 'max_allowed_packet' bytes

    出现这种情况: 临时解决方法是: 登录mysql: 执行: set global max_allowed_packet=1000000000;       set global net_buffer_ ...

  5. 【POJ2778】DNA Sequence(AC自动机,DP)

    题意: 生物课上我们学到,DNA序列中只有A, C, T和G四种片段. 经科学发现,DNA序列中,包含某些片段会产生不好的基因,如片段"ATC"是不好片段,则"AGATC ...

  6. 【Android端APP 安装包检查】安装包检查具体内容及实现方法

    一.安装包检查的具体包含内容有哪些? 1.安装包检查的一般内容包括: 安装包基本信息检查: 文件大小: xx MB 包名: com.xx 名称:  xx 本次安装包证书与外网证书对比一致性:是 版本号 ...

  7. 用任意语言与WebService进行交互

    using System; using System.Web.Services; using YY.SmsPlatform.Common.Objects; using YY.SmsPlatform.C ...

  8. jquery制作省份城市地区多选控件总结

    1.弹出的选择框有jquery直接放在body后面,以position:absolute绝对定位,top,left处理位置. 如果想让该选择框位于点选元素下面,则获取点选元素位置 var target ...

  9. CSS3 animation 的尝试

    下面是动画效果: .zoombie { width: 55px; height: 85px; background-image: url("http://images2015.cnblogs ...

  10. ASP.NET页面中去除VIEWSTATE视图状态乱码

    保存页的所有视图状态信息和控件状态信息. 基于SEO技术的开发,在没有接触MVC框架 Razor 引擎的时候,我们需要使用ASP.NET引擎,如果使用ASP.NET引擎的服务器端控件,那么在ASP.N ...