5

i am trying to use the various file functions in C# like File.GetLastWriteTime, copy command on the file placed at the path greater than maximum allowed path on windows 7 i.e 260. Its giving me an error on long path name. On MSDN support i they have asked to use the \\?\ before the path. I did the same but still i got the same error, it seems it doesn't make any change. Below is my code. Please let me know if i am using it correct or i need to add any thing:
These all lib i am using as the code is having other things also:

the below is the respective code:

filesToBeCopied = Directory.GetFiles(path,"*",SearchOption.AllDirectories);
for (int j = 0; j < filesToBeCopied.Length; j++)
{
    try
    {
        String filepath = @"\\?\" + filesToBeCopied[j];
        File.GetLastWriteTime(filepath);
    }
    catch (Exception ex)
    {
        MessageBox.Show("Error Inside the single file iteration for the path:" +
            filesToBeCopied[j] + " . The exception is :" + ex.Message);
    }
}

where as path is the path to the folder at windows machine starting with drive letter. for ex.: d:\abc\bcd\cd\cdc\dc\..........

Torbjörn Kalin
  • 1,976
  • 1
  • 22
  • 31
nishant jain
  • 51
  • 1
  • 1
  • 4
  • 1
    What does the path look like that is causing the error? Can you paste it here? – Robert Harvey Aug 30 '12 at 19:37
  • Here is the path: `D:\abcdefghi_abc\abcdefghis abcd abcdef company1\abcdefghis abcd abcdef company\project abcde\Do Not Delete - EP120605003\002 Image prep\Societe Generale (Open Access) - Returned 18 May 2012 (UL 30 May)\004 OCR\001 Ocr Working\003 Partition Files\4F33DBE75836ACFA95BE3B14B7BEFE5E.split` – nishant jain Aug 30 '12 at 19:42
  • 2
    .Net doesn't support long paths, you have to directly call the APIs with P/Invoke or shorten the paths. http://blogs.msdn.com/b/bclteam/archive/2007/02/13/long-paths-in-net-part-1-of-3-kim-hamilton.aspx – Todd Li Aug 30 '12 at 19:45
  • Yux, please post that as an answer so we can upvote you! – Winfield Trail Aug 30 '12 at 19:46
  • ye, but the below link says if we add \\?\ before the path it take it well. http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx#maximum%5Fpath%5Flength – nishant jain Aug 30 '12 at 19:46
  • 1
    That link describes behavior of the WIN32 native api, .Net does it own validation – rene Aug 30 '12 at 19:56
  • @rene thank you for explaining that. I read through the MSDN article without realizing that it wasn't in the .NET section and was confused as to why it didn't work with any of the .NET code. – Jon Senchyna Aug 30 '12 at 20:32
  • @sudowned *cough* that link was in my post... – Killnine Aug 30 '12 at 20:39
  • So should we assume rather than using native methods or PInvoke there is no other way out to solve this? – nishant jain Aug 30 '12 at 20:47
  • @Killnine, at the time Yuxiu commented there were no answers to the question. – Winfield Trail Aug 30 '12 at 23:53
  • @sudowned Yeah, I put together the timeline after I made the comment. Sorry ;P – Killnine Aug 31 '12 at 01:22
  • @Killnine, it's alright. Though in general, that sort of comment is just going to come across as fightey - I try just to roll with it. Answers get scooped all the time, but in the long run the site (and the world) still benefits from the answers. And I'm saying that as a mega-argumentative person. ;) – Winfield Trail Aug 31 '12 at 01:33
  • @sudowned *tumbleweed rolls by this thread* – Killnine Aug 31 '12 at 01:38
  • My own and other answers [here](http://stackoverflow.com/a/29605805/589059) suggest some wrapper libraries you can use for dealing with long paths. – rkagerer Apr 13 '15 at 13:35

4 Answers4

7

Here's a solution for at least the copying portion of your request (thank you pinvoke.net):

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

And then to actually copy your file:

// Don't forget the '\\?\' for long paths
string reallyLongPath = @"\\?\d:\abc\bcd\cd\cdc\dc\..........";
string destination = @"C:\some\other\path\filename.txt";
CopyFile(reallyLongPath , destination, false);
Jon Senchyna
  • 7,867
  • 2
  • 26
  • 46
3

As far as I know, you can't access a file directly if its path is too long (by directly, I mean using the methods of File, by creating a FileInfo via the constructor, or by using Directory.GetFiles(string fileName).

The only way I've found that will let you access such a file is to access a directory somewhere in the path before it gets too long, and then programatically walk down the tree until you get to your file, as seen here.

I've taken my code from there and modified it a little to return a FileInfo object for a file with a path that is "too long". Using this code, you can access the necessary properties on the returned FileInfo object (like LastWriteTime). It still has some limitations though, like the inability to use functions like CopyTo() or OpenText().

// Only call GetFileWithLongPath() if the path is too long
// ... otherwise, new FileInfo() is sufficient
private static FileInfo GetFile(string path)
{
    if (path.Length >= MAX_FILE_PATH)
    {
        return GetFileWithLongPath(path);
    }
    else return new FileInfo(path);
}

static int MAX_FILE_PATH = 260;
static int MAX_DIR_PATH = 248;

private static FileInfo GetFileWithLongPath(string path)
{
    string[] subpaths = path.Split('\\');
    StringBuilder sbNewPath = new StringBuilder(subpaths[0]);
    // Build longest sub-path that is less than MAX_PATH characters 
    for (int i = 1; i < subpaths.Length; i++)
    {
        if (sbNewPath.Length + subpaths[i].Length >= MAX_DIR_PATH)
        {
            subpaths = subpaths.Skip(i).ToArray();
            break;
        }
        sbNewPath.Append("\\" + subpaths[i]);
    }
    DirectoryInfo dir = new DirectoryInfo(sbNewPath.ToString());
    bool foundMatch = dir.Exists;
    if (foundMatch)
    {
        // Make sure that all of the subdirectories in our path exist. 
        // Skip the last entry in subpaths, since it is our filename. 
        // If we try to specify the path in dir.GetDirectories(),  
        // We get a max path length error. 
        int i = 0;
        while (i < subpaths.Length - 1 && foundMatch)
        {
            foundMatch = false;
            foreach (DirectoryInfo subDir in dir.GetDirectories())
            {
                if (subDir.Name == subpaths[i])
                {
                    // Move on to the next subDirectory 
                    dir = subDir;
                    foundMatch = true;
                    break;
                }
            }
            i++;
        }
        if (foundMatch)
        {
            // Now that we've gone through all of the subpaths, see if our file exists. 
            // Once again, If we try to specify the path in dir.GetFiles(),  
            // we get a max path length error. 
            foreach (FileInfo fi in dir.GetFiles())
            {
                if (fi.Name == subpaths[subpaths.Length - 1])
                {
                    return fi;
                }
            }
        }
    }
    // If we didn't find a match, return null;
    return null;
}

Now that you've seen that, go rinse your eyes and shorten your paths.

Community
  • 1
  • 1
Jon Senchyna
  • 7,867
  • 2
  • 26
  • 46
  • thanks jon, but my problem is not limited to filewritetime only, i have to use all other functions like copy delete and create equivalent directory as its a data backup code ..... – nishant jain Aug 30 '12 at 20:18
1

try with this code

var path = Path.Combine(@"\\?\", filesToBeCopied[j]); //don't forget extension

"\?\" prefix to a path string tells the Windows APIs to disable all string parsing and to send the string that follows it straight to the file system.

Important : Not all file I/O APIs support "\?\", you should look at the reference topic for each API

Jon Senchyna
  • 7,867
  • 2
  • 26
  • 46
Aghilas Yakoub
  • 28,516
  • 5
  • 46
  • 51
  • hi, the upper code is not even combining the path as i displayed the path after combining in a message box and it showed me the original path. – nishant jain Aug 30 '12 at 20:10
  • Has anyone gotten that to work? Using .NET 4.0 and Windows 7, I can't get that to work with either the `File`, `FileInfo`, `Directory`, or `DirectoryInfo` classes. – Jon Senchyna Aug 30 '12 at 20:13
  • AFAIK, IlSpy tells me that an private class called PathHelper in System.IO no matter what always throws if the path is longer then 260 chars. – rene Aug 31 '12 at 07:03
-1

http://www.codinghorror.com/blog/2006/11/filesystem-paths-how-long-is-too-long.html

I recently imported some source code for a customer that exceeded the maximum path limit of 256 characters.

The path you pasted was 285 characters long.

As you noted in your comment, MSDN's link here (http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx#maximum%5Fpath%5Flength) explains this length in greater detail:

In the Windows API (with some exceptions discussed in the following paragraphs), the maximum length for a path is MAX_PATH, which is defined as 260 characters. A local path is structured in the following order: drive letter, colon, backslash, name components separated by backslashes, and a terminating null character. For example, the maximum path on drive D is "D:\some 256-character path string" where "" represents the invisible terminating null character for the current system codepage. (The characters < > are used here for visual clarity and cannot be part of a valid path string.)

With respect to the \\?\ functionality:

Many but not all file I/O APIs support "\?\"; you should look at the reference topic for each API to be sure.

Killnine
  • 5,728
  • 8
  • 39
  • 66
  • thanks for the reply, but can you please tell me if there is any easy solution or workaround to do it as at this point of time i cant change the application to use the pinvoke – nishant jain Aug 30 '12 at 20:12
  • Just did a basic SO search: http://stackoverflow.com/questions/1190614/accessing-files-beyond-max-path-in-c-net The selected answer link ( http://blogs.msdn.com/b/bclteam/archive/2007/02/13/long-paths-in-net-part-1-of-3-kim-hamilton.aspx ) might offer some solutions, but obviously I can't promise anything. "your mileage may vary" – Killnine Aug 30 '12 at 20:16