[轉載]關於Windows文件讀寫


這幾天在研究怎麼才能加快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(一個免費文件拷貝軟件)源代碼時,發現它也同時打開了多個文件讀寫。可是速度卻沒有慢多少。具體原因還得研究研究。

    以上都是在本地硬盤操作的情況下,沒有網絡的限制,而當我要在服務器上拷貝文件時,最大的瓶頸便成了網絡。在這種情況下,我的想法是,服務器的硬盤讀取速度應該大大高於我們的機器硬盤,所以可以將文件分多段同時讀取,以爭取網絡帶寬,而在寫入時則以串行的方式寫入連續的文件。這樣既能充分利用網絡,又能避免本地硬盤的讀寫速度限制。當然,具體效果還須回公司試驗。[轉載]關於Windows文件讀寫

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章