The Windows OS does not allow a path to be more than 248 characters long. So what if your directories and file names are too long and they are nested. Then eventually you'll not be able to access/create the file /directory in it. How can they be created and how they can be accessed programmatically?
Recently I was facing that problem; I need to search a deep level of nested directories. I have tried System.IO.Directory.GetFiles() method and then suddenly it throws an error that "Couldn't read the part of path" or "Invalid path". Then somehow I managed to find the solution and now I am sharing it with you guys.
Windows provides the API to handle the longer files and directories paths. Using this API we can access the path longer than 248 chars. To use the path which is longer we need to add a prefix "\\?\" in the path. This informs the API that it's a long path and the Windows API will support up to 32767 bytes for long paths with this.
So you need to specify it using the CharSet.Unicode as an attribute of an internal static extern type method of System library function.
For Example:
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)] internal static extern IntPtr FindFirstFile(string lpFileName, out LongPathHandler.InteropVar.WIN32_FIND_DATA lpFindFileData);
Recently I was facing that problem; I need to search a deep level of nested directories. I have tried System.IO.Directory.GetFiles() method and then suddenly it throws an error that "Couldn't read the part of path" or "Invalid path". Then somehow I managed to find the solution and now I am sharing it with you guys.
Windows provides the API to handle the longer files and directories paths. Using this API we can access the path longer than 248 chars. To use the path which is longer we need to add a prefix "\\?\" in the path. This informs the API that it's a long path and the Windows API will support up to 32767 bytes for long paths with this.
So you need to specify it using the CharSet.Unicode as an attribute of an internal static extern type method of System library function.
For Example:
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)] internal static extern IntPtr FindFirstFile(string lpFileName, out LongPathHandler.InteropVar.WIN32_FIND_DATA lpFindFileData);
Here is the code to access the files and directories:
using System;using System.Collections.Generic;using System.IO;using System.Runtime.InteropServices;using Microsoft.Win32.SafeHandles;namespace LongPathHandler
{
public class CustomDir {
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
internal static extern IntPtr FindFirstFile(string lpFileName, out LongPathHandler.InteropVar.WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
internal static extern bool FindNextFile(IntPtr hFindFile, out LongPathHandler.InteropVar.WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool FindClose(IntPtr hFindFile);
/// <summary> /// Return all the dirctories and files /// Assumed dirName passed in is already prefixed with file:///?/ /// </summary> /// <param name="dirName">Directory that need to be searched</param> /// <returns></returns> public static List<string> FindFilesAndDirs(string dirName)
{
List<string> results = new List<string>();
LongPathHandler.InteropVar.WIN32_FIND_DATA findData;
IntPtr findHandle = FindFirstFile(dirName + @"\*", out findData);
if (findHandle != LongPathHandler.InteropVar.INVALID_HANDLE_VALUE)
{
bool found;
do {
string currentFileName = findData.cFileName;
// if this is a directory, find its contents if (((int)findData.dwFileAttributes & LongPathHandler.InteropVar.FILE_ATTRIBUTE_DIRECTORY) != 0)
{
if (currentFileName != "." && currentFileName != "..")
{
List<string> childResults = FindFilesAndDirs(Path.Combine(dirName, currentFileName));
// add children and self to results results.AddRange(childResults);
results.Add(Path.Combine(dirName, currentFileName)); }
else // it's a file; add it to the results {
results.Add(Path.Combine(dirName, currentFileName));
}
// find next found = FindNextFile(findHandle, out findData);
}
while (found);
}
// close the find handle FindClose(findHandle);
return results;
}
}
}
{
public class CustomDir {
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
internal static extern IntPtr FindFirstFile(string lpFileName, out LongPathHandler.InteropVar.WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
internal static extern bool FindNextFile(IntPtr hFindFile, out LongPathHandler.InteropVar.WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool FindClose(IntPtr hFindFile);
/// <summary> /// Return all the dirctories and files /// Assumed dirName passed in is already prefixed with file:///?/ /// </summary> /// <param name="dirName">Directory that need to be searched</param> /// <returns></returns> public static List<string> FindFilesAndDirs(string dirName)
{
List<string> results = new List<string>();
LongPathHandler.InteropVar.WIN32_FIND_DATA findData;
IntPtr findHandle = FindFirstFile(dirName + @"\*", out findData);
if (findHandle != LongPathHandler.InteropVar.INVALID_HANDLE_VALUE)
{
bool found;
do {
string currentFileName = findData.cFileName;
// if this is a directory, find its contents if (((int)findData.dwFileAttributes & LongPathHandler.InteropVar.FILE_ATTRIBUTE_DIRECTORY) != 0)
{
if (currentFileName != "." && currentFileName != "..")
{
List<string> childResults = FindFilesAndDirs(Path.Combine(dirName, currentFileName));
// add children and self to results results.AddRange(childResults);
results.Add(Path.Combine(dirName, currentFileName)); }
else // it's a file; add it to the results {
results.Add(Path.Combine(dirName, currentFileName));
}
// find next found = FindNextFile(findHandle, out findData);
}
while (found);
}
// close the find handle FindClose(findHandle);
return results;
}
}
}
Another class is that used in the above code is:
using System;using System.Collections.Generic;
using System.Linq;using System.Text;using System.IO;using System.Runtime.InteropServices;namespace LongPathHandler
{
class InteropVar {
internal static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
internal static int FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
internal const int MAX_PATH = 260;
[StructLayout(LayoutKind.Sequential)]
internal struct FILETIME {
internal uint dwLowDateTime;
internal uint dwHighDateTime;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct WIN32_FIND_DATA {
internal FileAttributes dwFileAttributes;
internal FILETIME ftCreationTime;
internal FILETIME ftLastAccessTime;
internal FILETIME ftLastWriteTime;
internal int nFileSizeHigh;
internal int nFileSizeLow;
internal int dwReserved0;
internal int dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
internal string cFileName;
// not using this
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
internal string cAlternate;
}
[Flags]
public enum EFileAccess : uint
{
GenericRead = 0x80000000,
GenericWrite = 0x40000000,
GenericExecute = 0x20000000,
GenericAll = 0x10000000,
}
[Flags]
public enum EFileShare : uint {
None = 0x00000000,
Read = 0x00000001,
Write = 0x00000002,
Delete = 0x00000004,
}
public enum ECreationDisposition : uint
{
New = 1,
CreateAlways = 2,
OpenExisting = 3,
OpenAlways = 4,
TruncateExisting = 5,
}
[Flags]
public enum EFileAttributes : uint {
Readonly = 0x00000001,
Hidden = 0x00000002,
System = 0x00000004,
Directory = 0x00000010,
Archive = 0x00000020,
Device = 0x00000040,
Normal = 0x00000080,
Temporary = 0x00000100,
SparseFile = 0x00000200,
ReparsePoint = 0x00000400,
Compressed = 0x00000800,
Offline = 0x00001000,
NotContentIndexed = 0x00002000,
Encrypted = 0x00004000,
Write_Through = 0x80000000,
Overlapped = 0x40000000,
NoBuffering = 0x20000000,
RandomAccess = 0x10000000,
SequentialScan = 0x08000000,
DeleteOnClose = 0x04000000,
BackupSemantics = 0x02000000,
PosixSemantics = 0x01000000,
OpenReparsePoint = 0x00200000,
OpenNoRecall = 0x00100000,
FirstPipeInstance = 0x00080000
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES {
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
}
}
using System.Linq;using System.Text;using System.IO;using System.Runtime.InteropServices;namespace LongPathHandler
{
class InteropVar {
internal static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
internal static int FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
internal const int MAX_PATH = 260;
[StructLayout(LayoutKind.Sequential)]
internal struct FILETIME {
internal uint dwLowDateTime;
internal uint dwHighDateTime;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct WIN32_FIND_DATA {
internal FileAttributes dwFileAttributes;
internal FILETIME ftCreationTime;
internal FILETIME ftLastAccessTime;
internal FILETIME ftLastWriteTime;
internal int nFileSizeHigh;
internal int nFileSizeLow;
internal int dwReserved0;
internal int dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
internal string cFileName;
// not using this
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
internal string cAlternate;
}
[Flags]
public enum EFileAccess : uint
{
GenericRead = 0x80000000,
GenericWrite = 0x40000000,
GenericExecute = 0x20000000,
GenericAll = 0x10000000,
}
[Flags]
public enum EFileShare : uint {
None = 0x00000000,
Read = 0x00000001,
Write = 0x00000002,
Delete = 0x00000004,
}
public enum ECreationDisposition : uint
{
New = 1,
CreateAlways = 2,
OpenExisting = 3,
OpenAlways = 4,
TruncateExisting = 5,
}
[Flags]
public enum EFileAttributes : uint {
Readonly = 0x00000001,
Hidden = 0x00000002,
System = 0x00000004,
Directory = 0x00000010,
Archive = 0x00000020,
Device = 0x00000040,
Normal = 0x00000080,
Temporary = 0x00000100,
SparseFile = 0x00000200,
ReparsePoint = 0x00000400,
Compressed = 0x00000800,
Offline = 0x00001000,
NotContentIndexed = 0x00002000,
Encrypted = 0x00004000,
Write_Through = 0x80000000,
Overlapped = 0x40000000,
NoBuffering = 0x20000000,
RandomAccess = 0x10000000,
SequentialScan = 0x08000000,
DeleteOnClose = 0x04000000,
BackupSemantics = 0x02000000,
PosixSemantics = 0x01000000,
OpenReparsePoint = 0x00200000,
OpenNoRecall = 0x00100000,
FirstPipeInstance = 0x00080000
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES {
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
}
}
Now just create these classes in your project and call the method FindFilesAndDirs() of the CustomDir class.
For Example:
List<String> ls = CustomDir.FindFilesAndDirs(@"\\?\" + rootPath);
For Example:
List<String> ls = CustomDir.FindFilesAndDirs(@"\\?\" + rootPath);
Note: The result will contain this prefix "\\?\" so you need to explicitly remove it if you want to get rid of an error "Invalid symbols in path". Now search the deepest path in your Windows pc using C# a program. Microsoft has released a support library code for handling the long paths but it's for .Net Version 4.0. But this code can be used with most all versions of the Framework.
Thanks.
Thanks.
great.......
ReplyDeleteThid is one of the best
Thanks :)
ReplyDeletecan you send me the link to Microsoft library for use in .NET version 4.0
ReplyDeleteRe: "Microsoft has released a support library code for handling the long paths but it's for .Net Version 4.0."
ReplyDeleteBy any chance you have the link? I couldn't find it myself...:-(
TIA
Uhm, sorry, I found it on CodePlex:
ReplyDeletehttp://bcl.codeplex.com/releases/view/42783
Sorry for late reply yes.. code plex have this open source project for .net 4.0. its good you find it yourself and thanks for sharing it here.. :)
ReplyDeleteI just want to Process.Star(@"\?\\"+), but i get an error.
ReplyDeleteHow do i do that?
What error are you getting? Give details i'll try to help
ReplyDeleteI get an Exception of FileNotFound. System could not find: "\\\\?\\S:\\longfilepath\\longfilename.txt"
ReplyDeleteI think i'm not grasping the concept well enough. I made a console aplication that opens a file with a very long path. The path is passed as an arg.
I'm not really sure what i have to do. File handling is a bit of an unexplored area to me...
Here's the code i came up with:
ReplyDelete[code]
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace ConsoleApplication1
{
class Program
{
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool abreFicheiro(string lpFileName, bool bFailIfExists);
static void Main(string[] args) {
string caminho = fixPathForLong(@"S:\longfilepath\longfilename.txt");
abreFicheiro(caminho);
}
public static bool abreFicheiro(string caminho) {
Process.Start(caminho);
if (!abreFicheiro(caminho, false))
{
throw new Win32Exception();
}
return true;
}
private static string fixPathForLong(String path)
{
if (!path.StartsWith(@"\\?\"))
path = @"\\?\" + path;
return path;
}
}
}
[/code]
your code looks ok.. I guess you need to make sure that path you are using to pointing that particular file is correct because the error is not for Long path its actually can not find the file specified. Make sure filename and path is correct.
ReplyDeleteYou're absolutely right!
ReplyDeleteDon't know how i missed such a trivial thing...
Thankyou for your invaluable help!
I am a complete beginner. Can you please explain "enum EFileAttributes" and the constant values being assigned to it. ALso, what is meant by "[Flags]" notation above it. Thank you.
ReplyDeleteHi,
ReplyDeleteFor a good solution, take a look at AlphaFS.dll
Site: https://alphafs.codeplex.com/