Linux 中的 I/O 设备大致分为两类:块设备和字符设备。块设备将信息存储在固定大小的块中,每个块都有自己的地址,都能独立于其它块而读写。磁盘是最常见的块设备。虚拟块设备文件则是将块设备封装成为一个文件,比如硬盘镜像文件(Hard Disk Image)(但不是所有的硬盘镜像文件都是虚拟块设备文件,比如 Ghost 的 GHO 格式的镜像文件就不是,它不能挂载为虚拟机中的硬盘直接使用)。
Linux 的 dd 命令,可以用于生成虚拟块设备文件。既可以用于创建空镜像文件,也可以用于创建物理硬盘的镜像。
例如,
# dd if=/dev/sda1 of=/sda1_dd.img 1024000+0 records in 1024000+0 records out 524288000 bytes (524 MB) copied, 21.4127 s, 24.5 MB/s
就可以将设备(硬盘分区)/dev/sda1 保存成为镜像文件 sda1_dd.img。参数 if 指定读取数据的源,of 指定数据写入的目标文件。注意,对于 dd 来说,输入和输出都是文件,dd 只是进行文件拷贝,实际上 Unix/Linux 下设备都是抽象为特殊的文件的。看看该文件,
# ls -al / | grep "dd" -rw-r--r-- 1 root root 524288000 Aug 20 06:43 sda1_dd.img
块设备的特点是可以随机读写(Random Access),比如内存、硬盘等。字符设备的特点是顺序读写(Sequential Access),比如鼠标,键盘,麦克风等。
如果想生成空镜像文件(也就是没什么有用内容的文件,仅仅是“占位”,比如 Linode VPS 提供的下载速度测试文件),还需要一个特殊的设备。/dev/zero 是 Linux 提供的一个特殊的字符设备(伪文件,Pseudo-devices),它的特点是可以永远读该文件,每次读取的结果都是二进制 0。下面的命令可以生成一个 100M 的空镜像文件:
dd if=/dev/zero of=/100m.img bs=1M count=100
这里的 bs=1M 表示每一次读写 1M 数据,count=100 表示读写 100 次。所以生成文件的大小也就是 100M 了。bs 参数还可以细分为 ibs 和 obs 两种,为读操作与写操作分别指定不同的 Buffer 大小。
既然这个文件实际上也没什么内容(内容都是重复的),而如果要生成 1G 的虚拟块设备文件,就得占用 1G 的硬盘空间,为了不占用那么多的实际硬盘空间,可以使用 Linux 支持的 sparse(稀疏)文件。将上面的命令行改为,
# dd if=/dev/zero of=/1g.img bs=1M seek=1000 count=0 0+0 records in 0+0 records out 0 bytes (0 B) copied, 3.101e-05 s, 0.0 kB/s
这里用了一个新的参数 seek,表示略过 1000 个 Block 不写(这里 Block 按照 bs 的定义是 1M ),count=0 表示写入 0 个 Block。然后用 ls 命令看看写入的文件 1g.img:
# ls -al / | grep "1g" -rw-r--r-- 1 root root 1048576000 Aug 20 07:15 1g.img
大小是 1048MB,而实际占用的磁盘空间:
# du -m /1g.img 0 /1g.img
貌似是 0。但是如果从服务器上下载这个文件,那可就是实打实的 1GB 数据了。
另外,dd 还有个不是很常用的用法,从一个设备拷贝数据到另一个设备,比如,从旧硬盘到新硬盘。用法:
dd if=/dev/sda of=/dev/sdb
因为 dd 复制数据的时候是一个字节一个字节的来的,所以当旧硬盘上的空余空间比较多的时候,就会比 cp(复制)命令要长得多的时间,而且是不必要的。下面指定一次复制 1M 位,这样会稍微少些时间:
dd if=/dev/sda of=/dev/sdb bs=1M
这样用的时候,新硬盘(这里的 sdb)必须比旧硬盘大,或者至少一样大,否则会丢失数据,或者会导致操作失败。而且,如果新硬盘比旧硬盘大,拷贝完成之后,新硬盘还会剩余一些“未被使用”的空间,也就是说,如果加载了文件系统,从新硬盘中能够直接使用的空间与旧硬盘是一样大的,而那些空余的空间需要用别的方法增加到新硬盘上现有的文件系统中。©
本文发表于水景一页。永久链接:<https://cnzhx.net/blog/linux-dd-make-an-image-file/>。转载请保留此信息及相应链接。