西部數(shù)碼網(wǎng)站管理助手4.0 破解版鏈接交易網(wǎng)
這段代碼是一個(gè)模仿 Linux dd 命令的工具,它用于在不同文件之間復(fù)制數(shù)據(jù)。dd 是一個(gè)非常強(qiáng)大的命令行工具,可以用于數(shù)據(jù)備份、轉(zhuǎn)換和復(fù)制。下面我將詳細(xì)解釋這段代碼的原理、實(shí)現(xiàn)方式以及如何運(yùn)行和測試。
Linux dd 命令的工作原理
dd 命令是 Unix 和 Linux 系統(tǒng)中非常強(qiáng)大的文件復(fù)制和轉(zhuǎn)換工具。它通過指定塊大小(block size)來讀取和寫入數(shù)據(jù),實(shí)現(xiàn)高效的文件或設(shè)備復(fù)制。dd 命令不僅能夠處理普通文件,還能直接操作設(shè)備文件,這使得它在系統(tǒng)備份、恢復(fù)和數(shù)據(jù)克隆等任務(wù)中非常有用。
-
基本語法:
dd if=輸入文件 of=輸出文件 [選項(xiàng)]
if
:指定輸入文件名或設(shè)備名。of
:指定輸出文件名或設(shè)備名。[選項(xiàng)]
:各種可選參數(shù),用于控制復(fù)制行為。
-
常用選項(xiàng):
bs
:設(shè)置讀寫的塊大小。例如:bs=4M
。count
:復(fù)制的塊數(shù)。例如:count=1
。conv
:指定數(shù)據(jù)轉(zhuǎn)換選項(xiàng),如conv=sync
確保同步模式。status=progress
:顯示詳細(xì)的進(jìn)度信息。
-
工作流程:
- 打開源和目標(biāo)文件/設(shè)備:dd 命令會(huì)先嘗試打開指定的輸入和輸出文件或設(shè)備。
- 按塊讀取和寫入:根據(jù)指定的塊大小(bs),dd 從輸入文件或設(shè)備讀取數(shù)據(jù),并寫入到輸出文件或設(shè)備中。
- 數(shù)據(jù)處理:在讀寫過程中,dd 可以根據(jù)指定的轉(zhuǎn)換選項(xiàng)對(duì)數(shù)據(jù)進(jìn)行處理,如大小寫轉(zhuǎn)換、字節(jié)順序轉(zhuǎn)換等。
- 重復(fù)操作:上述過程會(huì)根據(jù)指定的塊數(shù)(count)反復(fù)進(jìn)行,直到完成所有數(shù)據(jù)的復(fù)制或轉(zhuǎn)換。
命令行使用
dd
的基本命令行格式如下:
dd if=<input_file> of=<output_file> [其他參數(shù)]
- if:指定輸入文件。
- of:指定輸出文件。
以下是一些常用的參數(shù)示例:
- bs:設(shè)置塊大小,例如
bs=1024
。 - count:設(shè)置復(fù)制的塊數(shù),例如
count=10
。 - skip:設(shè)置跳過的塊數(shù),例如
skip=5
。 - seek:設(shè)置輸出文件中跳過的塊數(shù),例如
seek=5
。
示例
復(fù)制一個(gè)文件的前 10MB 到另一個(gè)文件:
dd if=/dev/zero of=example.img bs=1M count=10
將一個(gè)磁盤分區(qū)備份到另一個(gè)磁盤分區(qū):
dd if=/dev/sda of=/dev/sdb
基本文件復(fù)制:
dd if=inputfile of of=outputfile bs=64K count=1
將 inputfile 復(fù)制到 outputfile,每次讀取和寫入 64KB 的數(shù)據(jù)塊,只復(fù)制一個(gè)塊。
備份和還原硬盤:
dd if=/dev/sda of=/path/to/backup.img bs=4M
dd if=/path/to/backup.img of=/dev/sdb bs=4M
將整個(gè)硬盤 /dev/sda 備份到 backup.img 文件中,然后將 backup.img 還原到 /dev/sdb。
創(chuàng)建鏡像文件:
dd if=/dev/zero of=imagefile.img bs=1G count=10
創(chuàng)建一個(gè)名為 imagefile.img 的 10GB 鏡像文件,內(nèi)容全為零。
制作啟動(dòng)盤:
dd if=boot.img of=/dev/sdb bs=4M
將 boot.img 寫入到 USB 設(shè)備 /dev/sdb,制作可啟動(dòng)的 USB 盤。
擦除硬盤數(shù)據(jù):
dd if=/dev/urandom of of=/dev/sda bs=4M
使用隨機(jī)數(shù)據(jù)覆蓋整個(gè)硬盤,確保數(shù)據(jù)無法恢復(fù)。
日常定位分析
dd
命令在系統(tǒng)恢復(fù)、數(shù)據(jù)恢復(fù)和磁盤克隆等場景中非常有用。例如,當(dāng)你需要從一個(gè)損壞的文件系統(tǒng)中恢復(fù)數(shù)據(jù)時(shí),可以使用 dd
來復(fù)制文件系統(tǒng)的一部分到另一個(gè)健康的磁盤上,然后對(duì)復(fù)制的數(shù)據(jù)進(jìn)行分析和恢復(fù)。
三、dd 命令在實(shí)際工作中的定位與分析
dd 命令因其強(qiáng)大的功能和靈活性,在系統(tǒng)管理和運(yùn)維工作中有著廣泛的應(yīng)用場景。以下是幾個(gè)典型的應(yīng)用場景及其分析:
-
系統(tǒng)備份與恢復(fù):
- 場景:定期備份服務(wù)器上的硬盤或分區(qū),以防數(shù)據(jù)丟失或系統(tǒng)故障。
- 分析:通過 dd 命令,可以創(chuàng)建整個(gè)硬盤或分區(qū)的鏡像文件,方便存儲(chǔ)和快速恢復(fù)。此外,還可以使用壓縮工具(如 gzip)進(jìn)一步減小鏡像文件的大小。
-
數(shù)據(jù)克隆和遷移:
- 場景:在更換硬盤或遷移數(shù)據(jù)時(shí),需要將舊硬盤上的數(shù)據(jù)完整復(fù)制到新硬盤。
- 分析:dd 命令可以直接操作設(shè)備文件,無需經(jīng)過文件系統(tǒng),從而提高數(shù)據(jù)復(fù)制的效率和可靠性。這對(duì)于大規(guī)模數(shù)據(jù)遷移尤其有用。
-
制作啟動(dòng)盤和恢復(fù)盤:
- 場景:需要制作可啟動(dòng)的 USB 盤或 CD/DVD,用于系統(tǒng)安裝或故障排查。
- 分析:dd 命令可以將 ISO 鏡像文件直接寫入到 USB 或光盤設(shè)備,操作簡單且高效。這在緊急情況下尤為重要,如系統(tǒng)崩潰后的恢復(fù)工作。
-
安全刪除數(shù)據(jù):
- 場景:需要徹底刪除敏感數(shù)據(jù),確保無法通過恢復(fù)工具找回。
- 分析:通過用隨機(jī)數(shù)據(jù)覆蓋硬盤,可以有效防止數(shù)據(jù)被恢復(fù)。這種方法比單純的文件刪除更為安全,適用于處理包含敏感信息的硬盤。
-
性能測試:
- 場景:測試磁盤的讀寫速度,評(píng)估存儲(chǔ)設(shè)備的性能。
- 分析:dd 命令可以生成大規(guī)模的測試數(shù)據(jù),并通過計(jì)時(shí)等方式測量磁盤的讀寫速度。這對(duì)于存儲(chǔ)設(shè)備的選型和性能優(yōu)化具有重要參考價(jià)值。
Linux dd 命令詳解:工作原理與實(shí)用指南(C/C++代碼實(shí)現(xiàn))
size_t free_mem()
{uint64_t n = 0;char buf[1024], found = 0;FILE *f = fopen("/proc/meminfo", "r");if (!f)return 1024*1024;memset(buf, 0, sizeof(buf));for (;!feof(f);) {fgets(buf, sizeof(buf), f);if (strstr(buf, "MemFree:")) {found = 1;break;}}fclose(f);if (!found)return 1024*1024;n = strtoul(buf + 9, NULL, 10);if (!n)return 1024*1024;/* kB? */if (strchr(buf + 9, 'k'))n <<= 10;else if (strchr(buf + 9, 'M'))n <<= 20;return n/2;
}...#ifdef ANDROIDint copy_splice(struct dd_config *);int copy_splice_cores(struct dd_config *ddc)
{return copy_splice(ddc);
}#else
int copy_splice_cores(struct dd_config *ddc)
{int ifd, ofd, p[2] = {-1, -1};ssize_t r = 0, cpu_size = 0;size_t n = 0, min_bs = 4096;cpu_set_t *cpu_set = NULL;if (prepare_copy(ddc, &ifd, &ofd) < 0)return -1;if ((cpu_set = CPU_ALLOC(2)) == NULL) {close(ifd); close(ofd);return -1;}cpu_size = CPU_ALLOC_SIZE(2);CPU_ZERO_S(cpu_size, cpu_set);if (pipe(p) < 0) {ddc->saved_errno = errno;close(ifd); close(ofd);close(p[0]); close(p[1]);return -1;}#ifdef F_SETPIPE_SZfor (n = 29; n >= 20; --n) {if (fcntl(p[0], F_SETPIPE_SZ, 1<<n) != -1)break;}
#endifn = ddc->bs;if (fork() == 0) {/* bind to CPU#0 */CPU_SET_S(ddc->cores - 1, cpu_size, cpu_set);sched_setaffinity(0, cpu_size, cpu_set);close(p[0]);for (;ddc->b_in != ddc->count && !sigint;) {if (n > ddc->count - ddc->b_in)n = ddc->count - ddc->b_in;r = splice(ifd, NULL, p[1], NULL, n, SPLICE_F_MORE|SPLICE_F_NONBLOCK);if (r == 0)break;if (r < 0) {if (errno != EAGAIN)break;/* If running out of pipe buffer, decrease bs */r = 0;n = min_bs;}ddc->b_in += r;}exit(0);}/* bind to CPU#1 */CPU_SET_S(ddc->cores - 2, cpu_size, cpu_set);sched_setaffinity(0, cpu_size, cpu_set);for (;ddc->b_out != ddc->count;) {r = splice(p[0], NULL, ofd, NULL, n, SPLICE_F_MORE);if (r <= 0) {ddc->saved_errno = errno;break;}ddc->b_out += r;++ddc->rec_out;}ddc->rec_in = ddc->rec_out;close(ifd);close(ofd);close(p[0]);close(p[1]);wait(NULL);if (r < 0)return -1;return 0;
}
#endifint copy_splice(struct dd_config *ddc)
{
...if (prepare_copy(ddc, &ifd, &ofd) < 0)return -1;if (pipe(p) < 0) {ddc->saved_errno = errno;close(ifd); close(ofd);close(p[0]); close(p[1]);return -1;}#ifdef F_SETPIPE_SZfor (n = 29; n >= 20; --n) {if (fcntl(p[0], F_SETPIPE_SZ, 1<<n) != -1)break;}
#endifn = ddc->bs;for (;ddc->b_out != ddc->count && !sigint;) {if (n > ddc->count - ddc->b_out)n = ddc->count - ddc->b_out;r = splice(ifd, NULL, p[1], NULL, n, SPLICE_F_MORE);if (r <= 0) {ddc->saved_errno = errno;break;}++ddc->rec_in;r = splice(p[0], NULL, ofd, NULL, r, SPLICE_F_MORE);if (r <= 0) {ddc->saved_errno = errno;break;}ddc->b_out += r;++ddc->rec_out;}close(ifd);close(ofd);close(p[0]);close(p[1]);if (r < 0)return -1;return 0;
}int copy_mmap(struct dd_config *ddc)
{
...if (prepare_copy(ddc, &ifd, &ofd) < 0)return -1;if (ddc->fsize != (off_t)-1) {if (ftruncate(ofd, ddc->fsize) < 0) {ddc->saved_errno = errno;close(ifd);close(ofd);return -1;}}for (;ddc->b_out != ddc->count && !sigint;) {n = ddc->mmap;bs = ddc->bs;if (n > ddc->count - ddc->b_out)n = ddc->count - ddc->b_out;if (bs > n)bs = n;if (ddc->fsize == (off_t)-1) {if (ftruncate(ofd, ddc->b_out + n) < 0) {ddc->saved_errno = errno;break;}}addr = mmap(NULL, n, PROT_WRITE, MAP_SHARED, ofd, ddc->b_out + ddc->skip);if (addr == MAP_FAILED) {ddc->saved_errno = errno;break;}for (i = 0; i < n; i += r) {if (i + bs > n)bs = n - i;r = read(ifd, addr + i, bs);if (r <= 0) {ddc->saved_errno = errno;munmap(addr, n);break;}ddc->b_out += r;++ddc->rec_in;}...}if (ddc->fsize != ddc->b_out)ftruncate(ofd, ddc->b_out);close(ifd);close(ofd);if (r < 0 || addr == MAP_FAILED)return -1;return 0;
}int copy_sendfile(struct dd_config *ddc)
{
...off = ddc->skip;n = ddc->bs;for (;ddc->b_out < ddc->count && !sigint;) {if (n > ddc->count - ddc->b_out)n = ddc->count - ddc->b_out;r = sendfile(ofd, ifd, &off, n);if (r < 0) {ddc->saved_errno = errno;ret = -1;break;}++ddc->rec_in; ++ddc->rec_out;ddc->b_in += r;ddc->b_out += r;}close(ifd);close(ofd);return ret;
}int copy(struct dd_config *ddc)
{
...if (ddc->cores)r = copy_splice_cores(ddc);else if (ddc->mmap)r = copy_mmap(ddc);else if (ddc->sf)r = copy_sendfile(ddc);elser = copy_splice(ddc);ddc->t_end = time(NULL);/* 避免div為零 */if (ddc->t_start == ddc->t_end)++ddc->t_end;return r;
}void print_stat(const struct dd_config *ddc)
{
...#ifdef ANDROIDfprintf(stderr, "%llu records in\n%llu records out\n%llu bytes (%llu MB) copied, %lu s, %f MB/s [%f mB/s]\n",ddc->rec_in, ddc->rec_out, ddc->b_out, ddc->b_out/(1<<20),ddc->t_end - ddc->t_start,((double)(ddc->b_out/(1<<20)))/(ddc->t_end - ddc->t_start),((double)(ddc->b_out/(1000*1000)))/(ddc->t_end - ddc->t_start));
#elsefprintf(stderr, "%lu records in\n%lu records out\n%lu bytes (%lu MB) copied, %lu s, %f MB/s [%f mB/s]\n",ddc->rec_in, ddc->rec_out, ddc->b_out, ddc->b_out/(1<<20),ddc->t_end - ddc->t_start,((double)(ddc->b_out/(1<<20)))/(ddc->t_end - ddc->t_start),((double)(ddc->b_out/(1000*1000)))/(ddc->t_end - ddc->t_start));
#endif}void sig_int(int x)
{fprintf(stderr, "SIGINT! Aborting ...\n");sigint = 1;return;
}int main(int argc, char **argv)
{
...config.bs = 1<<16;config.in = "/dev/stdin";config.out = "/dev/stdout";/* 模擬“dd”參數(shù)解析 */for (i = 1; i < argc; ++i) {if (strcmp(argv[i], "-h") == 0 ||strcmp(argv[i], "--help") == 0)usage(argv[0]);memset(buf, 0, sizeof(buf));if (sscanf(argv[i], "if=%1023c", buf) == 1)config.in = strdup(buf);else if (sscanf(argv[i], "of=%1023c", buf) == 1)config.out = strdup(buf);else if (sscanf(argv[i], "skip=%1023c", buf) == 1)config.skip = strtoul(buf, NULL, 10);else if (sscanf(argv[i], "seek=%1023c", buf) == 1)config.seek = strtoul(buf, NULL, 10);else if (sscanf(argv[i], "count=%1023c", buf) == 1)config.count = strtoul(buf, NULL, 10);else if (sscanf(argv[i], "mmap=%1023c", buf) == 1) {if (!config.cores) {/* Size in MB */config.mmap = strtoul(buf, NULL, 10);config.mmap <<= 20;}} else if (sscanf(argv[i], "cores=%1023c", buf) == 1) {config.cores = strtoul(buf, NULL, 10);if (config.cores < 2)config.cores = 2;config.mmap = 0;} else if (strcmp(argv[i], "send") == 0) {config.sf = 1;} else if (strcmp(argv[i], "direct") == 0) {config.direct = 1;} else if (sscanf(argv[i], "bs=%1023c", buf) == 1) {config.bs = strtoul(buf, NULL, 10);} else if (strcmp(argv[i], "bs") == 0) {config.bs = 0;} else if (strcmp(argv[i], "quiet") == 0) {config.quiet = 1;} else if (strcmp(argv[i], "nosync") == 0) {config.nosync = 1;}}...return 0;
}
If you need the complete source code, please add the WeChat number (c17865354792)
編譯完成后,你可以使用以下命令行參數(shù)來測試它:
./linux_dd if=<input_file> of=<output_file> [其他參數(shù)]
例如,你可以使用以下命令來復(fù)制一個(gè)文件:
./linux_dd if=/dev/stdin of=/dev/stdout bs=1024 count=1024
這個(gè)命令會(huì)從標(biāo)準(zhǔn)輸入讀取數(shù)據(jù),并將數(shù)據(jù)寫入到標(biāo)準(zhǔn)輸出,每次復(fù)制 1024 字節(jié),總共復(fù)制 1024 次。
代碼中提供了多種復(fù)制策略:
-
splice(2):使用 Linux 的
splice
系統(tǒng)調(diào)用來在管道和文件之間傳輸數(shù)據(jù),這種方式可以有效地利用內(nèi)核緩沖區(qū),減少數(shù)據(jù)復(fù)制過程中的上下文切換。 -
mmap(2):通過內(nèi)存映射的方式直接在內(nèi)存中操作文件數(shù)據(jù),這種方式適用于大塊數(shù)據(jù)的復(fù)制。
-
sendfile(2):在內(nèi)核層面直接將數(shù)據(jù)從一個(gè)文件描述符傳輸?shù)搅硪粋€(gè),減少了數(shù)據(jù)在用戶空間的拷貝。
-
多核處理:代碼還支持將數(shù)據(jù)復(fù)制任務(wù)分配到多個(gè) CPU 核心上,以提高復(fù)制效率。
補(bǔ)充內(nèi)容
- 安全性:在使用
dd
時(shí),一定要小心指定正確的輸入和輸出文件,錯(cuò)誤的命令可能會(huì)導(dǎo)致數(shù)據(jù)丟失。 - 效率:選擇合適的塊大小可以顯著影響
dd
的性能。通常,較大的塊大小可以提高復(fù)制速度。 - 錯(cuò)誤處理:
dd
命令在執(zhí)行過程中可能會(huì)遇到錯(cuò)誤,了解如何解讀錯(cuò)誤信息對(duì)于解決問題至關(guān)重要。 - 日志記錄:
dd
命令執(zhí)行時(shí)可以重定向輸出到日志文件,以便于事后分析。 - 進(jìn)度監(jiān)控:可以通過
status=progress
參數(shù)來監(jiān)控dd
命令的執(zhí)行進(jìn)度。
結(jié)語
dd
命令是一個(gè)功能強(qiáng)大的工具,它在 Linux 系統(tǒng)中扮演著重要的角色。了解其工作原理和使用方法,可以幫助你更有效地管理和操作數(shù)據(jù)。在使用時(shí),務(wù)必謹(jǐn)慎,以避免不必要的數(shù)據(jù)損失。
Welcome to follow WeChat official account【程序猿編碼】