259 वर्णों से अधिक लंबे नाम वाली फ़ाइलों से कैसे निपटें?


82

मैं एक ऐसे एप्लिकेशन पर काम कर रहा हूं, जो कुछ निर्देशिकाओं में हर फ़ाइल के माध्यम से चलता है और उन फ़ाइलों के साथ कुछ क्रियाएं करता है। दूसरों के बीच, मुझे फ़ाइल का आकार और वह तिथि पुनः प्राप्त करनी चाहिए जब इस फ़ाइल को संशोधित किया गया था।

कुछ फ़ाइल पूर्ण नाम (निर्देशिका + फ़ाइल का नाम) बहुत लंबा है, मैं .NET फ्रेमवर्क का उपयोग नहीं कर सकता FileInfo, जो MAX_PATH(260 वर्ण) तक सीमित है । कई वेब स्रोतों ने उन फ़ाइलों को एक्सेस करने के लिए P / Invoke के माध्यम से देशी Win32 फ़ंक्शन का उपयोग करने की सलाह दी है जिनके नाम बहुत लंबे हैं।

वर्तमान में, बिल्कुल वही समस्या Win32 फ़ंक्शन के साथ उत्पन्न होती है। उदाहरण के लिए, GetFileAttributesEx(kernel32.dll) Win32 त्रुटि 3 ERROR_PATH_NOT_FOUND 270 बाइट्स के पथ के साथ विफल हो जाता है।

बहुत ही फ़ाइल को सफलतापूर्वक Notepad2 से खोला जा सकता है और सफलतापूर्वक Windows एक्सप्लोरर (लेकिन दृश्य स्टूडियो 2010 उदाहरण के लिए 259 वर्ण सीमा के कारण इसे खोलने में विफल रहता है) के साथ प्रदर्शित किया जा सकता है।

जब फ़ाइल पथ 270 वर्ण लंबा हो, तो मैं फ़ाइल तक पहुंचने में सक्षम होने के लिए क्या कर सकता हूं?

टिप्पणियाँ:

  • 259 वर्णों से अधिक लंबे फ़ाइल पथ लंबाई वाली फ़ाइलों को निकालना या अनदेखा करना समाधान नहीं है।

  • मैं यूनिकोड-संगत समाधानों की तलाश में हूं।

  • अनुप्रयोग Windows 2008 / Vista या बाद में .NET फ्रेमवर्क 4 स्थापित के साथ चलेगा।


2007 आश्चर्यजनक रूप से, Microsoft Word 2007 यह शिकायत करता है कि कंप्यूटर पर "फ़्लॉपी डिस्क बहुत छोटी है", जिसमें कोई फ़्लॉपी ड्राइव नहीं है, या जब 4 GB RAM शेष है, या अंत में "RAM मेमोरी कम है"। "एंटीवायरस सॉफ़्टवेयर [...] को अद्यतन करने की आवश्यकता है"। क्या वे कम से कम Microsoft Office जैसे प्रमुख उत्पादों में ऐसी मूर्खतापूर्ण अर्थहीन त्रुटियों को प्रदर्शित करने से एक दिन रोक देंगे?


1
मेरा मानना ​​है कि इन दिनों, यह भी है कि हर फ़ाइल नाम 8.3 प्रारूप फ़ाइल नाम के लिए, आप उस का उपयोग नहीं कर सकते हैं? en.wikipedia.org/wiki/…
थॉमस

6
यहां तक ​​कि एक 8.3 प्रारूप फ़ाइल नाम 260 वर्णों को पार कर सकता है, आपको बस गहरे फ़ोल्डर नेस्टिंग की आवश्यकता होती है।
डेविड हेफर्नन

1
ध्यान दें कि आप कर सकते हैं (और क्योंकि यह I / O ओवरहेड जोड़ता है) 8.3 नाम निर्माण को अक्षम कर सकता है, इसलिए, नहीं, आप यह सुनिश्चित नहीं कर सकते कि 8.3 मौजूद है। देखते हैं fsutil.exe 8dot3name
बेकन बिट्स

जवाबों:


81

.NET 4.6.2 समाधान

यहाँ\\?\C:\Verrrrrrrrrrrry long path वर्णित के रूप में वाक्यविन्यास का उपयोग करें

.NET कोर समाधान

यह सिर्फ इसलिए काम करता है क्योंकि फ्रेमवर्क आपके लिए लंबे पथ सिंटैक्स को जोड़ता है।

Pre .NET 4.6.2 समाधान

P / Invoke के साथ Win32 API फ़ंक्शन के लंबे पथ सिंटैक्स और यूनिकोड संस्करण का भी उपयोग करें से फ़ाइलें, पथ और नेमस्पेस नामकरण :

विंडोज एपीआई में कई कार्य हैं जिनमें 32,767 वर्णों की अधिकतम पथ लंबाई के लिए विस्तारित-लंबाई पथ की अनुमति देने के लिए यूनिकोड संस्करण भी हैं। इस प्रकार का पथ बैकस्लैश द्वारा अलग किए गए घटकों से बना होता है, प्रत्येक अप करने के लिए GetVolumeInformation फ़ंक्शन के lpMaximumComponentLength पैरामीटर में दिए गए मान (यह मान सामान्यत: 255 वर्ण है)। विस्तारित-लंबाई पथ निर्दिष्ट करने के लिए, \\?\उपसर्ग का उपयोग करें । उदाहरण के लिए, \\?\D:\very long path

इस Microsoft समर्थन पृष्ठ को पढ़ना को भी दिलचस्प हो सकता है।

बीसीएल टीम ब्लॉग पर किम हैमिल्टन द्वारा .NET में लॉन्ग पाथ्स में एक बहुत व्यापक स्पष्टीकरण इन रास्तों को संभालने में कुछ अड़चनों को सूचीबद्ध करता है जो वह दावा करते हैं कि यह वाक्य रचना अभी भी .NET में सीधे समर्थित नहीं है:

कई कारण हैं जो हम अतीत में लंबे रास्ते जोड़ने के लिए अनिच्छुक थे, और हम अभी भी इसके बारे में सावधान क्यों हैं <...>।

<...> \\?\उपसर्ग न केवल लंबे रास्तों को सक्षम करता है; यह विंडोज एपीआई द्वारा न्यूनतम संशोधन के साथ फाइल सिस्टम में पारित होने का मार्ग बनाता है। एक परिणाम यह है कि \\?\विंडोज एपीआई द्वारा निष्पादित फ़ाइल नाम सामान्यीकरण को बंद कर दिया जाता है, जिसमें अनुगामी रिक्त स्थान को निकालना, विस्तार करना शामिल है। और '..', सापेक्ष पथों को पूर्ण पथों में परिवर्तित करना, और इसी तरह <<>>

<...> \\?\उपसर्ग के साथ लंबे पथ का उपयोग अधिकांश फ़ाइल-संबंधित विंडोज एपीआई में किया जा सकता है , लेकिन सभी विंडोज एपीआई नहीं। उदाहरण के लिए, LoadLibrary <...> विफल रहता है यदि फ़ाइल का नाम MAX_PATH से अधिक लंबा है। <...> पूरे विंडोज एपीआई में समान उदाहरण हैं; कुछ वर्कअराउंड मौजूद हैं, लेकिन वे केस-बाय-केस आधार पर हैं।

एक अन्य कारक <...> अन्य विंडोज-आधारित अनुप्रयोगों और स्वयं विंडोज शेल के साथ संगतता है <...>

क्योंकि यह समस्या आम होती जा रही है <...> इसे संबोधित करने के लिए पूरे Microsoft में प्रयास किए जा रहे हैं। वास्तव में, समय पर विस्टा प्लग के रूप में, आपको कुछ परिवर्तन दिखाई देंगे जो MAX_PATH की सीमा से टकराने की संभावना को कम करते हैं: कई विशेष फ़ोल्डर नामों को छोटा कर दिया गया है, और अधिक दिलचस्प बात यह है कि शेल एक ऑटो-पथ सिकुड़ सुविधा का उपयोग कर रहा है <...> उन्हें 260 वर्णों में निचोड़ने का प्रयास।


चेतावनी: आपको सीधे विंडोज एपीआई को कॉल करने की आवश्यकता हो सकती है, क्योंकि मुझे लगता है कि .NET फ्रेमवर्क इस तरह के पथ सिंटैक्स का समर्थन नहीं कर सकता है।


हां, 3.5 ने इस तरह के रास्ते का समर्थन नहीं किया। मुझे संदेह है कि 4.0 ने इसे जोड़ा।
जेमी पेनी

3
हाँ, आप होगा पी / आह्वान करने के लिए Win32 एपीआई कार्यों की जरूरत है और उन्हें एक .NET अनुप्रयोग से सीधे कहते हैं। .NET की आंतरिक पाइपलाइन (विशेष रूप से, एक PathHelperवर्ग) पथ को मान्य करती है और अपवाद को फेंकता है यदि यह MAX_PATH(260) वर्णों से अधिक है ।
कोड़ी ग्रे

12
@AmaniKilumanga: तब आपका रास्ता मूल रूप से 6000 शब्दों का निबंध है और सिस्टम इसे संभाल नहीं सकता है।
user541686

1
@denahiro: शायद आप इसे संपादित करने के लिए स्वतंत्रता ले सकते हैं ... जैसा कि पिछले व्यक्ति ने इसे वहां रखा (मैंने नहीं किया ...)
user541686

1
बहुत सटीक - \\? \
_

33

मैंने उस मुद्दे को हल करने के लिए अपनी LongFileऔर LongDirectoryकक्षाएं बनाईं। जब भी मैं सामान्य रूप से उपयोग करूंगा, मैं इसका उपयोग करता हूं System.IO.File

इस पर अनुकूलन आदि हो सकते हैं, लेकिन यह वर्षों से अच्छी तरह से काम कर रहा है।

public static class LongFile
{
    private const int MAX_PATH = 260;

    public static bool Exists(string path)
    {
        if (path.Length < MAX_PATH) return System.IO.File.Exists(path);
        var attr = NativeMethods.GetFileAttributesW(GetWin32LongPath(path));
        return (attr != NativeMethods.INVALID_FILE_ATTRIBUTES && ((attr & NativeMethods.FILE_ATTRIBUTE_ARCHIVE) == NativeMethods.FILE_ATTRIBUTE_ARCHIVE));
    }

    public static void Delete(string path)
    {
        if (path.Length < MAX_PATH) System.IO.File.Delete(path);
        else
        {
            bool ok = NativeMethods.DeleteFileW(GetWin32LongPath(path));
            if (!ok) ThrowWin32Exception();
        }
    }

    public static void AppendAllText(string path, string contents)
    {
        AppendAllText(path, contents, Encoding.Default);
    }

    public static void AppendAllText(string path, string contents, Encoding encoding)
    {
        if (path.Length < MAX_PATH)
        {
            System.IO.File.AppendAllText(path, contents, encoding);
        }
        else
        {
            var fileHandle = CreateFileForAppend(GetWin32LongPath(path));
            using (var fs = new System.IO.FileStream(fileHandle, System.IO.FileAccess.Write))
            {
                var bytes = encoding.GetBytes(contents);
                fs.Position = fs.Length;
                fs.Write(bytes, 0, bytes.Length);
            }
        }
    }

    public static void WriteAllText(string path, string contents)
    {
        WriteAllText(path, contents, Encoding.Default);
    }

    public static void WriteAllText(string path, string contents, Encoding encoding)
    {
        if (path.Length < MAX_PATH)
        {
            System.IO.File.WriteAllText(path, contents, encoding);
        }
        else
        {
            var fileHandle = CreateFileForWrite(GetWin32LongPath(path));

            using (var fs = new System.IO.FileStream(fileHandle, System.IO.FileAccess.Write))
            {
                var bytes = encoding.GetBytes(contents);
                fs.Write(bytes, 0, bytes.Length);
            }
        }
    }

    public static void WriteAllBytes(string path, byte[] bytes)
    {
        if (path.Length < MAX_PATH)
        {
            System.IO.File.WriteAllBytes(path, bytes);
        }
        else
        {
            var fileHandle = CreateFileForWrite(GetWin32LongPath(path));

            using (var fs = new System.IO.FileStream(fileHandle, System.IO.FileAccess.Write))
            {
                fs.Write(bytes, 0, bytes.Length);
            }
        }
    }

    public static void Copy(string sourceFileName, string destFileName)
    {
        Copy(sourceFileName, destFileName, false);
    }

    public static void Copy(string sourceFileName, string destFileName, bool overwrite)
    {
        if (sourceFileName.Length < MAX_PATH && (destFileName.Length < MAX_PATH)) System.IO.File.Copy(sourceFileName, destFileName, overwrite);
        else
        {
            var ok = NativeMethods.CopyFileW(GetWin32LongPath(sourceFileName), GetWin32LongPath(destFileName), !overwrite);
            if (!ok) ThrowWin32Exception();
        }
    }

    public static void Move(string sourceFileName, string destFileName)
    {
        if (sourceFileName.Length < MAX_PATH && (destFileName.Length < MAX_PATH)) System.IO.File.Move(sourceFileName, destFileName);
        else
        {
            var ok = NativeMethods.MoveFileW(GetWin32LongPath(sourceFileName), GetWin32LongPath(destFileName));
            if (!ok) ThrowWin32Exception();
        }
    }

    public static string ReadAllText(string path)
    {
        return ReadAllText(path, Encoding.Default);
    }

    public static string ReadAllText(string path, Encoding encoding)
    {
        if (path.Length < MAX_PATH) { return System.IO.File.ReadAllText(path, encoding); }
        var fileHandle = GetFileHandle(GetWin32LongPath(path));

        using (var fs = new System.IO.FileStream(fileHandle, System.IO.FileAccess.Read))
        {
            var data = new byte[fs.Length];
            fs.Read(data, 0, data.Length);
            return encoding.GetString(data);
        }
    }

    public static string[] ReadAllLines(string path)
    {
        return ReadAllLines(path, Encoding.Default);
    }

    public static string[] ReadAllLines(string path, Encoding encoding)
    {
        if (path.Length < MAX_PATH) { return System.IO.File.ReadAllLines(path, encoding); }
        var fileHandle = GetFileHandle(GetWin32LongPath(path));

        using (var fs = new System.IO.FileStream(fileHandle, System.IO.FileAccess.Read))
        {
            var data = new byte[fs.Length];
            fs.Read(data, 0, data.Length);
            var str = encoding.GetString(data);
            if (str.Contains("\r")) return str.Split(new[] { "\r\n" }, StringSplitOptions.None);
            return str.Split('\n');
        }
    }
    public static byte[] ReadAllBytes(string path)
    {
        if (path.Length < MAX_PATH) return System.IO.File.ReadAllBytes(path);
        var fileHandle = GetFileHandle(GetWin32LongPath(path));

        using (var fs = new System.IO.FileStream(fileHandle, System.IO.FileAccess.Read))
        {
            var data = new byte[fs.Length];
            fs.Read(data, 0, data.Length);
            return data;
        }
    }


    public static void SetAttributes(string path, FileAttributes attributes)
    {
        if (path.Length < MAX_PATH)
        {
            System.IO.File.SetAttributes(path, attributes);
        }
        else
        {
            var longFilename = GetWin32LongPath(path);
            NativeMethods.SetFileAttributesW(longFilename, (int)attributes);
        }
    }

    #region Helper methods

    private static SafeFileHandle CreateFileForWrite(string filename)
    {
        if (filename.Length >= MAX_PATH) filename = GetWin32LongPath(filename);
        SafeFileHandle hfile = NativeMethods.CreateFile(filename, (int)NativeMethods.FILE_GENERIC_WRITE, NativeMethods.FILE_SHARE_NONE, IntPtr.Zero, NativeMethods.CREATE_ALWAYS, 0, IntPtr.Zero);
        if (hfile.IsInvalid) ThrowWin32Exception();
        return hfile;
    }

    private static SafeFileHandle CreateFileForAppend(string filename)
    {
        if (filename.Length >= MAX_PATH) filename = GetWin32LongPath(filename);
        SafeFileHandle hfile = NativeMethods.CreateFile(filename, (int)NativeMethods.FILE_GENERIC_WRITE, NativeMethods.FILE_SHARE_NONE, IntPtr.Zero, NativeMethods.CREATE_NEW, 0, IntPtr.Zero);
        if (hfile.IsInvalid)
        {
            hfile = NativeMethods.CreateFile(filename, (int)NativeMethods.FILE_GENERIC_WRITE, NativeMethods.FILE_SHARE_NONE, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero);
            if (hfile.IsInvalid) ThrowWin32Exception();
        }
        return hfile;
    }

    internal static SafeFileHandle GetFileHandle(string filename)
    {
        if (filename.Length >= MAX_PATH) filename = GetWin32LongPath(filename);
        SafeFileHandle hfile = NativeMethods.CreateFile(filename, (int)NativeMethods.FILE_GENERIC_READ, NativeMethods.FILE_SHARE_READ, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero);
        if (hfile.IsInvalid) ThrowWin32Exception();
        return hfile;
    }

    internal static SafeFileHandle GetFileHandleWithWrite(string filename)
    {
        if (filename.Length >= MAX_PATH) filename = GetWin32LongPath(filename);
        SafeFileHandle hfile = NativeMethods.CreateFile(filename, (int)(NativeMethods.FILE_GENERIC_READ | NativeMethods.FILE_GENERIC_WRITE | NativeMethods.FILE_WRITE_ATTRIBUTES), NativeMethods.FILE_SHARE_NONE, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero);
        if (hfile.IsInvalid) ThrowWin32Exception();
        return hfile;
    }

    public static System.IO.FileStream GetFileStream(string filename, FileAccess access = FileAccess.Read)
    {
        var longFilename = GetWin32LongPath(filename);
        SafeFileHandle hfile;
        if (access == FileAccess.Write)
        {
            hfile = NativeMethods.CreateFile(longFilename, (int)(NativeMethods.FILE_GENERIC_READ | NativeMethods.FILE_GENERIC_WRITE | NativeMethods.FILE_WRITE_ATTRIBUTES), NativeMethods.FILE_SHARE_NONE, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero);
        }
        else
        {
            hfile = NativeMethods.CreateFile(longFilename, (int)NativeMethods.FILE_GENERIC_READ, NativeMethods.FILE_SHARE_READ, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero);
        }

        if (hfile.IsInvalid) ThrowWin32Exception();

        return new System.IO.FileStream(hfile, access);
    }


    [DebuggerStepThrough]
    public static void ThrowWin32Exception()
    {
        int code = Marshal.GetLastWin32Error();
        if (code != 0)
        {
            throw new System.ComponentModel.Win32Exception(code);
        }
    }

    public static string GetWin32LongPath(string path)
    {
        if (path.StartsWith(@"\\?\")) return path;

        if (path.StartsWith("\\"))
        {
            path = @"\\?\UNC\" + path.Substring(2);
        }
        else if (path.Contains(":"))
        {
            path = @"\\?\" + path;
        }
        else
        {
            var currdir = Environment.CurrentDirectory;
            path = Combine(currdir, path);
            while (path.Contains("\\.\\")) path = path.Replace("\\.\\", "\\");
            path = @"\\?\" + path;
        }
        return path.TrimEnd('.'); ;
    }

    private static string Combine(string path1, string path2)
    {
        return path1.TrimEnd('\\') + "\\" + path2.TrimStart('\\').TrimEnd('.'); ;
    }


    #endregion

    public static void SetCreationTime(string path, DateTime creationTime)
    {
        long cTime = 0;
        long aTime = 0;
        long wTime = 0;

        using (var handle = GetFileHandleWithWrite(path))
        {
            NativeMethods.GetFileTime(handle, ref cTime, ref aTime, ref wTime);
            var fileTime = creationTime.ToFileTimeUtc();
            if (!NativeMethods.SetFileTime(handle, ref fileTime, ref aTime, ref wTime))
            {
                throw new Win32Exception();
            }
        }
    }

    public static void SetLastAccessTime(string path, DateTime lastAccessTime)
    {
        long cTime = 0;
        long aTime = 0;
        long wTime = 0;

        using (var handle = GetFileHandleWithWrite(path))
        {
            NativeMethods.GetFileTime(handle, ref cTime, ref aTime, ref wTime);

            var fileTime = lastAccessTime.ToFileTimeUtc();
            if (!NativeMethods.SetFileTime(handle, ref cTime, ref fileTime, ref wTime))
            {
                throw new Win32Exception();
            }
        }
    }

    public static void SetLastWriteTime(string path, DateTime lastWriteTime)
    {
        long cTime = 0;
        long aTime = 0;
        long wTime = 0;

        using (var handle = GetFileHandleWithWrite(path))
        {
            NativeMethods.GetFileTime(handle, ref cTime, ref aTime, ref wTime);

            var fileTime = lastWriteTime.ToFileTimeUtc();
            if (!NativeMethods.SetFileTime(handle, ref cTime, ref aTime, ref fileTime))
            {
                throw new Win32Exception();
            }
        }
    }

    public static DateTime GetLastWriteTime(string path)
    {
        long cTime = 0;
        long aTime = 0;
        long wTime = 0;

        using (var handle = GetFileHandleWithWrite(path))
        {
            NativeMethods.GetFileTime(handle, ref cTime, ref aTime, ref wTime);

            return DateTime.FromFileTimeUtc(wTime);
        }
    }

}

और एक संगत LongDirectory:

public class LongDirectory
{
    private const int MAX_PATH = 260;

    public static void CreateDirectory(string path)
    {
        if (string.IsNullOrWhiteSpace(path)) return;
        if (path.Length < MAX_PATH)
        {
            System.IO.Directory.CreateDirectory(path);
        }
        else
        {
            var paths = GetAllPathsFromPath(GetWin32LongPath(path));
            foreach (var item in paths)
            {
                if (!LongExists(item))
                {
                    var ok = NativeMethods.CreateDirectory(item, IntPtr.Zero);
                    if (!ok)
                    {
                        ThrowWin32Exception();
                    }
                }
            }
        }
    }

    public static void Delete(string path)
    {
        Delete(path, false);
    }

    public static void Delete(string path, bool recursive)
    {
        if (path.Length < MAX_PATH && !recursive)
        {
            System.IO.Directory.Delete(path, false);
        }
        else
        {
            if (!recursive)
            {
                bool ok = NativeMethods.RemoveDirectory(GetWin32LongPath(path));
                if (!ok) ThrowWin32Exception();
            }
            else
            {
                DeleteDirectories(new string[] { GetWin32LongPath(path) });
            }
        }
    }


    private static void DeleteDirectories(string[] directories)
    {
        foreach (string directory in directories)
        {
            string[] files = LongDirectory.GetFiles(directory, null, System.IO.SearchOption.TopDirectoryOnly);
            foreach (string file in files)
            {
                LongFile.Delete(file);
            }
            directories = LongDirectory.GetDirectories(directory, null, System.IO.SearchOption.TopDirectoryOnly);
            DeleteDirectories(directories);
            bool ok = NativeMethods.RemoveDirectory(GetWin32LongPath(directory));
            if (!ok) ThrowWin32Exception();
        }
    }

    public static bool Exists(string path)
    {
        if (path.Length < MAX_PATH) return System.IO.Directory.Exists(path);
        return LongExists(GetWin32LongPath(path));
    }

    private static bool LongExists(string path)
    {
        var attr = NativeMethods.GetFileAttributesW(path);
        return (attr != NativeMethods.INVALID_FILE_ATTRIBUTES && ((attr & NativeMethods.FILE_ATTRIBUTE_DIRECTORY) == NativeMethods.FILE_ATTRIBUTE_DIRECTORY));
    }


    public static string[] GetDirectories(string path)
    {
        return GetDirectories(path, null, SearchOption.TopDirectoryOnly);
    }

    public static string[] GetDirectories(string path, string searchPattern)
    {
        return GetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly);
    }

    public static string[] GetDirectories(string path, string searchPattern, System.IO.SearchOption searchOption)
    {
        searchPattern = searchPattern ?? "*";
        var dirs = new List<string>();
        InternalGetDirectories(path, searchPattern, searchOption, ref dirs);
        return dirs.ToArray();
    }

    private static void InternalGetDirectories(string path, string searchPattern, System.IO.SearchOption searchOption, ref List<string> dirs)
    {
        NativeMethods.WIN32_FIND_DATA findData;
        IntPtr findHandle = NativeMethods.FindFirstFile(System.IO.Path.Combine(GetWin32LongPath(path), searchPattern), out findData);

        try
        {
            if (findHandle != new IntPtr(-1))
            {

                do
                {
                    if ((findData.dwFileAttributes & System.IO.FileAttributes.Directory) != 0)
                    {
                        if (findData.cFileName != "." && findData.cFileName != "..")
                        {
                            string subdirectory = System.IO.Path.Combine(path, findData.cFileName);
                            dirs.Add(GetCleanPath(subdirectory));
                            if (searchOption == SearchOption.AllDirectories)
                            {
                                InternalGetDirectories(subdirectory, searchPattern, searchOption, ref dirs);
                            }
                        }
                    }
                } while (NativeMethods.FindNextFile(findHandle, out findData));
                NativeMethods.FindClose(findHandle);
            }
            else
            {
                ThrowWin32Exception();
            }
        }
        catch (Exception)
        {
            NativeMethods.FindClose(findHandle);
            throw;
        }
    }

    public static string[] GetFiles(string path)
    {
        return GetFiles(path, null, SearchOption.TopDirectoryOnly);
    }

    public static string[] GetFiles(string path, string searchPattern)
    {
        return GetFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
    }


    public static string[] GetFiles(string path, string searchPattern, System.IO.SearchOption searchOption)
    {
        searchPattern = searchPattern ?? "*";

        var files = new List<string>();
        var dirs = new List<string> { path };

        if (searchOption == SearchOption.AllDirectories)
        {
            //Add all the subpaths
            dirs.AddRange(LongDirectory.GetDirectories(path, null, SearchOption.AllDirectories));
        }

        foreach (var dir in dirs)
        {
            NativeMethods.WIN32_FIND_DATA findData;
            IntPtr findHandle = NativeMethods.FindFirstFile(System.IO.Path.Combine(GetWin32LongPath(dir), searchPattern), out findData);

            try
            {
                if (findHandle != new IntPtr(-1))
                {

                    do
                    {
                        if ((findData.dwFileAttributes & System.IO.FileAttributes.Directory) == 0)
                        {
                            string filename = System.IO.Path.Combine(dir, findData.cFileName);
                            files.Add(GetCleanPath(filename));
                        }
                    } while (NativeMethods.FindNextFile(findHandle, out findData));
                    NativeMethods.FindClose(findHandle);
                }
            }
            catch (Exception)
            {
                NativeMethods.FindClose(findHandle);
                throw;
            }
        }

        return files.ToArray();
    }



    public static void Move(string sourceDirName, string destDirName)
    {
        if (sourceDirName.Length < MAX_PATH || destDirName.Length < MAX_PATH)
        {
            System.IO.Directory.Move(sourceDirName, destDirName);
        }
        else
        {
            var ok = NativeMethods.MoveFileW(GetWin32LongPath(sourceDirName), GetWin32LongPath(destDirName));
            if (!ok) ThrowWin32Exception();
        }
    }

    #region Helper methods



    [DebuggerStepThrough]
    public static void ThrowWin32Exception()
    {
        int code = Marshal.GetLastWin32Error();
        if (code != 0)
        {
            throw new System.ComponentModel.Win32Exception(code);
        }
    }

    public static string GetWin32LongPath(string path)
    {

        if (path.StartsWith(@"\\?\")) return path;

        var newpath = path;
        if (newpath.StartsWith("\\"))
        {
            newpath = @"\\?\UNC\" + newpath.Substring(2);
        }
        else if (newpath.Contains(":"))
        {
            newpath = @"\\?\" + newpath;
        }
        else
        {
            var currdir = Environment.CurrentDirectory;
            newpath = Combine(currdir, newpath);
            while (newpath.Contains("\\.\\")) newpath = newpath.Replace("\\.\\", "\\");
            newpath = @"\\?\" + newpath;
        }
        return newpath.TrimEnd('.');
    }

    private static string GetCleanPath(string path)
    {
        if (path.StartsWith(@"\\?\UNC\")) return @"\\" + path.Substring(8);
        if (path.StartsWith(@"\\?\")) return path.Substring(4);
        return path;
    }

    private static List<string> GetAllPathsFromPath(string path)
    {
        bool unc = false;
        var prefix = @"\\?\";
        if (path.StartsWith(prefix + @"UNC\"))
        {
            prefix += @"UNC\";
            unc = true;
        }
        var split = path.Split('\\');
        int i = unc ? 6 : 4;
        var list = new List<string>();
        var txt = "";

        for (int a = 0; a < i; a++)
        {
            if (a > 0) txt += "\\";
            txt += split[a];
        }
        for (; i < split.Length; i++)
        {
            txt = Combine(txt, split[i]);
            list.Add(txt);
        }

        return list;
    }

    private static string Combine(string path1, string path2)
    {
        return path1.TrimEnd('\\') + "\\" + path2.TrimStart('\\').TrimEnd('.');
    }


    #endregion
}

NativeMethods:

internal static class NativeMethods
{
    internal const int FILE_ATTRIBUTE_ARCHIVE = 0x20;
    internal const int INVALID_FILE_ATTRIBUTES = -1;

    internal const int FILE_READ_DATA = 0x0001;
    internal const int FILE_WRITE_DATA = 0x0002;
    internal const int FILE_APPEND_DATA = 0x0004;
    internal const int FILE_READ_EA = 0x0008;
    internal const int FILE_WRITE_EA = 0x0010;

    internal const int FILE_READ_ATTRIBUTES = 0x0080;
    internal const int FILE_WRITE_ATTRIBUTES = 0x0100;

    internal const int FILE_SHARE_NONE = 0x00000000;
    internal const int FILE_SHARE_READ = 0x00000001;

    internal const int FILE_ATTRIBUTE_DIRECTORY = 0x10;

    internal const long FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE |
                                                FILE_WRITE_DATA |
                                                FILE_WRITE_ATTRIBUTES |
                                                FILE_WRITE_EA |
                                                FILE_APPEND_DATA |
                                                SYNCHRONIZE;

    internal const long FILE_GENERIC_READ = STANDARD_RIGHTS_READ |
                                            FILE_READ_DATA |
                                            FILE_READ_ATTRIBUTES |
                                            FILE_READ_EA |
                                            SYNCHRONIZE;



    internal const long READ_CONTROL = 0x00020000L;
    internal const long STANDARD_RIGHTS_READ = READ_CONTROL;
    internal const long STANDARD_RIGHTS_WRITE = READ_CONTROL;

    internal const long SYNCHRONIZE = 0x00100000L;

    internal const int CREATE_NEW = 1;
    internal const int CREATE_ALWAYS = 2;
    internal const int OPEN_EXISTING = 3;

    internal const int MAX_PATH = 260;
    internal const int MAX_ALTERNATE = 14;

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    internal struct WIN32_FIND_DATA
    {
        public System.IO.FileAttributes dwFileAttributes;
        public FILETIME ftCreationTime;
        public FILETIME ftLastAccessTime;
        public FILETIME ftLastWriteTime;
        public uint nFileSizeHigh; //changed all to uint, otherwise you run into unexpected overflow
        public uint nFileSizeLow;  //|
        public uint dwReserved0;   //|
        public uint dwReserved1;   //v
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
        public string cFileName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_ALTERNATE)]
        public string cAlternate;
    }


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


    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern bool CopyFileW(string lpExistingFileName, string lpNewFileName, bool bFailIfExists);


    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern int GetFileAttributesW(string lpFileName);


    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern bool DeleteFileW(string lpFileName);


    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern bool MoveFileW(string lpExistingFileName, string lpNewFileName);


    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern bool SetFileTime(SafeFileHandle hFile, ref long lpCreationTime, ref long lpLastAccessTime, ref long lpLastWriteTime);


    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern bool GetFileTime(SafeFileHandle hFile, ref long lpCreationTime, ref long lpLastAccessTime, ref long lpLastWriteTime);


    [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);


    [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);


    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern bool FindClose(IntPtr hFindFile);


    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern bool RemoveDirectory(string path);


    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern bool CreateDirectory(string lpPathName, IntPtr lpSecurityAttributes);


    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern int SetFileAttributesW(string lpFileName, int fileAttributes);
}

StackOverflow स्रोत कोड के पुस्तकालयों को साझा करने के लिए एक अच्छी जगह नहीं है। यदि आप चाहते हैं कि यह वास्तव में अन्य डेवलपर्स द्वारा उपयोग किया जाए, तो मेरा मानना ​​है कि आपको (1) इसे GitHub या इसी तरह की सेवा पर प्रकाशित करना चाहिए, (2) में यूनिट परीक्षण शामिल हैं, और (3) इसे NuGet पैकेज के रूप में प्रकाशित करें; वैकल्पिक रूप से, यदि आप अपने पुस्तकालय में योगदान करने के लिए अन्य लोगों को प्रोत्साहित करना चाहते हैं, तो आपको प्रलेखन जोड़ने पर विचार करना चाहिए। फिर आपने जो किया और जो इस लाइब्रेरी ने मूल प्रश्न (क्योंकि यह करता है!) का उत्तर देने के लिए और गीथहब और नुगेट के संगत लिंक को शामिल करने के लिए इस उत्तर को संपादित किया।
आर्सेनी मूरज़ेंको

13
यह मेरे व्यक्तिगत TFS रिपॉजिटरी (visualstudio.com) पर एक बड़ी परियोजना से सिर्फ कुछ कक्षाएं है। सोचा था कि मैं इसे साझा करता हूं क्योंकि मैं अक्सर सॉफ्टवेयर मुद्दों को लंबे रास्तों के लिए लापता समर्थन के साथ देखता हूं (यहां तक ​​कि टीएफएस 2013 विफल रहता है यदि आप लंबाई में 259 से आगे जाते हैं ...)। लेकिन हां। भविष्य में ऐसा कुछ हो सकता है (उदाहरण के लिए अगर इस पोस्ट को बहुत सारे वोट मिले :))।
वोल्फ 5

यह समाधान मेरे लिए काम करता है, लेकिन में InternalGetDirectories कार्य करते है, प्रत्यावर्तन काम करता है, तो ऐसा नहीं करता AllDirectories विकल्प चुना जाता है और खोज पैटर्न उपनिर्देशिका सूची में नहीं पाया जाता है। मुझे लाइन को ThrowWin32Exception () को बदलना पड़ा ; एक तरह से द्वारा (लंबी यहाँ शामिल होने के लिए करने के लिए कोड है, लेकिन बहुत समान करने के लिए "*" के साथ पहले से खोज पैटर्न के रूप में कर समारोह में कोड)।
एलेक्स

कोशिश की ZetaLongPaths nuget / github परियोजना, फ़ाइलों को कॉपी करना किसी कारण से भ्रष्ट फ़ाइलों का उत्पादन कर रहा था, अब यह कोशिश कर रहा है। मुझे लगता है कि यह इन पिनवोक पैटर्न का भी उपयोग करता है, लेकिन आप कभी नहीं जानते हैं!
fartwhif

इस महोदय के लिए धन्यवाद, लेकिन सिर्फ FYI करें, यदि लक्ष्य पथ सापेक्ष है (".. \ Fu \ Bar.txt") तो यह काम नहीं करेगा। मैंने इसे पूर्ण मार्ग के रूप में मजबूर करके अपनी ओर से तय किया।
टीपक्स

22

आप Delimon पुस्तकालय, इसके .NET .NET 4 आधारित पुस्तकालय को Microsoft TechNet पर लंबे फ़ाइल नाम की समस्या पर काबू पाने के लिए आज़मा सकते हैं:

Delimon.Win32.I हे पुस्तकालय (V4.0)।

यह System.IO से प्रमुख विधियों के अपने संस्करण हैं। उदाहरण के लिए, आप प्रतिस्थापित करेंगे:

System.IO.Directory.GetFiles

साथ में

Delimon.Win32.IO.Directory.GetFiles

जो आपको लंबी फ़ाइलों और फ़ोल्डरों को संभालने देगा।

वेबसाइट से:

Delimon.Win32.IO System.IO की मूल फ़ाइल फ़ंक्शन को प्रतिस्थापित करता है और 32,767 वर्णों तक फ़ाइल और फ़ोल्डर नामों का समर्थन करता है।

यह लाइब्रेरी .NET फ्रेमवर्क 4.0 पर लिखी गई है और इसे x86 & x64 सिस्टम पर उपयोग किया जा सकता है। मानक System.IO नाम स्थान की फ़ाइल और फ़ोल्डर सीमाएँ उन फ़ाइलों के साथ काम कर सकती हैं, जिनमें फ़ाइल नाम में 260 वर्ण और फ़ोल्डर नाम में 240 वर्ण हैं (MAX_PATH आमतौर पर 260 वर्णों के रूप में कॉन्फ़िगर किया गया है)। आमतौर पर आप मानक .NET लाइब्रेरी के साथ System.IO.PathTooLongException त्रुटि में चलते हैं।


4
260 वर्णों से अधिक के रास्तों के लिए अल्फ़ाज़ लाइब्रेरी भी है ।
मार्क जी


5

मैं एक आवेदन के साथ एक बार इस समस्या में भाग गया था जो मैं लिख रहा था। जब मैं 260 चरित्र की सीमा से टकराने के करीब हो रहा था, तो मैं पूर्ण पथ के कुछ सेगमेंट के लिए, मक्खी पर, नेटवर्क ड्राइव का नक्शा तैयार करूंगा, इस प्रकार पूर्ण पथ + फ़ाइल-नाम की लंबाई में काफी कमी आ जाएगी। यह वास्तव में एक सुरुचिपूर्ण समाधान नहीं है, लेकिन इसे काम मिल गया है।


3

एक साझा फ़ोल्डर (\\ ServerName \ PathThatIsVeryLong \) के लिए, हम "\\? \ UNC \ ServerName \ PathThatIsVeryLong \" का उपयोग कर सकते हैं, जहां "ServerName" कंप्यूटर का नाम है और "PathThatIsVeryLong" साझा फ़ोल्डर का नाम है। ।

संदर्भ: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN


2

GetFileAttributesEx के लिए MSDN संदर्भ का कहना है:

इस फ़ंक्शन के ANSI संस्करण में, नाम MAX_PATH वर्णों तक सीमित है। इस सीमा को 32,767 विस्तृत वर्णों तक विस्तारित करने के लिए, फ़ंक्शन के यूनिकोड संस्करण को कॉल करें और पथ में "\\? \" को प्रीपेन्ड करें। अधिक जानकारी के लिए, एक फ़ाइल का नामकरण देखें ।

तो आप GetFileAttributesExW का उपयोग करना चाहते हैं और "\\? \" के साथ अपना रास्ता उपसर्ग करें?


आपका उद्धरण सही है लेकिन थोड़ा भ्रामक है: इस सीमा का ANSI संस्करण से कोई लेना-देना नहीं है (यह यूनिकोड संस्करण में भी सीमित है)।
user541686

1
यह बहुत स्पष्ट रूप से बताता है कि सीमा का विस्तार करने के लिए आपको यूनिकोड संस्करण और उपसर्ग दोनों का उपयोग करने की आवश्यकता है।
lunixbochs

2

कृपया अपनी कॉन्फिग फाइल को इस तरह अपडेट करें:

<configuration>
  <runtime>
    <AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false;Switch.System.IO.BlockLongPaths=false" />
  </runtime>
</configuration>

0

रोबोकॉपी का उपयोग करने वाली एक अलग प्रक्रिया बनाना भी चर्चा के रूप में एक समाधान है: पथ नाम के साथ फ़ोल्डर / फाइलें कैसे स्थानांतरित करें> विंडोज 8.1 में 255 वर्ण?

  public static void RoboCopy(string src, string dst)
        {
            Process p = new Process();
            p.StartInfo.Arguments = string.Format("/C Robocopy {0} {1}", src, dst);
            p.StartInfo.FileName = "CMD.EXE";
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.UseShellExecute = false;
            p.Start();
            p.WaitForExit();
        }

जैसा कि देखा गया है: रब्बो कॉपी और प्रक्रिया का उपयोग करके फाइल कॉपी

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.