2012-12-11 15 views
8

मैं एक फ़ाइल को एक नए फ़ाइल नाम में कॉपी करना चाहता हूं। कभी कभी स्रोत फ़ाइलफ़ाइल.कॉपी() और प्रतीकात्मक लिंक

mklink C:\MyPath\ThisIsASymbolicLink.xml C:\MyPath\ThisIsTheOriginal.xml 

मैं इस कोड का उपयोग कर रहा साथ एक प्रतीकात्मक (फाइल) लिंक, बनाया हो सकता है:

string from = @"C:\MyPath\ThisIsASymbolicLink.xml"; 
string to = @"C:\MyPath\WantCopyOfOriginalFileHere.xml"; 
File.Copy(from, to, true); 

हालांकि, मैं एक IOException

नाम प्राप्त फ़ाइल का सिस्टम द्वारा हल नहीं किया जा सकता है।

जब from फ़ाइल वास्तव में एक प्रतीकात्मक लिंक है।

मैं उन मामलों के लिए कोड कैसे कर सकता हूं जहां स्रोत फ़ाइल वास्तविक फ़ाइल हो सकती है, या फ़ाइल के लिए एक प्रतीकात्मक लिंक हो सकता है?

+0

हम्म, यह एक फ़ाइल सिस्टम दुर्घटना है। किसी अन्य ड्राइव पर लिंक लक्ष्य की तरह कुछ जो अब मौजूद नहीं है। –

+0

@ हंसपैसेंट: यह एक ही ड्राइव पर सभी स्थानीय है, और मैंने अभी इस लिंक को बनाया है। –

+0

@ हंसपैसेंट: यह एक समान प्रश्न से संबंधित हो सकता है जिसे मैंने अभी पोस्ट किया है: http://stackoverflow.com/q/13831759/141172 –

उत्तर

12

इस blog post पर विस्तारित, मैंने विस्तार विधियों को बनाया है जो एक निर्देशिकाइंफो या फ़ाइलइन्फो लेते हैं जो मूल या प्रतीकात्मक लिंक को संदर्भित कर सकते हैं, और एक मूल स्ट्रिंग के पूर्ण योग्य पथ नाम को इंगित करने वाली स्ट्रिंग को वापस कर सकते हैं।

अनुप्रयोग कोड

आवेदन कोड इस प्रकार संशोधित किया गया है:

// Works whether or not file is a symbolic link 
string from = 
    new FileInfo(@"C:\MyPath\ThisIsASymbolicLink.xml").GetSymbolicLinkTarget(); 

एक्सटेंशन विधि संहिता

private const int FILE_SHARE_READ = 1; 
    private const int FILE_SHARE_WRITE = 2; 

    private const int CREATION_DISPOSITION_OPEN_EXISTING = 3; 

    private const int FILE_FLAG_BACKUP_SEMANTICS = 0x02000000; 

    // http://msdn.microsoft.com/en-us/library/aa364962%28VS.85%29.aspx 
    [DllImport("kernel32.dll", EntryPoint = "GetFinalPathNameByHandleW", CharSet = CharSet.Unicode, SetLastError = true)] 
    public static extern int GetFinalPathNameByHandle(IntPtr handle, [In, Out] StringBuilder path, int bufLen, int flags); 

    // http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx 
    [DllImport("kernel32.dll", EntryPoint = "CreateFileW", CharSet = CharSet.Unicode, SetLastError = true)] 
    public static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode, 
    IntPtr SecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile); 

    public static string GetSymbolicLinkTarget(this FileSystemInfo symlink) 
    { 
     using (SafeFileHandle fileHandle = CreateFile(symlink.FullName, 0, 2, System.IntPtr.Zero, CREATION_DISPOSITION_OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, System.IntPtr.Zero)) 
     { 
      if (fileHandle.IsInvalid) 
       throw new Win32Exception(Marshal.GetLastWin32Error()); 

      StringBuilder path = new StringBuilder(512); 
      int size = GetFinalPathNameByHandle(fileHandle.DangerousGetHandle(), path, path.Capacity, 0); 
      if (size < 0) 
       throw new Win32Exception(Marshal.GetLastWin32Error()); 
      // The remarks section of GetFinalPathNameByHandle mentions the return being prefixed with "\\?\" 
      // More information about "\\?\" here -> http://msdn.microsoft.com/en-us/library/aa365247(v=VS.85).aspx 
      if (path[0] == '\\' && path[1] == '\\' && path[2] == '?' && path[3] == '\\') 
       return path.ToString().Substring(4); 
      else 
       return path.ToString(); 
     } 
    } 

यूनिट टेस्ट

[TestClass] 
public class SymlinkTest 
{ 
    [TestInitialize] 
    public void SetupFiles() 
    { 
     if (!File.Exists(@"C:\Temp\SymlinkUnitTest\Original.txt")) throw new Exception("Run Symlinksetup.bat as Admin to create test data."); 
    } 

    [TestMethod] 
    public void OrdinaryFile() 
    { 
     string file = @"C:\Temp\SymlinkUnitTest\Original.txt"; 
     string actual = new FileInfo(file).GetSymbolicLinkTarget(); 
     Assert.IsTrue(actual.EndsWith(@"SymlinkUnitTest\Original.txt")); 
    } 

    [TestMethod] 
    public void FileSymlink() 
    { 
     string file = @"C:\Temp\SymlinkUnitTest\Symlink.txt"; 
     string actual = new FileInfo(file).GetSymbolicLinkTarget(); 
     Assert.IsTrue(actual.EndsWith(@"SymlinkUnitTest\Original.txt")); 
    } 

    [TestMethod] 
    public void OrdinaryDirectory() 
    { 
     string dir = @"C:\Temp\SymlinkUnitTest"; 
     string actual = new DirectoryInfo(dir).GetSymbolicLinkTarget(); 
     Assert.IsTrue(actual.EndsWith(@"SymlinkUnitTest")); 
    } 

    [TestMethod] 
    public void DirectorySymlink() 
    { 
     string dir = @"C:\Temp\SymlinkUnitTest"; 
     string actual = new DirectoryInfo(dir).GetSymbolicLinkTarget(); 
     Assert.IsTrue(actual.EndsWith(@"SymlinkUnitTest")); 
    } 
} 

बैच फ़ाइल बनाने के लिए यूनिट टेस्ट डाटा

प्रशासक ... mklink की एक आवश्यकता के रूप में चलाने की जानी चाहिए।

@Echo Off 
Echo Must be run as Administrator (due to mklink) 
mkdir C:\Temp 
mkdir C:\Temp\SymlinkUnitTest 
c: 
cd C:\Temp\SymlinkUnitTest 

echo Original File>Original.txt 
mklink Symlink.txt Original.txt 

mklink /D C:\Temp\SymlinkUnitTest\SymDir C:\Temp\SymlinkUnitTest 
+1

उत्तर देने के लिए धन्यवाद, इससे वास्तव में मेरी मदद मिली! मुझे एक मुद्दा मिला, हालांकि - सेफफाइलहैंडल डिस्पोजेबल है और आप या तो() या .dispose() का उपयोग करने के लिए भूल गए हैं। मेरे मामले में, मैं लक्ष्य फ़ाइल के आकार की जांच करने के बाद एक सिम्लिंक हटा रहा था, और इसलिए फ़ाइल को वास्तव में हटाया नहीं गया था क्योंकि मैं अभी भी फ़ाइल में हैंडल रख रहा था। – BigScary

+0

@ बिगस्केरी: अच्छी पकड़। मैंने कोड अपडेट किया। एमएसडीएन ने अपने उदाहरणों में उचित कोडिंग पैटर्न शामिल करने की आदत शुरू की, दुर्भाग्य से कुछ ब्लॉगर्स ने आगे बढ़े हैं। –

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