Linux和Windows稀疏文件拷贝移动

1. 概述

稀疏文件(英语:sparse file)是一种计算机文件,它能尝试在文件内容大多为空时更有效率地使用文件系统的空间。它的原理是以简短的信息(元数据)表示空数据块,而不是在在磁盘上占用实际空间来存储空数据块。只有真实(非空)的数据块会按原样写入磁盘。
在读取稀疏文件时,文件系统会按元数据在运行时将这些透明转换为“真实”的数据块,即填充为零。应用程序不会察觉这个转换。
大多数现代的文件系统支持稀疏文件,包括大多数Unix变种和NTFS。苹果的HFS+不提供稀疏文件支持,但在OS X中,虚拟档案系统层支持在任何受支持文件系统中存储稀疏文件,包括HFS+。2016年6月在WWDC宣布的苹果文件系统(APFS)支持稀疏文件。稀疏文件常被用在磁盘映像、数据库快照、日志文件和科学应用中。
稀疏文件(Sparse File), 指的是文件中出现大量的0数据,这些数据对我们用处不大,但是却一样的占用我们的空间,针对此,WINNT 3.51中的NTFS文件系统对此进行了优化,那些无用的0字节被用一定的算法压缩起来,使得这些0字节不再占用那么多的空间,在你声明一个很大的稀疏文件时(例如 100GB),这个文件实际上并不需要占用这么大的空间,因为里面大都是无用的0数据,那么,NTFS对稀疏文件的压缩算法可以释放这些无用的0字节空间, 可以说这是对磁盘占用空间以及效率的一种优化,记住,FAT32上并不支持稀疏文件的压缩。

1.1. 优势

稀疏文件的优势是,它分配的存储空间只在需要时使用:这样节省了磁盘空间,并且可以创建很大的文件,即使文件系统中的可用空间不足。这也减少了首次写入的时间,因为系统不会分配“跳过”的空间。如果初始分配需要写入全零到空间,这也使得系统不必写入两次。

1.2. 缺点

稀疏文件的缺点包括:稀疏文件可能碎片化;文件系统的空余空间报告可能产生误导;包含稀疏文件的文件系统被填满可能产生意外效果,例如只是重写现有文件的内容时遭遇磁盘已满或超出配额错误——开发者未预料到文件可能被稀疏;使用非显式支持的计算机程序复制稀疏文件可能会复制整个内容,即未压缩的文件大小,包括未实际在磁盘上分配的零空间——也就是使稀疏文件失去稀疏属性。稀疏文件也不是被所有备份软件和应用支持。不过,VFS的实现回避了先前两个缺点。在Windows上加载稀疏的可执行文件(exe或dll)可能需要更多时间,因为文件不被映射到内存和缓存。

该文章为平时工作学习时的笔记整理,仅供参考,有问题欢迎交流


2. Linux稀疏文件处理

2.1. 创建稀疏文件

稀疏文件通常对用户透明(不可见)处理。但在某些情况下,稀疏文件会与正常文件显现出差异。

2.1.1. dd命令创建

dd of=sparse-file bs=1k seek=5120 count=0

将创建一个5MB大小的文件,但不在磁盘上存储数据(仅存储元数据)。

2.1.2. truncate命令创建

truncate -s 5M 

2.1.3. qemu-img命令创建

qemu-img create -f qcow2 spare-file.qcow2 200G

2.2. 查看/显示稀疏文件

2.2.1. ls/du

ls命令显示文件大小的空间(由文件系统决定)。

ls -hl sparse-file

或者,du命令将打印占用的空间,而ls打印明面的大小。

du -hl sparse-file

2.2.2. qemu-img info

qemu-img info spare-file.qcow2

virtual size显示文件大小
disk size显示文件实际占用空间大小

2.3. 复制/拷贝保留稀疏性

2.3.1. cp

一般来说,GNU版本的cp是检测文件是否为稀疏文件的较好方式,所以
cp sparse-file new-file
创建一个新文件,它将是稀疏性质。但是,GNU版本的cp有–sparse=WHEN选项。[3]这尤为有用,如果一个已保存文件包含长串零块且非稀疏方式保存(即长串的零块已被完全写入并占用磁盘空间)。用此命令可以节省磁盘空间:

cp --sparse=always file1 file1_sparsed

在某些例如FreeBSD的cp实现中,–sparse选项不被支持,将始终展开稀疏文件。这些系统上的可行替代方案是使用rsync的–sparse选项[4]代替cp。遗憾的是–sparse无法与–inplace组合使用,因此通过网络rsync巨大文件时始终会浪费网络和磁盘带宽。
通过标准输入

 cp --sparse=always /proc/self/fd/0 new-sparse-file < somefile

2.3.2. scp(重点)

使用scp的后果是网络传输大小为该文件的virtual size ,造成浪费磁盘空间,如果这个稀疏文件很大的话,scp会很慢。
需要采用先tar后压缩,再scp,解决文件拷贝稀疏问题

tar cSf spare-file.qcow2.tar spare-file.qcow2
gzip spare-file.qcow2.tar
scp spare-file.qcow2.tar.gz root@controller1:/opt/

2.3.3. rsync -S

rsync --sparse sparse-1 sparse-1-copy
rsync -avSh spare-file.qcow2  /opt/

依文件系统而定,不建议使用

2.3.4. kvm虚拟机精简导出(重点)

KVM虚拟机的模版导出,通常都是直接用qemu-img命令可以将默认的raw格式或者qcow2格式的磁盘文件压缩后导出,指令如下:
//将默认raw格式的磁盘,简单压缩转换成qcow2格式

qemu-img convert -c -f raw -O qcow2 vm200G.raw /path/new-vm200G.qcow2

//将默认qcow2格式的磁盘,导出为简单压缩后的qcow2格式

qemu-img convert -c -O qcow2 vm200G.qcow2 new.img.qcow2

以上两种方法都能在一定程度上压缩减小导出后的镜像文件体积;但仅限于在虚拟机刚安装部署好,还没有进行过大量数据读写处理的情况下;
假如虚拟机磁盘大小分配200G,刚装好的操作系统加入占用了9G,那么通过以上的方式压缩导出的镜像文件可能也就只占9~10G左右;这是因为该磁盘镜像的大量的剩余空间都还没有被虚拟机的操作系统使用到(大量剩余block块都是空白的,未写入过数据)所以在导出的过程中,这些空白的block就会被压缩甚至忽略掉;所以这样压缩出来的缩效果还是很不错的;
但是,假如该虚拟机在装好后之后,有在磁盘上产生并存储过一个10G的大文件,尽管当前已经从虚拟机中彻底删除了这个大文件,虚拟机内的磁盘空间也显示剩余空间已经释放出来了,系统占用空间会变成跟系统刚装完时一样只有9GB;但此时再使用上面的指令对磁盘镜像文件进行压缩导出,你就会发现导出的文件体积比之前至少会多出10GB的体积;
这是因为虚拟机内删除文件,实际只是在分区表中把文件的索引给删除了,其10G文件的物理数据还是依然占用着磁盘上对应的block块的;此时在kvm下用qemu-img info指令就可以清楚看到该虚拟磁盘镜像的物理占用空间(disk size)比之前也变大了10GB;
那么有没有办法只导出当前虚拟机内实际占用的有效数据呢?将所有已经删除了的文件和其对应的磁盘block块都忽略掉,不要导出到我们的镜像文件中,以最大程度缩减导出来的文件体积!
方法就是在导出镜像之前,先在虚拟机系统的内部,对所有未使用,以及所有剩余可使用的磁盘空间进行全面置零填充操作,可以简单理解为将当前所有未存储有效数据的block(含已删除的文件block)全都进行写0覆盖,然后再进行镜像压缩导出,就可以忽略所有这些无用的数据空间了;
在虚拟机内部写零操作:

dd if=/dev/zero of=/null.dat   //创建一个全0的大文件,占满所有的剩余磁盘空间,需要很久时间
rm -f /null.dat                //删除这个文件

将虚拟机关机,执行镜像文件导出
针对raw格式虚拟磁盘文件精简导出

cp --sparse=always vm200G.raw vm200G-new.raw   //--sparse=always稀疏拷贝,忽略全0数据
qemu-img convert -c -f raw -O qcow2 vm200G.raw vm200G.qcow2

针对原本就是qcow2格式的虚拟磁盘文件精简导出

qemu-img convert -c -O qcow2 vm200G.qcow2 vm200G-mini.qcow2

3. Windows稀疏文件处理

如果一个文件的大部分数据是0,则这个文件被称包含了稀疏数据集。 文件压缩可以有效率地表示稀疏文件,但压缩与解压会带来时间代价。 NTFS文件系统支持稀疏文件表示,并对文件的读写操作透明。
为确定文件系统是否支持稀疏文件,调用GetVolumeInformation函数,使用lpFileSystemFlags参数,检查返回结果对应于FILE_SUPPORTS_SPARSE_FILES比特标志。 DWORD dwFileSystemFlags = 0; BOOL bOk = GetVolumeInformation(“C:\”, NULL, 0, NULL, NULL, &dwFileSystemFlags, NULL, 0); bOk = dwFileSystemFlags&FILE_SUPPORTS_SPARSE_FILES ; 判断一个文件是否是稀疏文件:GetFileInformationByHandle
大部分文件,在改变它的EndOfFile的时候,中间的空白会被操作系统填0,也就是说,如果用SetFilePointer和SetEndOfFile来产生一个很大的文件,那么这个文件它占用的是真正的磁盘空间,即使里面全是0,系统默认的也会在DeviceIoControl()中的ControlCode里用FSCTL_SET_ZERO_DATA标记,这个标记使得那些文件空洞被0所填充。为了节省磁盘空间,必须把一个文件声明为稀疏文件,以便让系统把那些无用的0字节压缩,并释放相应的磁盘空间,这需要用DeviceIoControl()将标记改为FSCTL_SET_SPARSE。

3.1. fsutil sparse

适用于:Windows Server 2022、Windows Server 2019、Windows Server 2016、Windows 10、Windows Server 2012 R2、Windows 8.1、Windows Server 2012、Windows 8
管理稀疏文件。 稀疏文件是包含一个或多个未分配数据区域的文件。
程序将这些未分配的区域视为包含值为零的字节,并且没有表示这些零的磁盘空间。 读取稀疏文件时,分配的数据作为存储返回,并且根据 C2 安全要求规范,未分配的数据默认返回为零。 稀疏文件支持允许从文件中的任何位置释放数据。

语法:

fsutil sparse [queryflag] 
fsutil sparse [queryrange] 
fsutil sparse [setflag] 
fsutil sparse [setrange]   

参数:

参数 说明
queryflag 查询稀疏。
queryrange 扫描文件并搜索可能包含非零数据的范围。
setflag 将指示的文件标记为稀疏文件。
setrange 用零填充文件的指定范围。
指定文件的完整路径,包括文件名和扩展名,例如C:\documents\filename.txt。
指定文件中要标记为稀疏的偏移量。
指定文件中要标记为稀疏区域的区域长度 (字节数) 。

注解
分配所有有意义的或非零数据,而所有 (数据包含由零组成的大型数据字符串,) 分配。
在稀疏文件中,较大的零范围可能不需要磁盘分配。 写入文件时,将根据需要分配非零数据的空间。
只有压缩文件或稀疏文件才能具有操作系统已知的零范围。
如果文件稀疏或压缩,NTFS 可能会取消分配文件内的磁盘空间。 这会在不扩展文件大小的情况下将字节范围设置为零。

3.2. 示例

若要将 c:\tempsample.txt中名为sample.txt的文件标记为稀疏,请键入:

fsutil sparse setflag c:\temp\sample.txt

4. 参考文献

https://zh.wikipedia.org/zh-hans/%E7%A8%80%E7%96%8F%E6%96%87%E4%BB%B6
https://yo.zgserver.com/x658.html
https://blog.csdn.net/allway2/article/details/101084050
https://docs.microsoft.com/zh-cn/windows-server/administration/windows-commands/fsutil-sparse
https://blog.csdn.net/allway2/article/details/101084050
https://www.moonfly.net/archives/50.html

你可能感兴趣的:(linux,linux,windows,unix)