<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Conmajia

      Stop stealing sheep!

      導航

      分頁讀取GB級別超大文件試驗

      ? Conmajia 2012

      May 15th, 2012

       

      (注:本文使用 FileStream 類的 Seek() 和 Read() 方法完成文件讀取,沒有用其他的騷東西。)

      我們在編程過程中,經常會和計算機文件讀取操作打交道。隨著計算機功能和性能的發展,我們需要操作的文件尺寸也是越來越大。在 .NET Framework 中,我們一般使用 FileStream 來讀取、寫入文件流。當文件只有數十 kB 或者數 MB 時,一般的文件讀取方式如 Read()、ReadAll() 等應用起來游刃有余,基本不會感覺到太大的延遲。但當文件越來越大,達到數百 MB 甚至數 GB 時,這種延遲將越來越明顯,最終達到不能忍受的程度。

      通常定義大小在 2GB 以上的文件為超大文件(當然,這個數值會隨著科技的進步,越來越大)。對于這樣規模的文件讀取,普通方法已經完全不能勝任。這就要求我們使用更高效的方法,如內存映射法、分頁讀取法等。

      內存映射(Memory Mapping)

      內存映射的方法可以使用下面的 Windows API 實現。 

      LPVOID MapViewOfFile(HANDLE hFileMappingObject,
        DWORD dwDesiredAccess,
        DWORD dwFileOffsetHigh,
        DWORD dwFileOffsetLow,
        DWORD dwNumberOfBytesToMap);

      雖然使用方便,但使用上限制較多,比如規定的分配粒度(Windows下通常為64KB)等。下面貼出內存映射法實例代碼供參考,但本文不做進一步討論。 

      內存映射法(使用MapViewOfFile)
        1 using System;
        2 using System.Collections.Generic;
        3 using System.Text;
        4 using System.Runtime.InteropServices;
        5 
        6 namespace BlueVision.SaYuan.FileMapping
        7 {
        8     public class ShareMemory
        9     {
       10         [DllImport( "user32.dll", CharSet = CharSet.Auto )]
       11         public static extern IntPtr SendMessage( IntPtr hWnd, int Msg, int wParam, IntPtr lParam );
       12 
       13         [DllImport( "Kernel32.dll", CharSet = CharSet.Auto )]
       14         public static extern IntPtr CreateFileMapping( IntPtr hFile, IntPtr lpAttributes, uint flProtect, uint dwMaxSizeHi, uint dwMaxSizeLow, string lpName );
       15 
       16         [DllImport( "Kernel32.dll", CharSet = CharSet.Auto )]
       17         public static extern IntPtr OpenFileMapping( int dwDesiredAccess, [MarshalAs( UnmanagedType.Bool )] bool bInheritHandle, string lpName );
       18 
       19         [DllImport( "Kernel32.dll", CharSet = CharSet.Auto )]
       20         public static extern IntPtr MapViewOfFile( IntPtr hFileMapping, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, uint dwNumberOfBytesToMap );
       21 
       22         [DllImport( "Kernel32.dll", CharSet = CharSet.Auto )]
       23         public static extern bool UnmapViewOfFile( IntPtr pvBaseAddress );
       24 
       25         [DllImport( "Kernel32.dll", CharSet = CharSet.Auto )]
       26         public static extern bool CloseHandle( IntPtr handle );
       27 
       28         [DllImport( "kernel32", EntryPoint = "GetLastError" )]
       29         public static extern int GetLastError();
       30 
       31         [DllImport( "kernel32.dll" )]
       32         static extern void GetSystemInfo( out SYSTEM_INFO lpSystemInfo );
       33 
       34         [StructLayout( LayoutKind.Sequential )]
       35         public struct SYSTEM_INFO
       36         {
       37             public ushort processorArchitecture;
       38             ushort reserved;
       39             public uint pageSize;
       40             public IntPtr minimumApplicationAddress;
       41             public IntPtr maximumApplicationAddress;
       42             public IntPtr activeProcessorMask;
       43             public uint numberOfProcessors;
       44             public uint processorType;
       45             public uint allocationGranularity;
       46             public ushort processorLevel;
       47             public ushort processorRevision;
       48         }
       49         /// <summary>
       50         /// 獲取系統的分配粒度
       51         /// </summary>
       52         /// <returns></returns>
       53         public static uint GetPartitionsize()
       54         {
       55             SYSTEM_INFO sysInfo;
       56             GetSystemInfo( out sysInfo );
       57             return sysInfo.allocationGranularity;
       58         }
       59 
       60         const int ERROR_ALREADY_EXISTS = 183;
       61 
       62         const int FILE_MAP_COPY = 0x0001;
       63         const int FILE_MAP_WRITE = 0x0002;
       64         const int FILE_MAP_READ = 0x0004;
       65         const int FILE_MAP_ALL_ACCESS = 0x0002 | 0x0004;
       66 
       67         const int PAGE_READONLY = 0x02;
       68         const int PAGE_READWRITE = 0x04;
       69         const int PAGE_WRITECOPY = 0x08;
       70         const int PAGE_EXECUTE = 0x10;
       71         const int PAGE_EXECUTE_READ = 0x20;
       72         const int PAGE_EXECUTE_READWRITE = 0x40;
       73 
       74         const int SEC_COMMIT = 0x8000000;
       75         const int SEC_IMAGE = 0x1000000;
       76         const int SEC_NOCACHE = 0x10000000;
       77         const int SEC_RESERVE = 0x4000000;
       78 
       79         IntPtr m_fHandle;
       80 
       81         IntPtr m_hSharedMemoryFile = IntPtr.Zero;
       82         IntPtr m_pwData = IntPtr.Zero;
       83         bool m_bAlreadyExist = false;
       84         bool m_bInit = false;
       85         uint m_MemSize = 0x1400000;//20M
       86         long m_offsetBegin = 0;
       87         long m_FileSize = 0;
       88         FileReader File = new FileReader();
       89 
       90 
       91         /// <summary>
       92         ///  初始化文件
       93         /// </summary>
       94         /// <param name="MemSize">緩沖大小</param>
       95         public ShareMemory( string filename, uint memSize )
       96         {
       97             // 分頁映射文件時,每頁的起始位置startpos,必須為64K的整數倍。
       98             // memSize即緩存區的大小必須是系統分配粒度的整倍說,window系統的分配粒度是64KB
       99             this.m_MemSize = memSize;
      100             Init( filename );
      101         }
      102 
      103 
      104         /// <summary>
      105         /// 默認映射20M緩沖
      106         /// </summary>
      107         /// <param name="filename"></param>
      108         public ShareMemory( string filename )
      109         {
      110             this.m_MemSize = 0x1400000;
      111             Init( filename );
      112         }
      113 
      114         ~ShareMemory()
      115         {
      116             Close();
      117         }
      118 
      119         /// <summary>
      120         /// 初始化共享內存
      121         /// 
      122         /// 共享內存名稱
      123         /// 共享內存大小
      124         /// </summary>
      125         /// <param name="strName"></param>
      126         protected void Init( string strName )
      127         {
      128             //if (lngSize <= 0 || lngSize > 0x00800000) lngSize = 0x00800000;
      129 
      130             if ( !System.IO.File.Exists( strName ) ) throw new Exception( "未找到文件" );
      131 
      132             System.IO.FileInfo f = new System.IO.FileInfo( strName );
      133 
      134             m_FileSize = f.Length;
      135 
      136             m_fHandle = File.Open( strName );
      137 
      138             if ( strName.Length > 0 )
      139             {
      140                 //創建文件映射
      141                 m_hSharedMemoryFile = CreateFileMapping( m_fHandle, IntPtr.Zero, ( uint )PAGE_READONLY, 0, ( uint )m_FileSize, "mdata" );
      142                 if ( m_hSharedMemoryFile == IntPtr.Zero )
      143                 {
      144                     m_bAlreadyExist = false;
      145                     m_bInit = false;
      146                     throw new Exception( "CreateFileMapping失敗LastError=" + GetLastError().ToString() );
      147                 }
      148                 else
      149                     m_bInit = true;
      150 
      151                 ////映射第一塊文件
      152                 //m_pwData = MapViewOfFile(m_hSharedMemoryFile, FILE_MAP_READ, 0, 0, (uint)m_MemSize);
      153                 //if (m_pwData == IntPtr.Zero)
      154                 //{
      155                 //    m_bInit = false;
      156                 //    throw new Exception("m_hSharedMemoryFile失敗LastError=" + GetLastError().ToString());
      157                 //}
      158 
      159             }
      160         }
      161         /// <summary>
      162         /// 獲取高32位
      163         /// </summary>
      164         /// <param name="intValue"></param>
      165         /// <returns></returns>
      166         private static uint GetHighWord( UInt64 intValue )
      167         {
      168             return Convert.ToUInt32( intValue >> 32 );
      169         }
      170         /// <summary>
      171         /// 獲取低32位
      172         /// </summary>
      173         /// <param name="intValue"></param>
      174         /// <returns></returns>
      175         private static uint GetLowWord( UInt64 intValue )
      176         {
      177 
      178             return Convert.ToUInt32( intValue & 0x00000000FFFFFFFF );
      179         }
      180 
      181         /// <summary>
      182         /// 獲取下一個文件塊 塊大小為20M
      183         /// </summary>
      184         /// <returns>false 表示已經是最后一塊文件</returns>
      185         public uint GetNextblock()
      186         {
      187             if ( !this.m_bInit ) throw new Exception( "文件未初始化。" );
      188             //if ( m_offsetBegin + m_MemSize >= m_FileSize ) return false;
      189 
      190             uint m_Size = GetMemberSize();
      191             if ( m_Size == 0 ) return m_Size;
      192 
      193             // 更改緩沖區大小
      194             m_MemSize = m_Size;
      195 
      196             //卸載前一個文件
      197             //bool l_result = UnmapViewOfFile( m_pwData );
      198             //m_pwData = IntPtr.Zero;
      199 
      200 
      201             m_pwData = MapViewOfFile( m_hSharedMemoryFile, FILE_MAP_READ, GetHighWord( ( UInt64 )m_offsetBegin ), GetLowWord( ( UInt64 )m_offsetBegin ), m_Size );
      202             if ( m_pwData == IntPtr.Zero )
      203             {
      204                 m_bInit = false;
      205                 throw new Exception( "映射文件塊失敗" + GetLastError().ToString() );
      206             }
      207             m_offsetBegin = m_offsetBegin + m_Size;
      208 
      209             return m_Size; //創建成功
      210         }
      211         /// <summary>
      212         /// 返回映射區大小
      213         /// </summary>
      214         /// <returns></returns>
      215         private uint GetMemberSize()
      216         {
      217             if ( m_offsetBegin >= m_FileSize )
      218             {
      219                 return 0;
      220             }
      221             else if ( m_offsetBegin + m_MemSize >= m_FileSize )
      222             {
      223                 long temp = m_FileSize - m_offsetBegin;
      224                 return ( uint )temp;
      225             }
      226             else
      227                 return m_MemSize;
      228         }
      229 
      230         /// <summary>
      231         /// 關閉內存映射
      232         /// </summary>
      233         public void Close()
      234         {
      235             if ( m_bInit )
      236             {
      237                 UnmapViewOfFile( m_pwData );
      238                 CloseHandle( m_hSharedMemoryFile );
      239                 File.Close();
      240             }
      241         }
      242 
      243         /// <summary>
      244         /// 從當前塊中獲取數據
      245         /// </summary>
      246         /// <param name="bytData">數據</param>
      247         /// <param name="lngAddr">起始數據</param>
      248         /// <param name="lngSize">數據長度,最大值=緩沖長度</param>
      249         /// <param name="Unmap">讀取完成是否卸載緩沖區</param>
      250         /// <returns></returns>
      251         public void Read( ref byte[] bytData, int lngAddr, int lngSize, bool Unmap )
      252         {
      253             if ( lngAddr + lngSize > m_MemSize )
      254                 throw new Exception( "Read操作超出數據區" );
      255             if ( m_bInit )
      256             {
      257                 // string bb = Marshal.PtrToStringAuto(m_pwData);//
      258                 Marshal.Copy( m_pwData, bytData, lngAddr, lngSize );
      259             }
      260             else
      261             {
      262                 throw new Exception( "文件未初始化" );
      263             }
      264 
      265             if ( Unmap )
      266             {
      267                 bool l_result = UnmapViewOfFile( m_pwData );
      268                 if ( l_result )
      269                     m_pwData = IntPtr.Zero;
      270             }
      271         }
      272 
      273         /// <summary>
      274         /// 從當前塊中獲取數據
      275         /// </summary>
      276         /// <param name="bytData">數據</param>
      277         /// <param name="lngAddr">起始數據</param>
      278         /// <param name="lngSize">數據長度,最大值=緩沖長度</param>
      279         /// <exception cref="Exception: Read操作超出數據區"></exception>
      280         /// <exception cref="Exception: 文件未初始化"></exception>
      281         /// <returns></returns>
      282         public void Read( ref byte[] bytData, int lngAddr, int lngSize )
      283         {
      284             if ( lngAddr + lngSize > m_MemSize )
      285                 throw new Exception( "Read操作超出數據區" );
      286             if ( m_bInit )
      287             {
      288                 Marshal.Copy( m_pwData, bytData, lngAddr, lngSize );
      289             }
      290             else
      291             {
      292                 throw new Exception( "文件未初始化" );
      293             }
      294         }
      295 
      296         /// <summary>
      297         /// 從當前塊中獲取數據
      298         /// </summary>
      299         /// <param name="lngAddr">緩存區偏移量</param>
      300         /// <param name="byteData">數據數組</param>
      301         /// <param name="StartIndex">數據數組開始復制的下標</param>
      302         /// <param name="lngSize">數據長度,最大值=緩沖長度</param>
      303         /// <exception cref="Exception: 起始數據超過緩沖區長度"></exception>
      304         /// <exception cref="Exception: 文件未初始化"></exception>
      305         /// <returns>返回實際讀取值</returns>
      306         public uint ReadBytes( int lngAddr, ref byte[] byteData, int StartIndex, uint intSize )
      307         {
      308             if ( lngAddr >= m_MemSize )
      309                 throw new Exception( "起始數據超過緩沖區長度" );
      310 
      311             if ( lngAddr + intSize > m_MemSize )
      312                 intSize = m_MemSize - ( uint )lngAddr;
      313 
      314             if ( m_bInit )
      315             {
      316                 IntPtr s = new IntPtr( ( long )m_pwData + lngAddr ); // 地址偏移
      317                 Marshal.Copy( s, byteData, StartIndex, ( int )intSize );
      318             }
      319             else
      320             {
      321                 throw new Exception( "文件未初始化" );
      322             }
      323 
      324             return intSize;
      325         }
      326 
      327         /// <summary>
      328         /// 寫數據
      329         /// </summary>
      330         /// <param name="bytData">數據</param>
      331         /// <param name="lngAddr">起始地址</param>
      332         /// <param name="lngSize">個數</param>
      333         /// <returns></returns>
      334         private int Write( byte[] bytData, int lngAddr, int lngSize )
      335         {
      336             if ( lngAddr + lngSize > m_MemSize ) return 2; //超出數據區
      337             if ( m_bInit )
      338             {
      339                 Marshal.Copy( bytData, lngAddr, m_pwData, lngSize );
      340             }
      341             else
      342             {
      343                 return 1; //共享內存未初始化
      344             }
      345             return 0; //寫成功
      346         }
      347     }
      348     internal class FileReader
      349     {
      350         const uint GENERIC_READ = 0x80000000;
      351         const uint OPEN_EXISTING = 3;
      352         System.IntPtr handle;
      353 
      354         [DllImport( "kernel32", SetLastError = true )]
      355         public static extern System.IntPtr CreateFile(
      356             string FileName,          // file name
      357             uint DesiredAccess,       // access mode
      358             uint ShareMode,           // share mode
      359             uint SecurityAttributes,  // Security Attributes
      360             uint CreationDisposition, // how to create
      361             uint FlagsAndAttributes,  // file attributes
      362             int hTemplateFile         // handle to template file
      363         );
      364 
      365         [System.Runtime.InteropServices.DllImport( "kernel32", SetLastError = true )]
      366         static extern bool CloseHandle
      367         (
      368             System.IntPtr hObject // handle to object
      369         );
      370 
      371 
      372 
      373         public IntPtr Open( string FileName )
      374         {
      375             // open the existing file for reading       
      376             handle = CreateFile
      377             (
      378                 FileName,
      379                 GENERIC_READ,
      380                 0,
      381                 0,
      382                 OPEN_EXISTING,
      383                 0,
      384                 0
      385             );
      386 
      387             if ( handle != System.IntPtr.Zero )
      388             {
      389                 return handle;
      390             }
      391             else
      392             {
      393                 throw new Exception( "打開文件失敗" );
      394             }
      395         }
      396 
      397         public bool Close()
      398         {
      399             return CloseHandle( handle );
      400         }
      401     }
      402 }

       

      分頁讀取法(Paging)

      另外一種高效讀取文件的方法就是分頁法,也叫分段法(Segmentation),對應的讀取單位被稱作頁(Page)和段(Segment)。其基本思想是將整體數據分割至較小的粒度再進行處理,以便滿足時間、空間和性能方面的要求。分頁法的概念使用相當廣泛,如嵌入式系統中的分塊處理(Blocks)和網絡數據的分包傳輸(Packages)。

      圖1 數據局部性示意

      在開始研究分頁法前,先來看看在超大文件處理中,最為重要的問題:高速隨機訪問。桌面編程中,分頁法通常應用于文字處理、閱讀等軟件,有時也應用在大型圖片顯示等方面。這類軟件的一個特點就是數據的局部性,無論需要處理的文件有多么大,使用者的注意力(也可以稱為視口ViewPort)通常只有非常局部的一點(如幾頁文檔和屏幕大小的圖片)。這就要求了接下來,我們要找到一種能夠實現高速的隨機訪問,而這種訪問效果還不能和文件大小有關(否則就失去了高速的意義)。事實上,以下我們研究的分頁法就是利用了「化整為零」的方法,通過只讀取和顯示用戶感興趣的那部分數據,達到提升操作速度的目的。

       

      圖2 文件分頁示意

      參考上圖,假設計算機上有某文件F,其內容為「01234567890123456」(引號「」中的內容,不含引號,下同),文件大小為FileLength=17字節,以PageSize=3對F進行分頁,總頁數PageCount=6,得到頁號為0~5的6個頁面(圖中頁碼=頁號+1)。各頁面所含數據如下表所示。

       
      頁號  頁碼 內容 至頭部偏移量 (Hex) 長度
       0  1  012   00 01 02  3
       1  2  345   03 04 05  3
       2  3  678   06 07 08  3
       3  4  901   09 0a 0b  3
       4  5  234   0c 0d 0e  3
       5  6  56   0f 10  2

      可以看到,最后一頁的長度為2(最后一頁長度總是小于PageSize)。

      當我們要讀取「第n頁」的數據(即頁碼=n)時,實際上讀取的是頁號PageNumber=n-1的內容。例如n=3時,PageNumber=2,數據為「678」,該頁數據偏移量范圍從0x06至0x08,長度為3(PageSize)。為便于講述,在此約定:以下文字中,均只涉及頁號,即PageNumber。

      參考圖2,設當PageNumber=x時,頁x的數據范圍為[offsetStart, offsetEnd],那么可以用如下的代碼進行計算(C#2.0)。 

       1 offsetStart = pageNumber * pageSize;
       2 
       3 if(offsetStart + pageSize < fileSize)
       4 {
       5     offsetEnd = offsetStart + pageSize;
       6 }
       7 else
       8 {
       9     offsetEnd = fileSize - 1;
      10 }

      我們常用的System.IO.FileStream類有兩個重要的方法:Seek()和Read()。  

       1 // 將該流的當前位置設置為給定值。
       2 public override long Seek (
       3     long offset,
       4     SeekOrigin origin
       5 )
       6 
       7 // 從流中讀取字節塊并將該數據寫入給定緩沖區中。
       8 public override int Read (
       9     [InAttribute] [OutAttribute] byte[] array,
      10     int offset,
      11     int count
      12 )

      利用這兩個方法,我們可以指定每次讀取的數據起始位置(offsetStart)和讀取長度(offsetEnd - offsetStart),這樣就可以讀到任意指定的頁數據。我們可以遍歷讀取所有頁,這就相當于普通讀取整個文件(實際操作中,一般不會有需求一次讀取上GB的文件)。

      指定PageNumber,讀取頁面數據
       1 指定PageNumber,讀取頁數據
       2  byte[] getPage(Int64 pageNumber)
       3  {
       4      if (fileStream == null || !fileStream.CanSeek || !fileStream.CanRead)
       5          return null;
       6  
       7      if (pageNumber < 0 || pageNumber >= pageCount)
       8          return null;
       9  
      10      // absolute offileStreamet of read range
      11      Int64 offsetStart = (Int64)pageNumber * (Int64)pageSize;
      12      Int64 offsetEnd = 0;
      13  
      14      if (pageNumber < pageCount - 1)
      15          // not last pageNumber
      16          offsetEnd = offsetStart + pageSize - 1;
      17      else
      18          // last pageNumber
      19          offsetEnd = fileSize - 1;
      20  
      21      byte[] tmp = new byte[offsetEnd - offsetStart + 1];
      22  
      23      fileStream.Seek(offsetStart, SeekOrigin.Begin);
      24      int rd = fileStream.Read(tmp, 0, (Int32)(offsetEnd - offsetStart + 1));
      25  
      26      return tmp;
      27  }

      由于每次讀取的數據長度(PageSize)遠遠小于文件長度(FileSize),所以使用分頁法能夠只讀取程序需要的那部分數據,最大化提高程序的運行效率。下表是筆者在實驗環境下對分頁法讀取文件的運行效率的測試。

      CPU:Intel Core i3 380M @ 2.53GHz

      內存:DDR3 2048MB x2

      硬盤:TOSHIBA MK3265GSX (320 GB) @ 5400 RPM

      為盡量保證測試質量,測試前系統進行了重裝、硬盤整理等維護操作。該硬盤性能測試結果如下圖所示。 

      下面是為了測試分頁法而制作的超大文件讀取器界面截圖,圖中讀取的是本次試驗的用例之一Windows8消費者預覽版光盤鏡像(大小:3.40GB)。 

      本次測試選擇了「大、中、小」3種規格的測試文件作為測試用例,分別為:

       
       # 文件名 文件內容 大小(KB)
       1  AlishaHead.png  Poser Pro 6貼圖  11,611
       2  ubuntu-11.10-desktop-i386.iso  Ubuntu11.10桌面版鏡像  711,980
       3  Windows8-ConsumerPreview-64bit-ChineseSimplified.iso  Windows8消費者預覽版64位簡體中文版鏡像  3,567,486

      通過進行多次讀取,采集到如下表A所示的文件讀取數據結果。表中項目「分頁(單頁)」表示使用分頁讀取法,但設置頁面大小為文件大小(即只有1頁)進行讀取。同樣的,為了解分頁讀取的性能變化情況,使用普通讀取方法(一次讀取)采集到另一份數據結果,如下表B所示。

      對用例#1,該用例大小僅11MB,使用常規(單次)讀取方法,僅用不到20ms即將全部內容讀取完畢。而當采用分頁法,隨著分頁大小越來越小,文件被劃分為更多的頁面,盡管隨機訪問文件內容使得文件操作更加方便,但在讀取整個文件的時候,分頁卻帶來了更多的消耗。例如當分頁大小為1KB時,文件被分割為11,611個頁面。讀取整個文件時,需要重復調用11,611次FileStream.Read()方法,增加了很多消耗,如下圖所示。(圖中數據僅為全文讀取操作對比)

       

       

      從圖中可以看到,當分頁尺寸過分的小(1KB)時,這種過度追求微粒化反而導致了操作性能下降。可以看到,即實現了微粒化,能夠進行隨機訪問,同時仍保有一定量的操作性能,分頁大小為64KB和1MB是不錯的選擇。實際上,上文介紹的MapViewOfFile函數的推薦分頁大小正是64KB。

      對用例#2,該用例大小為695.29MB,達到較大的尺寸,因此對讀取緩存(cache)需求較高,同時也對合適的分頁尺寸提出了要求。可以看到,和用例#1不同,當文件尺寸從11.34MB增加到近700MB時,分頁尺寸隨之相應的擴大,是提高操作性能的好方法(下圖中1MB分頁)。

       

       

      對用例#3,該用例達到3.4GB大小,符合我們對超大文件的定義。通過前述2個用例的分析,可以推測,為獲得最佳性能,分頁大小需繼續提高(比如從1MB提高到4MB)。由于本次試驗時間倉促,考慮不周,未使用「邊讀取、邊丟棄」的測試算法,導致分頁讀取用例#3的數據時,數據不斷在內存中積累,最終引發System.OutOfMemoryException異常,使得分頁讀取完整文件這項測試不能正常完成。這一問題,需在下次的試驗當中加以解決和避免。

       

      引發System.OutOfMemoryException

       

      盡管如此,通過試驗,仍然可以清楚的看到,在常規文件(GB以下級別)操作中,分頁法具有高度靈活性,但額外開銷大,全文讀取速度慢的問題。當操作超大文件(GB以上級別)時,分頁法的優勢開始顯現。極高的數據讀取靈活性帶來的是和文件大小無關的隨機頁面訪問速度(僅和分頁大小有關)。在這個級別上,文件大小往往遠遠超過常規方法所能讀取的最大值(0x7FFFFFFF),因此只有使用分頁法,積少成多,才能完成讀取完整文件的工作。

      分頁法使用簡單,思路清晰,具有很高的靈活性和與文件長度無關的隨機讀取能力,最大支持文件大小理論上能夠達到8,388,608 TB(Int64)。但同時它也具有額外開銷大的特點,因此不適合小文件的操作。

      通過擴展該方法,我們可以幾乎在所有需要大量、重復、大范圍算法處理的程序中加以應用分頁法的「化整為零」思想,以減少計算粒度,實現計算的可持續進行。

      分頁法,以及上文提到的內存映射法,其實均早已出現多年,更是廣泛應用于各個行業。筆者之所以仍舊撰寫此文,一則鍛煉自己的編程能力、語言歸納能力、文字寫作能力,二則加深對方法的理解,通過試驗得出的現象來深入方法的本質。鑒于筆者才疏學淺,在此妄言,有些詞不達意,甚至謬誤之處,還望各位讀者多加批評、指正。

      (全文完)

      ? Conmajia 2012

      posted on 2012-05-16 05:52  Conmajia  閱讀(13918)  評論(1)    收藏  舉報

      主站蜘蛛池模板: 久热这里有精品视频在线| 最新亚洲av日韩av二区| 精品成人免费自拍视频| 精品国产迷系列在线观看| 国产色视频一区二区三区| 日韩剧情片电影网站| 新田县| 福利一区二区视频在线| 国产成人精品视频不卡| 亚洲国产午夜精品福利| 国产熟睡乱子伦午夜视频| 一本一道av中文字幕无码| 国产精品午夜爆乳美女视频| 国内精品免费久久久久电影院97| 伊人激情av一区二区三区| 欧美精品一区二区三区中文字幕| 日韩人妻少妇一区二区三区| 2020年最新国产精品正在播放| 精品免费国产一区二区三区四区 | 乱码午夜-极品国产内射| 欧美精品国产综合久久| 日韩成人无码影院| 蜜臀91精品国产高清在线| 国内精品自线在拍| av中文字幕国产精品| 天堂www在线中文| 久久天天躁综合夜夜黑人鲁色| 精品偷拍被偷拍在线观看| 天堂中文在线资源| 亚洲中文字幕一区精品自| 噜噜综合亚洲av中文无码| 亚洲精品二区在线播放| 亚洲一区二区三区啪啪| 日韩人妻无码精品专区综合网| 免费AV片在线观看网址| 日本丰满护士bbw| 国产精品亚洲аv无码播放| 熟妇女人妻丰满少妇中文字幕| 国产一区二区在线有码| 国产成人精品三上悠亚久久| 又黄又刺激又黄又舒服|