2011-05-06 9 views
12

में गैर-कैश फ़ाइल कैसे लिखती है मैं सबसे खराब केस डिस्क गति निर्धारित करने की कोशिश कर रहा हूं, इसलिए मैंने निम्न कार्य लिखा।सी # Winform ऐप

static public decimal MBytesPerSec(string volume) 
{ 
    string filename = volume + "\\writetest.tmp"; 

    if (System.IO.File.Exists(filename)) 
     System.IO.File.Delete(filename); 

    System.IO.StreamWriter file = new System.IO.StreamWriter(filename); 

    char[] data = new char[64000]; 
    Stopwatch watch = new Stopwatch(); 
    watch.Start(); 

    int i = 0; 

    for (; i < 1000; i++) 
    { 
     file.Write(data); 
     if (watch.ElapsedMilliseconds > 2000) 
     { 
      break; 
     } 
    } 

    watch.Stop(); 
    file.Close(); 

    System.IO.File.Delete(volume + "\\test.txt"); 
    decimal mbytessec = (i * 64/watch.ElapsedMilliseconds); 
    return mbytessec; 
} 

फ़ंक्शन ठीक काम करता है, लेकिन लेखन कैश हो रहे हैं, इसलिए गति सबसे खराब स्थिति नहीं है।

WIN32 सी ++ में, मैं बस FILE_FLAG_NO_BUFFERING, FILE_FLAG_WRITE_THROUGH विकल्पों के साथ फ़ाइल बना सकेगी, और फिर गैर-कैश लेखन नियम (क्षेत्र आकार ऑफसेट पर फ़ाइल पर लिखने, 4k की न्यूनतम के साथ लिखते हैं)

का पालन करना सुनिश्चित

मुझे एक article मिला जो .NET तकनीक पर चर्चा करता है।

इसलिए मैंने एक नया फ़ंक्शन लिखा (गणित त्रुटियों को अनदेखा करें)।

static public decimal MBytesPerSecNonCached(string volume) 
{ 
    const FileOptions FILE_FLAG_NO_BUFFERING = (FileOptions)0x20000000; 

    string filename = volume + "\\writetest.tmp"; 

    using (FileStream fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, 1024, FileOptions.WriteThrough | FILE_FLAG_NO_BUFFERING)) 
    { 
     byte[] data = new byte[65535]; 
     int i = 0; 

     Stopwatch watch = new Stopwatch(); 
     watch.Start(); 

     for (; i < 1000; i++) 
     { 
      fs.Write(data, 0, 65535); 
      if (watch.ElapsedMilliseconds > 2000) 
      { 
       break; 
      } 
     } 

     watch.Stop(); 
     fs.Close(); 

     System.IO.File.Delete(filename); 

     decimal mbytessec = (i * 64/watch.ElapsedMilliseconds); 

     return mbytessec; 
    } 
} 

इस समारोह 4k के लिए काम करता है, 16K और 32K आकार लिखते हैं, लेकिन एक बार मैं 64K आकार लिखने का प्रयास करें, मैं एक अपवाद प्राप्त करें:

IO operation will not work. Most likely the file will become too long or the handle was not opened to support synchronous IO operations.

तो, मैं इसे ठीक कर सकते हैं तो मैं परीक्षण कर सकते हैं 32 केबी से अधिक लिखने के आकार के साथ (64 केबी से 4096 केबी)?

+2

डेवलपर से उन निर्णयों को हटाने के लिए .NET ढांचा विकसित किया गया था और ढांचे को "आपके लिए" प्रबंधित करने की अनुमति दी गई थी। अच्छी खबर यह है कि 99% जरूरतों के लिए यह वास्तव में बहुत अच्छा है। बुरी खबर, यह आपको उस नियंत्रण को नहीं देना चाहती जब आपको लगता है कि आपको इसकी आवश्यकता है (_ या सिर्फ सादा इसे चाहिए)। समाधान, यदि आप इसे 'स्वयं' करने पर उत्सुक हैं, तो Win32 dlls को संबोधित करने के लिए PInvoke का उपयोग करना है और फिर उसी तरह से करें जैसा आप C++ में करेंगे। –

उत्तर

11

कुछ अप्रबंधित कोड का प्रयास करें:

[DllImport("kernel32", SetLastError = true)] 
     static extern unsafe SafeFileHandle CreateFile(
      string FileName,   // file name 
      uint DesiredAccess,  // access mode 
      uint ShareMode,   // share mode 
      IntPtr SecurityAttributes, // Security Attr 
      uint CreationDisposition, // how to create 
      uint FlagsAndAttributes, // file attributes 
      IntPtr hTemplate // template file 
      ); 
const uint FILE_FLAG_NO_BUFFERING = 0x20000000; 

SafeFileHandle handle = CreateFile("filename", 
          (uint)FileAccess.Write, 
          (uint)FileShare.None, 
          IntPtr.Zero, 
          (uint)FileMode.Open, 
          FILE_FLAG_NO_BUFFERING, 
          IntPtr.Zero); 

var unBufferedStream = new FileStream(handle,FileAccess.Read,blockSize,false); 

अब आप जो आप पढ़ सकते हैं और फिर भी लिखना आप बगैर किसी अड़चन

रिकॉर्ड के लिए के साथ कृपया कर सकते एक unbuffered धारा का प्रयोग करना चाहिए .... आप कर सकते हैं इस तरह कैशिंग को अक्षम भी करें:

[DllImport("KERNEL32", SetLastError = true)] 
     public extern static int DeviceIoControl(IntPtr hDevice, uint IoControlCode, 
      IntPtr lpInBuffer, uint InBufferSize, 
      IntPtr lpOutBuffer, uint nOutBufferSize, 
      ref uint lpBytesReturned, 
      IntPtr lpOverlapped); 
     [DllImport("KERNEL32", SetLastError = true)] 
     public extern static int CloseHandle(
     IntPtr hObject); 

[StructLayout(LayoutKind.Sequential)] 
     public struct DISK_CACHE_INFORMATION 
     {    
      public byte ParametersSavable;    
      public byte ReadCacheEnabled;    
      public byte WriteCacheEnabled; 
      public int ReadRetentionPriority;//DISK_CACHE_RETENTION_PRIORITY = enum = int 
      public int WriteRetentionPriority;//DISK_CACHE_RETENTION_PRIORITY = enum = int 
      public Int16 DisablePrefetchTransferLength;//WORD    
      public byte PrefetchScalar;    
     } 

public void SetDiskCache(byte val) 
     { 
      IntPtr h = CreateFile("\\\\.\\PHYSICALDRIVE0", (uint)FileAccess.Read | (uint)FileAccess.Write, (uint)FileShare.Write, IntPtr.Zero, (uint)FileMode.Open, 0, IntPtr.Zero); 
      DISK_CACHE_INFORMATION sInfo = new DISK_CACHE_INFORMATION(); 
      IntPtr ptrout = Marshal.AllocHGlobal(Marshal.SizeOf(sInfo)); 
      Marshal.StructureToPtr(sInfo, ptrout, true);    
      uint dwWritten = 0; 
      int ret = DeviceIoControl(h,IOCTL_DISK_GET_CACHE_INFORMATION,IntPtr.Zero,0,ptrout,(uint)Marshal.SizeOf(sInfo),ref dwWritten,IntPtr.Zero);    
      sInfo = (DISK_CACHE_INFORMATION)Marshal.PtrToStructure(ptrout,typeof(DISK_CACHE_INFORMATION));    
      sInfo.ReadCacheEnabled = val; 
      // acuma trimite structura modificata 
      IntPtr ptrin = Marshal.AllocHGlobal(Marshal.SizeOf(sInfo)); 
      Marshal.StructureToPtr(sInfo, ptrin, true);    
      ret = DeviceIoControl(h, IOCTL_DISK_SET_CACHE_INFORMATION, ptrin, (uint)Marshal.SizeOf(sInfo), IntPtr.Zero, 0, ref dwWritten, IntPtr.Zero);    
      CloseHandle(h);    
     } 
+0

धन्यवाद ट्यूडर मैं कल इसे आज़मा दूंगा, और देखें कि क्या होता है। मैं उत्सुक हूं कि एक ड्राइव पर कैश को अक्षम करने में कितना समय लगता है। किसी पर खेलने के लिए एक औसत चाल होगी;) –

+0

इस अप्रबंधित कोड में बफर स्ट्रीम अभी भी एक ही त्रुटि देता है: 'आईओ ऑपरेशन काम नहीं करेगा। सबसे अधिक संभावना है कि फाइल बहुत लंबी हो जाएगी या सिंक्रोनस आईओ ऑपरेशंस का समर्थन करने के लिए हैंडल खोला नहीं गया था। –

+0

CreateFile नोट्स के लिए प्रलेखन के रूप में, FILE_FLAG_NO_BUFFERING ध्वज की आवश्यकता है कि फ़ाइल हैंडल पर सभी I/O संचालन क्षेत्र के आकार के गुणकों में हों, और I/O बफर को उन पते पर गठबंधन किया जाए जो क्षेत्र के आकार के गुणक हैं। – TheLegendaryCopyCoder