原文地址:http://blog.sina.com.cn/s/blog_6589148801016668.html這幾天在研究怎麼才能加快windows檔案讀寫速度,搜了很多文章,MSDN也看了不少。稍微給大家分享一下。 限制windows檔案讀寫速度的瓶頸其實最終還是來源於我們硬碟的固有特性,磁碟本身的轉速和硬碟的序列化工作機制。我們所能做的只是改善軟體實現方法去逼近硬碟的極限讀寫速度。平時我們在拷貝粘貼檔案的時候,其實是用的windows本身的實現,其中有一個很大的影響速度的地方就是它們都用了windows的檔案快取機制,當你拷貝一個大檔案時,windows會根據你要拷貝的檔案大小緩衝很大一部分到系統緩衝,這時候你會看到系統緩衝瞬間飆漲,機器效能大大降低。整體拷貝速度為10M/S左右。而IDE
7200轉的硬碟讀寫速度一般能達到30M/S左右,所以浪費了很大一部分硬碟讀寫速度。而當我們並行讀寫多個檔案時,速度比串列讀寫多個檔案還要慢,這就是因為硬碟串列工作機制的限制,多檔案並行操作時,時間都花在磁頭擺動上了。並且在緩衝讀取上,命中率也將大大降低。所以我們要避免使用windows緩衝機制,並盡量不要同時讀寫多段檔案,盡量讀寫連續的檔案塊。 一般來說,我們操作一個windows I/O控制代碼用的是windows檔案讀寫系列API:CreateFile, ReadFile, WriteFile等,這些API不僅可以讀寫檔案控制代碼,所有的I/O裝置控制代碼都能通過這些API來操作。比如socket描述符, 串口描述符,管道描述符等。通過設定他們的參數,我們可以選擇以不同的方式操作IO。例如CreateFile,原型如下:
HANDLE CreateFile(
LPCTSTR lpFileName, //指向檔案名稱的指標
DWORD dwDesiredAccess, //訪問模式(寫/讀)
DWORD dwShareMode, //共用模式
LPSECURITY_ATTRIBUTES lpSecurityAttributes, //指向安全屬性的指標
DWORD dwCreationDisposition, //如何建立
DWORD dwFlagsAndAttributes, //檔案屬性
HANDLE hTemplateFile //用於複製檔案控制代碼
);
對於讀寫速度,最重要的是dwFlagsAndAttributes參數,這個參數的取值可以參看MSDN,這裡稍微說一下:
Attributes:
該參數可以接收下列屬性的任意組合.除非其它所有的檔案屬性忽略FILE_ATTRIBUTE_NORMAL.
FILE_ATTRIBUTE_ARCHIVE 檔案將被存檔,程式使用此屬性來標誌檔案去備份或移除
FILE_ATTRIBUTE_HIDDEN 檔案被隱藏,它不會在一般資料夾清單中被裝載.
FILE_ATTRIBUTE_NORMAL 檔案沒有被設定任何屬性.
FILE_ATTRIBUTE_OFFLINE 檔案的資料沒有被立即用到。指出正在離線使用該檔案。
FILE_ATTRIBUTE_READONLY 這個檔案只可讀取.程式可以讀檔案,但不可以在上面寫入內容,也不可刪除.
FILE_ATTRIBUTE_SYSTEM 檔案是系統的一部分,或是系統專用的.
FILE_ATTRIBUTE_TEMPORARY 檔案被使用後,檔案系統將努力為(檔案的)所有資料的迅迅訪問保持一塊記憶體。臨時檔案應當在程式不用時及時刪除。
Flags:
可以接受下列標誌的任意組合。
FILE_FLAG_WRITE_THROUGH
指示系統通過快速緩衝直接寫入磁碟,
FILE_FLAG_OVERLAPPED
指示系統初始化對象, 此操作將對進程設定一個引用計數並返回ERROR_IO_PENDING.處理完成後, 指定對象將被設定為訊號狀態.當你指定FILE_FLAG_OVERLAPPED時,讀寫檔案的函數必須指定一個OVERLAPPED結構.並且. 當FILE_FLAG_OVERLAPPED被指定, 程式必須執行重疊參數(指向OVERLAPPED結構)去進行檔案的讀寫. 這個標誌也可以有超過一個操作去執行.
FILE_FLAG_NO_BUFFERING
指示系統不使用快速緩衝區或緩衝,當和FILE_FLAG_OVERLAPPED組合,該標誌給出最
大的非同步作業量, 因為I/O不依賴記憶體管理器的非同步作業.然而,一些I/O操作將會運行得長一些,因為資料沒有控制在緩衝中.
當使用FILE_FLAG_NO_BUFFERING開啟檔案進行工作時,程式必須達到下列要求:
1. 檔案的存取開頭的位元組位移量必須是扇區尺寸的整倍數.
2. 檔案存取的位元組數必須是扇區尺寸的整倍數.例如,如果扇區尺寸是512位元組.程式就可以讀或者寫512,1024或者2048位元組,但不能夠是335,981或者7171位元組.
3. 進行讀和寫操作的地址必須在扇區的對齊位置,在記憶體中對齊的地址是扇區.尺寸的整倍數.一個將緩衝區與扇區尺寸對齊的途徑是使用VirtualAlloc函數.它分配與作業系統記憶體頁大小的整倍數對齊的記憶體位址.因為記憶體頁尺寸和扇區尺寸--2都是它們的冪.這塊記憶體在地址中同樣與扇區尺寸大小的整倍數對齊.程式可以通過調用GetDiskFreeSpace來確定扇區的尺寸.
FILE_FLAG_RANDOM_ACCESS
指定檔案是隨機訪問,這個標誌可以使系統最佳化檔案的緩衝.
FILE_FLAG_SEQUENTIAL_SCAN
指定檔案將從頭到尾連續地訪問.這個標誌可以提示系統最佳化檔案緩衝. 如果程式在
隨機訪問檔案中移動檔案指標,最佳化可能不會發生;然而,正確的操作仍然可以得到保
證. 指定這個標誌可以提高程式以順序訪問模式讀取大檔案的效能, 效能的提高在許多程式讀取一些大的循序檔時是異常明顯的.但是可能會有小範圍的位元組遺漏.
FILE_FLAG_DELETE_ON_CLOSE
指示系統在檔案所有開啟的控制代碼關閉後立即刪除檔案.不只有你指定了FILE_FLAG_DELETE_ON_CLOSE的檔案。
FILE_SHARE_DELETE
如果沒有使用FILE_SHARE_DELETE,後續的開啟檔案的請求將會失敗.
FILE_FLAG_BACKUP_SEMANTICS
WINDOWS NT:指示系統為檔案的開啟或建立執行一個備份或恢複操作. 系統保證調
用進程忽略檔案的安全選項,倘若它必須有一個特權.則相關的特權則是SE_BACKUP_NAME和SE_RESTORE_NAME.你也可以使用這個標誌獲得一個檔案夾的控制代碼,一個檔案夾控制代碼能夠象一個檔案控制代碼一樣傳給某些Win32函數。
FILE_FLAG_POSIX_SEMANTICS
指明檔案符合POSIX標準.這是在MS-DOS與16位Windows下的標準.
FILE_FLAG_OPEN_REPARSE_POINT
指定這個標誌制約NTFS分區指標.該標誌不能夠和CREAT_ALWAYS一起使用.
FILE_FLAG_OPEN_NO_RECALL
指明需要檔案資料,但是將繼續從遠程儲存空間中接收.它不會將資料存放在本機存放區器中.這個標誌由遠程儲存系統或等級儲存管理器系統使用.
可以看到,有很多標誌和屬性可以使用,但是這裡最重要的對速度影響最大的是紅字部分的FILE_FLAG_NO_BUFFERING和FILE_FLAG_OVERLAPPED.
FILE_FLAG_NO_BUFFERING就是說檔案操作時不使用windows緩衝機制,FILE_FLAG_OVERLAPPED則表示檔案的操作將非同步進行。就是說不等待I/O操作完成,讀寫函數便返回,這要用到重疊IO機制,自己針對IO狀態做不同的事情,基本上用到的是GetOverlappedResult和WaitForMultiObject。
當我單獨使用FILE_FLAG_NO_BUFFERING時,拷貝粘貼一個400M檔案大概22秒,接近20M/S的速度,但是指定FILE_FLAG_NO_BUFFERING時,檔案位置,緩衝大小,檔案大小都有很大的限制,即都要和扇區大小對齊(見紅字部分)。如果不這樣,讀寫將失敗。這的確增大了不少記憶體配置操作,但是速度提高卻很明顯。
而當我使用FILE_FLAG_OVERLAPPED將檔案分為多個部分同時讀寫時,發現速度反而慢了。回到開頭說的,這就是硬碟本身的限制了。但是我參考Fastcopy(一個免費檔案拷貝軟體)原始碼時,發現它也同時開啟了多個檔案讀寫。可是速度卻沒有慢多少。具體原因還得研究研究。
以上都是在本地硬碟操作的情況下,沒有網路的限制,而當我要在伺服器上拷貝檔案時,最大的瓶頸便成了網路。在這種情況下,我的想法是,伺服器的硬碟讀取速度應該大大高於我們的機器硬碟,所以可以將檔案分多段同時讀取,以爭取網路頻寬,而在寫入時則以串列的方式寫入連續的檔案。這樣既能充分利用網路,又能避免本地硬碟的讀寫速度限制。當然,具體效果還須回公司實驗。