首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

C 語言 mmap 文件複製:write 寫入佔位符被 memcpy 覆蓋原理解析

     編輯:程式設計疑難解答

代碼片段背景

使用 mmap 實現文件複製,關鍵步驟:

  1. 打開源文件、目標文件。
  2. fstat 獲取源文件大小 st_size。
  3. lseek(dst, st_size-1, SEEK_SET) 定位到目標文件末尾前 1 字節。
  4. write(dst, "a", 1) 寫入佔位符 'a',擴展目標文件至源文件大小。
  5. mmap 映射源文件 (PROT_READ) 和目標文件 (PROT_WRITE | MAP_SHARED)。
  6. memcpy(dst_map, src_map, st_size) 複製內存區域。

核心疑問

為什麼 write(dst, "a", 1) 寫入的 'a' 在最終複製的文件中找不到?

原理解析

  1. 佔位符目的:mmap 無法擴展文件大小,必須先通過 lseek + write 將目標文件「撐大」到源文件大小。寫入的 'a' 只是佔位,位於文件偏移量 st_size - 1。
  2. memcpy 完全覆蓋:memcpy(dm, sm, st_size) 將源文件全部內容(包含最後一字節)複製到目標映射區。目標映射區的最後一字節正是之前寫入 'a' 的位置,因此被源文件的最後一字節覆蓋。
  3. 結果:目標文件最終內容與源文件完全一致,佔位符 'a' 不復存在。

內存/文件狀態演示

源文件 (大小 100 字節):  [S0, S1, ..., S98, S99]
目標文件擴展後:           [?, ?, ..., ?, 'a']  // lseek 99 寫入 'a'
mmap 映射後:
  src_map -> 源文件內容
  dst_map -> 目標文件內存映射 (最後一字節為 'a')
memcpy(dst_map, src_map, 100) 執行後:
  dst_map -> [S0, S1, ..., S98, S99]  // 'a' 被 S99 覆蓋
msync/文件關閉後,磁盤文件即為源文件完整副本

關鍵技術點總結

步驟作用關鍵參數
lseek(dst, st_size-1, SEEK_SET)定位文件末尾前 1 字節偏移量 = 文件大小 - 1
write(dst, "a", 1)寫入 1 字節擴展文件內容無關緊要,常用 '\0' 或 'a'
mmap(..., PROT_READ, MAP_PRIVATE, ...)源文件只讀映射MAP_PRIVATE 修改不回寫磁盤
mmap(..., PROT_WRITE, MAP_SHARED, ...)目標文件可寫共享映射MAP_SHARED 修改同步回磁盤
memcpy(dm, sm, st_size)內存級高速複製長度 = 源文件大小

常見誤區提醒

  • 以為佔位符會保留:實際上 memcpy 是完全覆蓋,佔位符只是為了讓 mmap 映射成功的臨時手段。
  • 省略 msync 導致數據丟失:雖然 MAP_SHARED 通常自動回寫,但調用 msync(dm, st_size, MS_SYNC) 更保險。
  • 文件大小為 0 時 lseek(-1) 出錯:需特殊處理空文件情況。

總結

write 寫入的 'a' 是擴展文件大小的佔位符,後續 memcpy 將源文件完整內容複製到映射區時直接覆蓋了該位置,因此最終文件中不存在。這是 mmap 複製文件的標準模式:先撐大,再映射,再複製。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved