2009-03-03 9 views
42

मैं .NET से एनटीएफएस वैकल्पिक डेटा स्ट्रीम कैसे बना/हटा/पढ़/लिख सकता/सकती हूं?एनटीएफएस वैकल्पिक डेटा स्ट्रीम - .NET

यदि कोई मूल .NET समर्थन नहीं है, तो मैं Win32 API का उपयोग कैसे करूं? साथ ही, मैं उनका उपयोग कैसे करूं, क्योंकि मुझे नहीं लगता कि यह दस्तावेज है?

+0

बीटीडब्ल्यू, यदि आप मानक फ़ाइल-प्रतिलिपि प्रगति संवाद के साथ फ़ाइल (ओं) की प्रतिलिपि बनाना चाहते हैं, तो आप :: SHFileOperation() का उपयोग नहीं कर सकते - यह AltDataStreams के साथ बिल्कुल काम नहीं करता है (विंडोज 7 पर चेक किया गया है)। :: CopyFileEx() के लिए, यह कुछ मामलों में काम करता है (उदा। यह प्रगति कॉलबैक को कॉल करते समय एक फ़ाइल को AltDataStream में कॉपी कर सकता है), लेकिन यह दूसरों में काम नहीं करता है। – Nishi

उत्तर

4
.NET में नहीं

:

http://support.microsoft.com/kb/105763

#include <windows.h> 
    #include <stdio.h> 

    void main() 
    { 
     HANDLE hFile, hStream; 
     DWORD dwRet; 

     hFile = CreateFile("testfile", 
         GENERIC_WRITE, 
        FILE_SHARE_WRITE, 
           NULL, 
         OPEN_ALWAYS, 
            0, 
           NULL); 
     if(hFile == INVALID_HANDLE_VALUE) 
     printf("Cannot open testfile\n"); 
     else 
      WriteFile(hFile, "This is testfile", 16, &dwRet, NULL); 

     hStream = CreateFile("testfile:stream", 
           GENERIC_WRITE, 
          FILE_SHARE_WRITE, 
             NULL, 
            OPEN_ALWAYS, 
              0, 
             NULL); 
     if(hStream == INVALID_HANDLE_VALUE) 
     printf("Cannot open testfile:stream\n"); 
     else 
     WriteFile(hStream, "This is testfile:stream", 23, &dwRet, NULL); 
    } 
+8

दो लापता CloseHandle कॉल ... ओएस साफ हो जाएगा, लेकिन वास्तविक एप्लिकेशन में एक समस्या होगी। – Richard

+3

@ रिचर्ड - बस एमएस की समर्थन साइट से कॉपी किया गया ... –

+1

ávio आप सी # से उन कार्यों को पी/आमंत्रित कर सकते हैं। –

30

यहाँ उनके लिए कोई देशी नेट समर्थन नहीं है के लिए सी #

using System.Runtime.InteropServices; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var mainStream = NativeMethods.CreateFileW(
      "testfile", 
      NativeConstants.GENERIC_WRITE, 
      NativeConstants.FILE_SHARE_WRITE, 
      IntPtr.Zero, 
      NativeConstants.OPEN_ALWAYS, 
      0, 
      IntPtr.Zero); 

     var stream = NativeMethods.CreateFileW(
      "testfile:stream", 
      NativeConstants.GENERIC_WRITE, 
      NativeConstants.FILE_SHARE_WRITE, 
      IntPtr.Zero, 
      NativeConstants.OPEN_ALWAYS, 
      0, 
      IntPtr.Zero); 
    } 
} 

public partial class NativeMethods 
{ 

    /// Return Type: HANDLE->void* 
    ///lpFileName: LPCWSTR->WCHAR* 
    ///dwDesiredAccess: DWORD->unsigned int 
    ///dwShareMode: DWORD->unsigned int 
    ///lpSecurityAttributes: LPSECURITY_ATTRIBUTES->_SECURITY_ATTRIBUTES* 
    ///dwCreationDisposition: DWORD->unsigned int 
    ///dwFlagsAndAttributes: DWORD->unsigned int 
    ///hTemplateFile: HANDLE->void* 
    [DllImportAttribute("kernel32.dll", EntryPoint = "CreateFileW")] 
    public static extern System.IntPtr CreateFileW(
     [InAttribute()] [MarshalAsAttribute(UnmanagedType.LPWStr)] string lpFileName, 
     uint dwDesiredAccess, 
     uint dwShareMode, 
     [InAttribute()] System.IntPtr lpSecurityAttributes, 
     uint dwCreationDisposition, 
     uint dwFlagsAndAttributes, 
     [InAttribute()] System.IntPtr hTemplateFile 
    ); 

} 


public partial class NativeConstants 
{ 

    /// GENERIC_WRITE -> (0x40000000L) 
    public const int GENERIC_WRITE = 1073741824; 

    /// FILE_SHARE_DELETE -> 0x00000004 
    public const int FILE_SHARE_DELETE = 4; 

    /// FILE_SHARE_WRITE -> 0x00000002 
    public const int FILE_SHARE_WRITE = 2; 

    /// FILE_SHARE_READ -> 0x00000001 
    public const int FILE_SHARE_READ = 1; 

    /// OPEN_ALWAYS -> 4 
    public const int OPEN_ALWAYS = 4; 
} 
+8

यह सुनिश्चित करने के लिए कि आप उन फ़ाइल हैंडल को साफ़ करते हैं, यहां से सुरक्षित हैंडल से व्युत्पन्न एक प्रकार का उपयोग करना चाहिए। – Richard

+7

आपने दिखाया कि देशी एपीआई का उपयोग कैसे करें, लेकिन 'CreateFileW' से लौटाए गए पॉइंटर का उपयोग कैसे करें। मैं * वास्तव में * एक और पूर्ण नमूना देखना चाहता हूं जो विंडोज एक्सप्लोरर में फ़ाइल गुणों के सारांश टैब में उपलब्ध सामान्य गुणों को लिखता है। –

13

एक संस्करण है। आपको देशी Win32 विधियों को कॉल करने के लिए पी/Invoke का उपयोग करना होगा।

उन्हें बनाने के लिए, CreateFile पर filename.txt:streamname जैसे पथ के साथ कॉल करें। यदि आप एक इंटरफ़ेस कॉल का उपयोग करते हैं जो एक सुरक्षितफाइल हैंडल देता है, तो आप उस फ़ाइलस्ट्रीम को बनाने के लिए उपयोग कर सकते हैं जिसे आप & लिख सकते हैं।

सूचीबद्ध करने के लिए धाराओं कि एक फ़ाइल पर मौजूद हैं, (केवल सर्वर 2003 और बाद में जो मौजूद - नहीं एक्सपी) FindFirstStreamW और FindNextStreamW का उपयोग करें।

मुझे विश्वास नहीं है कि आप बाकी फ़ाइल की प्रतिलिपि बनाकर और धाराओं में से किसी एक को छोड़कर एक स्ट्रीम हटा सकते हैं। लंबाई को 0 तक सेट करना भी काम कर सकता है, लेकिन मैंने कोशिश नहीं की है।

आप निर्देशिका में वैकल्पिक डेटा स्ट्रीम भी प्राप्त कर सकते हैं। आप उन्हें फाइलों के साथ ही एक्सेस करते हैं - C:\some\directory:streamname

धाराओं में संपीड़न, एन्क्रिप्शन और स्पर्सनेस सेट डिफ़ॉल्ट स्ट्रीम से स्वतंत्र हो सकते हैं।

+7

आप * स्ट्रीम को हटा सकते हैं: बस "फ़ाइल नाम: स्ट्रीमनाम" के साथ DeleteFile API को कॉल करें। जाहिर है, आप एक सामान्य फ़ाइल के साथ कुछ भी कर सकते हैं जो आप एडीएस के साथ कर सकते हैं। फ़ाइलस्ट्रीम इसे संभाल नहीं करने का एकमात्र कारण यह है क्योंकि यह पथ को मान्य करता है, और इसमें विफल रहता है यदि इसमें ":" है ... –

6

पहला, माइक्रोसॉफ़्ट® .NET Framework में कुछ भी इस कार्यक्षमता प्रदान करता है। यदि आप इसे चाहते हैं, सादा और सरल आपको किसी प्रकार का इंटरऑप करना होगा, या तो सीधे या किसी तृतीय-पक्ष लाइब्रेरी का उपयोग करना होगा।

यदि आप Windows Server ™ 2003 या बाद में उपयोग कर रहे हैं, तो Kernel32.dll FindFirstFile और FindNextFile को समकक्षों का खुलासा करता है जो सटीक कार्यक्षमता प्रदान करते हैं जो आप खोज रहे हैं। FindFirstStreamW और FindNextStreamW आपको किसी विशेष फ़ाइल के भीतर सभी वैकल्पिक डेटा स्ट्रीमों को खोजने और गणना करने की अनुमति देता है, प्रत्येक के बारे में जानकारी पुनर्प्राप्त करता है, जिसमें उसका नाम और इसकी लंबाई शामिल है। प्रबंधित कोड से इन कार्यों का उपयोग कर के लिए कोड बहुत कि जो मैं अपने दिसम्बर कॉलम में पता चला है के समान है, और केवल आप चित्रा में 1.

चित्रा 1 FindFirstStreamW और FindNextStreamW

का उपयोग
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] 
public sealed class SafeFindHandle : SafeHandleZeroOrMinusOneIsInvalid { 

    private SafeFindHandle() : base(true) { } 

    protected override bool ReleaseHandle() { 
     return FindClose(this.handle); 
    } 

    [DllImport("kernel32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
    private static extern bool FindClose(IntPtr handle); 

} 

public class FileStreamSearcher { 
    private const int ERROR_HANDLE_EOF = 38; 
    private enum StreamInfoLevels { FindStreamInfoStandard = 0 } 

    [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern SafeFindHandle FindFirstStreamW(string lpFileName, StreamInfoLevels InfoLevel, [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_STREAM_DATA lpFindStreamData, uint dwFlags); 

    [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool FindNextStreamW(SafeFindHandle hndFindFile, [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_STREAM_DATA lpFindStreamData); 
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
    private class WIN32_FIND_STREAM_DATA { 
     public long StreamSize; 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 296)] 
     public string cStreamName; 
    } 

    public static IEnumerable<string> GetStreams(FileInfo file) { 
     if (file == null) throw new ArgumentNullException("file"); 
     WIN32_FIND_STREAM_DATA findStreamData = new WIN32_FIND_STREAM_DATA(); 
     SafeFindHandle handle = FindFirstStreamW(file.FullName, StreamInfoLevels.FindStreamInfoStandard, findStreamData, 0); 
     if (handle.IsInvalid) throw new Win32Exception(); 
     try { 
      do { 
       yield return findStreamData.cStreamName; 
      } while (FindNextStreamW(handle, findStreamData)); 
      int lastError = Marshal.GetLastWin32Error(); 
      if (lastError != ERROR_HANDLE_EOF) throw new Win32Exception(lastError); 
     } finally { 
      handle.Dispose(); 
     } 
    } 
} 

दिखाया गया है FindFirstStreamW को कॉल करें, इसे लक्ष्य फ़ाइल के लिए पूर्ण पथ से गुजरना। FindFirstStreamW का दूसरा पैरामीटर आपके द्वारा लौटाए गए डेटा में इच्छित विवरण के स्तर को निर्देशित करता है; वर्तमान में, केवल एक स्तर (FindStreamInfoStandard) है, जिसमें 0 का संख्यात्मक मान है। फ़ंक्शन के लिए तीसरा पैरामीटर WIN32_FIND_STREAM_DATA संरचना के लिए एक सूचक है (तकनीकी रूप से, तीसरा पैरामीटर बिंदु जो दूसरे पैरामीटर के मान से निर्धारित होता है सूचना स्तर का विवरण देना, लेकिन वर्तमान में केवल एक स्तर है, सभी उद्देश्यों और उद्देश्यों के लिए यह एक WIN32_FIND_STREAM_DATA है)। मैंने उस वर्ग के प्रबंधित समकक्ष को एक वर्ग के रूप में घोषित कर दिया है, और इंटरऑप हस्ताक्षर में मैंने इसे एक सूचक के रूप में एक सूचक के रूप में चिह्नित किया है। अंतिम पैरामीटर भविष्य के उपयोग के लिए आरक्षित है और 0 होना चाहिए। यदि FindFirstStreamW से एक मान्य हैंडल वापस किया जाता है, तो WIN32_FIND_STREAM_DATA इंस्टेंस में स्ट्रीम के बारे में जानकारी होती है, और इसके cStreamName मान को कॉलर को पहले स्ट्रीम नाम के रूप में वापस लाया जा सकता है। FindNextStreamW FindFirstStreamW से लौटाए गए हैंडल को स्वीकार करता है और उपलब्ध होने पर उपलब्ध अगली स्ट्रीम के बारे में जानकारी के साथ आपूर्ति किए गए WIN32_FIND_STREAM_DATA को भरता है। FindNextStreamW सत्य लौटाता है यदि कोई अन्य स्ट्रीम उपलब्ध है, या गलत नहीं है। नतीजतन, मैं लगातार FindNextStreamW को कॉल करता हूं और परिणामी स्ट्रीम नाम उत्पन्न करता हूं जब तक FindNextStreamW झूठी रिटर्न नहीं देता है। जब ऐसा होता है, तो मैं यह सुनिश्चित करने के लिए अंतिम त्रुटि मान को दोबारा जांचता हूं कि पुनरावृत्ति रोक दी गई क्योंकि FindNextStreamW स्ट्रीम से बाहर हो गया, न कि कुछ अप्रत्याशित कारणों से। दुर्भाग्यवश, यदि आप Windows® XP या Windows 2000 सर्वर का उपयोग कर रहे हैं, तो ये फ़ंक्शन आपके लिए उपलब्ध नहीं हैं, लेकिन कुछ विकल्प हैं। पहले समाधान में वर्तमान में Kernel32.dll, NTQueryInformationFile से निर्यात किए गए एक अनियंत्रित फ़ंक्शन शामिल है। हालांकि, अनियंत्रित कार्यों को किसी कारण से अनियंत्रित किया गया है, और भविष्य में किसी भी समय उन्हें बदला या हटाया जा सकता है। उनका उपयोग न करना सबसे अच्छा है। यदि आप इस फ़ंक्शन का उपयोग करना चाहते हैं, तो वेब पर खोजें और आपको बहुत सारे संदर्भ और नमूना स्रोत कोड मिलेंगे। लेकिन अपने जोखिम पर ऐसा करें। एक अन्य समाधान, और जिसे मैंने में प्रदर्शित किया है चित्रा 2, कर्नेल 32.dll से निर्यात किए गए दो कार्यों पर निर्भर करता है, और ये दस्तावेज हैं।

BOOL BackupRead(HANDLE hFile, LPBYTE lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, BOOL bAbort, BOOL bProcessSecurity, LPVOID* lpContext); 
BOOL BackupSeek(HANDLE hFile, DWORD dwLowBytesToSeek, DWORD dwHighBytesToSeek, LPDWORD lpdwLowByteSeeked, LPDWORD lpdwHighByteSeeked, LPVOID* lpContext); 

चित्र 2 BackupRead और BackupSeek

public enum StreamType { 
    Data = 1, 
    ExternalData = 2, 
    SecurityData = 3, 
    AlternateData = 4, 
    Link = 5, 
    PropertyData = 6, 
    ObjectID = 7, 
    ReparseData = 8, 
    SparseDock = 9 
} 

public struct StreamInfo { 
    public StreamInfo(string name, StreamType type, long size) { 
     Name = name; 
     Type = type; 
     Size = size; 
    } 
    readonly string Name; 
    public readonly StreamType Type; 
    public readonly long Size; 
} 

public class FileStreamSearcher { 
    [DllImport("kernel32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool BackupRead(SafeFileHandle hFile, IntPtr lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, [MarshalAs(UnmanagedType.Bool)] bool bAbort, [MarshalAs(UnmanagedType.Bool)] bool bProcessSecurity, ref IntPtr lpContext);[DllImport("kernel32.dll")] 

    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool BackupSeek(SafeFileHandle hFile, uint dwLowBytesToSeek, uint dwHighBytesToSeek, out uint lpdwLowByteSeeked, out uint lpdwHighByteSeeked, ref IntPtr lpContext); public static IEnumerable<StreamInfo> GetStreams(FileInfo file) { 
     const int bufferSize = 4096; 
     using (FileStream fs = file.OpenRead()) { 
      IntPtr context = IntPtr.Zero; 
      IntPtr buffer = Marshal.AllocHGlobal(bufferSize); 
      try { 
       while (true) { 
        uint numRead; 
        if (!BackupRead(fs.SafeFileHandle, buffer, (uint)Marshal.SizeOf(typeof(Win32StreamID)), out numRead, false, true, ref context)) throw new Win32Exception(); 
        if (numRead > 0) { 
         Win32StreamID streamID = (Win32StreamID)Marshal.PtrToStructure(buffer, typeof(Win32StreamID)); 
         string name = null; 
         if (streamID.dwStreamNameSize > 0) { 
          if (!BackupRead(fs.SafeFileHandle, buffer, (uint)Math.Min(bufferSize, streamID.dwStreamNameSize), out numRead, false, true, ref context)) throw new Win32Exception(); name = Marshal.PtrToStringUni(buffer, (int)numRead/2); 
         } 
         yield return new StreamInfo(name, streamID.dwStreamId, streamID.Size); 
         if (streamID.Size > 0) { 
          uint lo, hi; BackupSeek(fs.SafeFileHandle, uint.MaxValue, int.MaxValue, out lo, out hi, ref context); 
         } 
        } else break; 
       } 
      } finally { 
       Marshal.FreeHGlobal(buffer); 
       uint numRead; 
       if (!BackupRead(fs.SafeFileHandle, IntPtr.Zero, 0, out numRead, true, false, ref context)) throw new Win32Exception(); 
      } 
     } 
    } 
} 

BackupRead के पीछे विचार यह किया जा सकता है का उपयोग करते हुए: उनके नाम का मतलब है के रूप में, BackupRead और BackupSeek बैकअप समर्थन के लिए Win32® एपीआई का हिस्सा हैं फ़ाइल से डेटा को बफर में पढ़ने के लिए उपयोग किया जाता है, जिसे बैकअप स्टोरेज माध्यम में लिखा जा सकता है। हालांकि, बैकअप रीड वैकल्पिक फ़ाइल स्ट्रीम बनाने वाले प्रत्येक वैकल्पिक डेटा स्ट्रीम के बारे में जानकारी खोजने के लिए भी बहुत आसान है। यह फ़ाइल में सभी डेटा को अलग बाइट स्ट्रीम की श्रृंखला के रूप में संसाधित करता है (प्रत्येक वैकल्पिक डेटा स्ट्रीम इन बाइट स्ट्रीमों में से एक है), और प्रत्येक धारा WIN32_STREAM_ID संरचना से पहले होती है। इस प्रकार, सभी धाराओं को गिनने के लिए, आपको बस प्रत्येक स्ट्रीम की शुरुआत से इन सभी WIN32_STREAM_ID संरचनाओं को पढ़ने की आवश्यकता है (यह वह जगह है जहां बैकअपसेक बहुत आसान हो जाता है, क्योंकि इसे स्ट्रीम से स्ट्रीम तक स्ट्रीम करने के लिए उपयोग किया जा सकता है फ़ाइल में सभी डेटा के माध्यम से पढ़ने के लिए)। शुरू करने के लिए, आपको पहले अप्रबंधित WIN32_STREAM_ID संरचना के लिए एक प्रबंधित समकक्ष बनाने की जरूरत:

typedef struct _WIN32_STREAM_ID { 
    DWORD dwStreamId; DWORD dwStreamAttributes; 
    LARGE_INTEGER Size; 
    DWORD dwStreamNameSize; 
    WCHAR cStreamName[ANYSIZE_ARRAY]; 
} WIN32_STREAM_ID; 

अधिकांश भाग के लिए, यह किसी भी अन्य संरचना आप पी/आह्वान के माध्यम से मार्शल चाहते हैं की तरह है। हालांकि, कुछ जटिलताओं हैं। सबसे पहले और सबसे महत्वपूर्ण, WIN32_STREAM_ID एक चर-आकार की संरचना है। इसका अंतिम सदस्य, सीस्ट्रीमनाम, लंबाई ANYSIZE_ARRAY के साथ एक सरणी है। जबकि ANYSIZE_ARRAY को 1 होने के लिए परिभाषित किया गया है, सीस्ट्रीमनाम पिछले चार फ़ील्ड के बाद संरचना में शेष डेटा का पता है, जिसका अर्थ है कि यदि संरचना को आकार (WIN32_STREAM_ID) बाइट्स से बड़ा होने के लिए आवंटित किया गया है, तो वह अतिरिक्त स्थान होगा असल में cStreamName सरणी का हिस्सा बनें। पिछले फ़ील्ड, dwStreamNameSize, यह निर्दिष्ट करता है कि सरणी कितनी देर तक है। हालांकि यह Win32 विकास के लिए बहुत अच्छा है, यह एक मार्शलर पर कहर बरकरार रखता है जिसे बैकअपअप के इंटरऑप कॉल के हिस्से के रूप में प्रबंधित डेटा को अप्रबंधित स्मृति से कॉपी करने की आवश्यकता होती है। मार्शलर कैसे जानता है कि WIN32_STREAM_ID संरचना वास्तव में कितनी बड़ी है, यह देखते हुए कि यह परिवर्तनीय आकार है? यह नहीं है दूसरी समस्या पैकिंग और संरेखण के साथ करना है। एक पल के लिए cStreamName की अनदेखी करते हुए अपने प्रबंधित WIN32_STREAM_ID समकक्ष के लिए निम्नलिखित संभावना पर विचार:

[StructLayout(LayoutKind.Sequential)] 
public struct Win32StreamID { 
    public int dwStreamId; 
    public int dwStreamAttributes; 
    public long Size; 
    public int dwStreamNameSize; 
} 

कोई Int32 आकार में 4 बाइट है और एक Int64 8 बाइट है। इस प्रकार, आप उम्मीद करेंगे कि यह संरचना 20 बाइट्स होगी।हालांकि, अगर आप निम्नलिखित कोड चलाने के लिए, आपको लगता है कि दोनों मूल्यों 24, नहीं 20 हैं मिल जाएगा:

int size1 = Marshal.SizeOf(typeof(Win32StreamID)); 
int size2 = sizeof(Win32StreamID); // in an unsafe context 

मुद्दा यह है कि संकलक सुनिश्चित करें कि इन संरचनाओं के भीतर मूल्यों पर हमेशा गठबंधन कर रहे हैं बनाना चाहता है उचित सीमा चार-बाइट मान 4 से विभाजित पते पर होना चाहिए, 8-बाइट मान 8 से विभाजित सीमाओं पर होना चाहिए, और इसी तरह। अब कल्पना करें कि क्या होगा यदि आप Win32StreamID संरचनाओं की एक सरणी बनाना चाहते थे। सरणी के पहले उदाहरण में सभी फ़ील्ड ठीक से गठबंधन किए जाएंगे। उदाहरण के लिए, चूंकि आकार फ़ील्ड दो 32-बिट पूर्णांक का पालन करता है, इसलिए यह 8-बाइट मान के लिए उपयुक्त सरणी की शुरुआत से 8 बाइट होगा। हालांकि, अगर संरचना आकार में 20-बाइट थी, तो सरणी में दूसरा उदाहरण उसके सभी सदस्यों को सही ढंग से गठबंधन नहीं करेगा। पूर्णांक मान सभी ठीक होंगे, लेकिन लंबी मान सरणी की शुरुआत से 28 बाइट्स होगी, एक मान 8 तक समान रूप से विभाजित नहीं है। इसे ठीक करने के लिए, कंपाइलर संरचना को 24 के आकार में पैड करता है, जैसे कि सभी खेतों को हमेशा ठीक से गठबंधन किया जाएगा (सरणी स्वयं मानते हैं)। यदि कंपाइलर सही काम कर रहा है, तो आप सोच रहे होंगे कि मैं इसके बारे में चिंतित क्यों हूं। आप देखेंगे कि यदि आप चित्रा 2 में कोड को देखते हैं तो मैंने वर्णित पहले मार्शलिंग मुद्दे को प्राप्त करने के लिए, वास्तव में Win32StreamID संरचना से cStreamName को छोड़ दिया है। मैं अपने Win32StreamID संरचना को भरने के लिए पर्याप्त बाइट्स में पढ़ने के लिए बैकअप रीड का उपयोग करता हूं, और फिर मैं संरचना के dwStreamNameSize फ़ील्ड की जांच करता हूं। अब जब मुझे पता है कि नाम कितना समय है, तो मैं फ़ाइल से स्ट्रिंग के मान में पढ़ने के लिए बैकअप रीड का उपयोग कर सकता हूं। यह सब ठीक है और बेवकूफ है, लेकिन अगर मार्शल.SizeOf 20 की बजाय मेरी Win32StreamID संरचना के लिए 24 लौटाता है, तो मैं बहुत अधिक डेटा पढ़ने का प्रयास कर रहा हूं। इससे बचने के लिए, मुझे यह सुनिश्चित करने की ज़रूरत है कि Win32StreamID का आकार वास्तव में 20 है और 24 नहीं है। यह स्ट्रक्चरलेआउट एट्रिब्यूट पर फ़ील्ड का उपयोग करके दो अलग-अलग तरीकों से पूरा किया जा सकता है जो संरचना को सजाते हैं।

[StructLayout(LayoutKind.Sequential, Size = 20)] 

दूसरा विकल्प पैक फ़ील्ड का उपयोग करने के लिए है: पहला आकार क्षेत्र है, जो क्रम को तय वास्तव में कितना बड़ा संरचना होना चाहिए उपयोग करने के लिए है। पैक पैकिंग आकार को इंगित करता है जिसका प्रयोग तब किया जाना चाहिए जब लेआउटकिंड। आवश्यक मान निर्दिष्ट किया गया हो और संरचना के भीतर फ़ील्ड के संरेखण को नियंत्रित करता है। एक प्रबंधित संरचना के लिए डिफ़ॉल्ट पैकिंग आकार 8 है। यदि मैं इसे 4 में बदलता हूं, तो मुझे 20-बाइट संरचना मिलती है जिसे मैं ढूंढ रहा हूं (और जैसा कि मैं वास्तव में इसे किसी सरणी में उपयोग नहीं कर रहा हूं, मैं दक्षता खोना नहीं चाहता या स्थिरता कि इस तरह की पैकिंग परिवर्तन से प्रभावित हो सकती है):

[StructLayout(LayoutKind.Sequential, Pack = 4)] 
public struct Win32StreamID { 
    public StreamType dwStreamId; 
    public int dwStreamAttributes; 
    public long Size; 
    public int dwStreamNameSize; // WCHAR cStreamName[1]; 
} 

जगह में इस कोड के साथ, मैं अब धाराओं के सभी एक फ़ाइल में, जैसा कि यहाँ दिखाया गणना कर सकते हैं:

static void Main(string[] args) { 
    foreach (string path in args) { 
     Console.WriteLine(path + ":"); 
     foreach (StreamInfo stream in FileStreamSearcher.GetStreams(new FileInfo(path))) { 
      Console.WriteLine("\t{0}\t{1}\t{2}", stream.Name != null ? stream.Name : "(unnamed)", stream.Type, stream.Size); 
     } 
    } 
} 

आप ' देखेंगे कि FileStreamSearcher का यह संस्करण FindFirstStreamW और FindNextStreamW का उपयोग करने वाले संस्करण की तुलना में अधिक जानकारी देता है। बैकअप रीड केवल प्राथमिक स्ट्रीम और वैकल्पिक डेटा स्ट्रीम से अधिक डेटा प्रदान कर सकता है, जो सुरक्षा जानकारी वाले डेटा पर भी काम कर रहा है, डेटा दोहरा सकता है, आदि। यदि आप केवल वैकल्पिक डेटा स्ट्रीम देखना चाहते हैं, तो आप StreamInfo की प्रकार की संपत्ति के आधार पर फ़िल्टर कर सकते हैं, जो वैकल्पिक डेटा स्ट्रीम के लिए StreamType.AlternateData होगा।

> echo ".NET Matters" > C:\test.txt 
> echo "MSDN Magazine" > C:\test.txt:magStream 
> StreamEnumerator.exe C:\test.txt 
test.txt: 
     (unnamed)    SecurityData 164 
     (unnamed)    Data   17 
     :magStream:$DATA  AlternateData 18 
> type C:\test.txt 
".NET Matters" 
> more < C:\test.txt:magStream 
"MSDN Magazine" 

तो, अब आप में संग्रहीत सभी वैकल्पिक डेटा स्ट्रीम के नाम को पुनः प्राप्त करने में समर्थ हैं: इस कोड का परीक्षण करने के लिए, आप है कि वैकल्पिक डेटा स्ट्रीम कमांड प्रॉम्प्ट पर गूंज आदेश का उपयोग कर एक फाइल बना सकते हैं एक पंक्ति। महान। लेकिन क्या होगा यदि आप वास्तव में उन धाराओं में से किसी एक में डेटा का उपयोग करना चाहते हैं? दुर्भाग्यवश, यदि आप फ़ाइलस्ट्रीम कन्स्ट्रक्टर में से किसी एक वैकल्पिक डेटा स्ट्रीम के लिए पथ पारित करने का प्रयास करते हैं, तो एक NotSupportedException फेंक दिया जाएगा: "दिए गए पथ का प्रारूप समर्थित नहीं है।" इसके आस-पास पहुंचने के लिए, आप kernel32 से प्रकट CreateFile फ़ंक्शन को सीधे एक्सेस करके फ़ाइलस्ट्रीम के पथ कैननिकलाइज़ेशन चेक को बाईपास कर सकते हैं।डीएलएल (देखें चित्रा 3)। मैंने CreateFile फ़ंक्शन के लिए पथ पर किसी भी प्रबंधित अनुमति जांच किए बिना निर्दिष्ट पथ के लिए एक सुरक्षितफाइल हैंडल खोलने और पुनर्प्राप्त करने के लिए P/Invoke का उपयोग किया है, इसलिए इसमें वैकल्पिक डेटा स्ट्रीम पहचानकर्ता शामिल हो सकते हैं। यह SafeFileHandle का उपयोग तब एक नया प्रबंधित फ़ाइलस्ट्रीम बनाने के लिए किया जाता है, जो आवश्यक पहुंच प्रदान करता है। उस जगह के साथ, System.IO नेमस्पेस की कार्यक्षमता का उपयोग कर वैकल्पिक डेटा स्ट्रीम की सामग्री में हेरफेर करना आसान है। निम्न उदाहरण पढ़ता है और सी की सामग्री को बाहर प्रिंट: \ test.txt: पिछले उदाहरण में बनाया magStream:

string path = @"C:\test.txt:magStream"; 
using (StreamReader reader = new StreamReader(CreateFileStream(path, FileAccess.Read, FileMode.Open, FileShare.Read))) { 
    Console.WriteLine(reader.ReadToEnd()); 
} 

3 चित्र CreateFile

private static FileStream CreateFileStream(string path, FileAccess access, FileMode mode, FileShare share) { 
    if (mode == FileMode.Append) mode = FileMode.OpenOrCreate; SafeFileHandle handle = CreateFile(path, access, share, IntPtr.Zero, mode, 0, IntPtr.Zero); 
    if (handle.IsInvalid) throw new IOException("Could not open file stream.", new Win32Exception()); 
    return new FileStream(handle, access); 
} 

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
private static extern SafeFileHandle CreateFile(string lpFileName, FileAccess dwDesiredAccess, FileShare dwShareMode, IntPtr lpSecurityAttributes, FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile); 

Stephen Toub के लिए पी/आह्वान का उपयोग करना MSDN Magazine from January 2006 में।

+4

लिंक का एकमात्र उत्तर खराब क्यों है इसका एक अच्छा उदाहरण है। –

+0

एमएसडीएन पत्रिकाओं के सभी लिंक टूटे हुए हैं, और एमएसडीएन वेबसाइट के लिंक जल्द ही टूट जाएंगे। कृपया उत्तर पर अधिक जानकारी शामिल करें। – AaA

14

यह nuget पैकेज CodeFluent Runtime Client है (अन्य उपयोगिताओं के साथ) NtfsAlternateStream Class जो बनाता/पढ़/अपडेट/हटा/गणना ऑपरेशन का समर्थन करता है।

+7

और यहां आपके पास इसका उपयोग करने के तरीके के बारे में कुछ उदाहरण हैं http://blog.codefluententities.com/2013/03/14/manipulating-ntfs-alternate-data-streams-in-c-with-the-codefluent-runtime- क्लाइंट / – polkduran

संबंधित मुद्दे