Steven
Steven

Reputation: 13975

c# could not get part of file path error

I'm attempting to recursively copy all files and directories and here is my class code. I am getting could not find part of path. I'm going to assume it may be because there is about 20 sub directories to directories (paths like \game\resour.zip\shared\effects\materials\ and such.) Any help would be appreciated.

    static IEnumerable<string> GetFiles(string path)
    {
        Queue<string> queue = new Queue<string>();
        queue.Enqueue(path);
        while (queue.Count > 0)
        {
            path = queue.Dequeue();
            try
            {
                foreach (string subDir in Directory.GetDirectories(path))
                {
                    queue.Enqueue(subDir);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            string[] files = null;
            try
            {
                files = Directory.GetFiles(path);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            if (files != null)
            {
                for (int i = 0; i < files.Length; i++)
                {
                    yield return files[i];
                }
            }
        }
    }

Upvotes: 2

Views: 8363

Answers (3)

user152949
user152949

Reputation:

In .NET the full path to a file can not be longer than 260 characters, if you wan't to use longer paths you must call the Win API directly using UNC paths and your file paths can be 32,767 characters long, I have added a .NET class that does this, I did not write this code originally but sadly I did not find the original article when looking for it today so I will just enter my modified code here for demonstration purposes, the code is slightly altered from the original code and has some extra functionalty.

/* 
All sample code is provided by the Inge Henriksen for illustrative purposes only. These examples have not been thoroughly tested under all conditions. Inge Henriksen, therefore, cannot guarantee or imply reliability, serviceability, or function of these programs.
 */
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.IO;
using log4net;

namespace MyStuff.DAL.Services.IO.File
{
    /// <summary>
    /// Class for communicating with the Windows kernel library for low-level disk access.
    /// The main purpose of this class is to allow for longer file paths than System.IO.File,
    /// this class handles file paths up to 32,767 characters. 
    /// Note: Always be careful when accessing this class from a managed multi-threaded application
    /// as the unmanaged Windows kernel is different, this "crash" causes application unstability 
    /// if not handled properly.
    /// TODO: Look into if there are any significant gains on 64-bit systems using another kind of 
    /// core component than kernel32.dll.
    /// </summary>
    public class Win32File
    {
        ILog Log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        #region DLLImport's
        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        static extern bool MoveFile(string lpExistingFileName, string lpNewFileName);

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

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

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

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        static extern uint SetFilePointer(SafeFileHandle hFile, long lDistanceToMove, IntPtr lpDistanceToMoveHigh, uint dwMoveMethod);

        #endregion

        // uint GetMode( FileMode mode )
        // Converts the filemode constant to win32 constant
        #region GetMode
        private uint GetMode(FileMode mode)
        {
            Log.Debug("Get Win32 file mode");
            uint umode = 0;
            switch (mode)
            {
                case FileMode.CreateNew:
                    umode = Win32FileAttributes.CREATE_NEW;
                    break;
                case FileMode.Create:
                    umode = Win32FileAttributes.CREATE_ALWAYS;
                    break;
                case FileMode.Append:
                    umode = Win32FileAttributes.OPEN_ALWAYS;
                    break;
                case FileMode.Open:
                    umode = Win32FileAttributes.OPEN_EXISTING;
                    break;
                case FileMode.OpenOrCreate:
                    umode = Win32FileAttributes.OPEN_ALWAYS;
                    break;
                case FileMode.Truncate:
                    umode = Win32FileAttributes.TRUNCATE_EXISTING;
                    break;
            }
            return umode;
        }
        #endregion

        // uint GetAccess(FileAccess access)
        // Converts the FileAccess constant to win32 constant
        #region GetAccess
        private uint GetAccess(FileAccess access)
        {
            Log.Debug("Get Win32 file access");
            uint uaccess = 0;
            switch (access)
            {
                case FileAccess.Read:
                    uaccess = Win32FileAttributes.GENERIC_READ;
                    break;
                case FileAccess.ReadWrite:
                    uaccess = Win32FileAttributes.GENERIC_READ | Win32FileAttributes.GENERIC_WRITE;
                    break;
                case FileAccess.Write:
                    uaccess = Win32FileAttributes.GENERIC_WRITE;
                    break;
            }
            return uaccess;
        }
        #endregion

        // uint GetShare(FileShare share)
        // Converts the FileShare constant to win32 constant
        #region GetShare
        private uint GetShare(FileShare share)
        {
            Log.Debug("Get Win32 file share");
            uint ushare = 0;
            switch (share)
            {
                case FileShare.Read:
                    ushare = Win32FileAttributes.FILE_SHARE_READ;
                    break;
                case FileShare.ReadWrite:
                    ushare = Win32FileAttributes.FILE_SHARE_READ | Win32FileAttributes.FILE_SHARE_WRITE;
                    break;
                case FileShare.Write:
                    ushare = Win32FileAttributes.FILE_SHARE_WRITE;
                    break;
                case FileShare.Delete:
                    ushare = Win32FileAttributes.FILE_SHARE_DELETE;
                    break;
                case FileShare.None:
                    ushare = 0;
                    break;

            }
            return ushare;
        }
        #endregion

        public bool Move(string existingFile, string newFile)
        {
            Log.Debug(String.Format("Rename the file \"{0}\" to \"{1}\"", existingFile, newFile) );
            return Win32File.MoveFile(existingFile, newFile);
        }

        public bool CreateDirectory(string filepath)
        {
            Log.Debug(String.Format("Create the directory \"{0}\"", filepath));
            // If file path is disk file path then prepend it with \\?\
            // if file path is UNC prepend it with \\?\UNC\ and remove \\ prefix in unc path.
            if (filepath.StartsWith(@"\\"))
                filepath = @"\\?\UNC\" + filepath.Substring(2, filepath.Length - 2);
            else
                filepath = @"\\?\" + filepath;
            return CreateDirectoryW(filepath, IntPtr.Zero);
        }

        public FileStream Open(string filepath, FileMode mode, uint uaccess)
        {
            Log.Debug(String.Format("Open the file \"{0}\"", filepath));

            //opened in the specified mode and path, with read/write access and not shared
            FileStream fs = null;
            uint umode = GetMode(mode);
            uint ushare = 0;    // Not shared
            if (mode == FileMode.Append) uaccess = Win32FileAttributes.FILE_APPEND_DATA;

            // If file path is disk file path then prepend it with \\?\
            // if file path is UNC prepend it with \\?\UNC\ and remove \\ prefix in unc path.
            if (filepath.StartsWith(@"\\"))
                filepath = @"\\?\UNC\" + filepath.Substring(2, filepath.Length - 2);
            else filepath = @"\\?\" + filepath;

            SafeFileHandle sh = CreateFileW(filepath, uaccess, ushare, IntPtr.Zero, umode, Win32FileAttributes.FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
            int iError = Marshal.GetLastWin32Error();
            if ((iError > 0 && !(mode == FileMode.Append && iError == Win32FileAttributes.ERROR_ALREADY_EXISTS)) || sh.IsInvalid)
            {
                Log.Error(String.Format("Error opening file; Win32 Error: {0}", iError));
                throw new Exception("Error opening file; Win32 Error:" + iError);
            }
            else
            {
                fs = new FileStream(sh, FileAccess.ReadWrite);
            }

            // if opened in append mode
            if (mode == FileMode.Append)
            {
                if (!sh.IsInvalid)
                {
                    SetFilePointer(sh, 0, IntPtr.Zero, Win32FileAttributes.FILE_END);
                }
            }

            Log.Debug(String.Format("The file \"{0}\" is now open", filepath));
            return fs;
        }

        public FileStream Open(string filepath, FileMode mode, FileAccess access)
        {
            Log.Debug(String.Format("Open the file \"{0}\"", filepath));

            //opened in the specified mode and access and not shared
            FileStream fs = null;
            uint umode = GetMode(mode);
            uint uaccess = GetAccess(access);
            uint ushare = 0;    // Exclusive lock of the file

            if (mode == FileMode.Append) uaccess = Win32FileAttributes.FILE_APPEND_DATA;

            // If file path is disk file path then prepend it with \\?\
            // if file path is UNC prepend it with \\?\UNC\ and remove \\ prefix in unc path.
            if (filepath.StartsWith(@"\\"))
                filepath = @"\\?\UNC\" + filepath.Substring(2, filepath.Length - 2);
            else
                filepath = @"\\?\" + filepath;

            SafeFileHandle sh = CreateFileW(filepath, uaccess, ushare, IntPtr.Zero, umode, Win32FileAttributes.FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
            int iError = Marshal.GetLastWin32Error();
            if ((iError > 0 && !(mode == FileMode.Append && iError != Win32FileAttributes.ERROR_ALREADY_EXISTS)) || sh.IsInvalid)
            {
                Log.Error(String.Format("Error opening file; Win32 Error: {0}", iError));
                throw new Exception("Error opening file; Win32 Error:" + iError);
            }
            else
            {
                fs = new FileStream(sh, access);
            }

            // if opened in append mode
            if (mode == FileMode.Append)
            {
                if (!sh.IsInvalid)
                {
                    SetFilePointer(sh, 0, IntPtr.Zero, Win32FileAttributes.FILE_END);
                }
            }

            Log.Debug(String.Format("The file \"{0}\" is now open", filepath));
            return fs;
        }

        public FileStream Open(string filepath, FileMode mode, FileAccess access, FileShare share)
        {
            //opened in the specified mode , access and  share
            FileStream fs = null;
            uint umode = GetMode(mode);
            uint uaccess = GetAccess(access);
            uint ushare = GetShare(share);
            if (mode == FileMode.Append) uaccess = Win32FileAttributes.FILE_APPEND_DATA;

            // If file path is disk file path then prepend it with \\?\
            // if file path is UNC prepend it with \\?\UNC\ and remove \\ prefix in unc path.
            if (filepath.StartsWith(@"\\"))
                filepath = @"\\?\UNC\" + filepath.Substring(2, filepath.Length - 2);
            else
                filepath = @"\\?\" + filepath;
            SafeFileHandle sh = CreateFileW(filepath, uaccess, ushare, IntPtr.Zero, umode, Win32FileAttributes.FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
            int iError = Marshal.GetLastWin32Error();
            if ((iError > 0 && !(mode == FileMode.Append && iError != Win32FileAttributes.ERROR_ALREADY_EXISTS)) || sh.IsInvalid)
            {
                throw new Exception("Error opening file Win32 Error:" + iError);
            }
            else
            {
                fs = new FileStream(sh, access);
            }
            // if opened in append mode
            if (mode == FileMode.Append)
            {
                if (!sh.IsInvalid)
                {
                    SetFilePointer(sh, 0, IntPtr.Zero, Win32FileAttributes.FILE_END);
                }
            }
            return fs;
        }

        public FileStream OpenRead(string filepath)
        {
            Log.Debug(String.Format("Open the file \"{0}\"", filepath));
            // Open readonly file mode open(String, FileMode.Open, FileAccess.Read, FileShare.Read)
            return Open(filepath, FileMode.Open, FileAccess.Read, FileShare.Read);
        }

        public FileStream OpenWrite(string filepath)
        {
            Log.Debug(String.Format("Open the file \"{0}\" for writing", filepath));
            //open writable open(String, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None).
            return Open(filepath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
        }

        public bool Delete(string filepath)
        {
            Log.Debug(String.Format("Delete the file \"{0}\"", filepath));
            // If file path is disk file path then prepend it with \\?\
            // if file path is UNC prepend it with \\?\UNC\ and remove \\ prefix in unc path.
            if (filepath.StartsWith(@"\\"))
                filepath = @"\\?\UNC\" + filepath.Substring(2, filepath.Length - 2);
            else
                filepath = @"\\?\" + filepath;
            Log.Debug(String.Format("The file \"{0}\" has been deleted", filepath));
            return DeleteFile(filepath);
        }
    }
}

Upvotes: 3

AaronLS
AaronLS

Reputation: 38367

Not sure if this will be of assistance:

/// <summary>
/// Operates just like GetFileSystemInfos except it is recursive, operates on more than
/// one FileSystemInfo, ensures no paths are duplicateed, and includes the original
/// items in the return.
/// </summary>
/// <param name="files">A collection of files and/or directories to expand.</param>
/// <returns>A Dictionary of all file, directories, and subfiles and subdirectories of 
/// those directories and subdirectories.  The key is the fullpath, and the value
/// is the FileSystemInfo.</returns>
public static Dictionary<string, FileSystemInfo> ExpandFileSystemInfos(FileSystemInfo[] files)
{
  Dictionary<string, FileSystemInfo> resultingFiles = new Dictionary<string,FileSystemInfo>();

  //GetFileSystemInfosRecursively will expand everything, except it may contain duplicates
  foreach (FileSystemInfo file in GetFileSystemInfosRecursively(files))
  {//so we just go through adding them to the Dictionary
    if (!resultingFiles.ContainsKey(file.FullName))
    {
      resultingFiles.Add(file.FullName, file);
    }
  }
  return resultingFiles;
}

//helper method for ExpandFileSystemInfos
private static List<FileSystemInfo> GetFileSystemInfosRecursively(FileSystemInfo[] files)
{
  List<FileSystemInfo> resultingFiles = new List<FileSystemInfo>();
  foreach (FileSystemInfo file in files)
  {
    if (file is DirectoryInfo)
    {
      //get its sub items and pass to another function to process
      DirectoryInfo dir = (DirectoryInfo)file;

      //recursive call, passing in subdirectories and files of current directory.  
      //The result returned will be all subdirectories and files nested within the current
      //dir.  So we add them to our collection of results for each directory we encounter.
      resultingFiles.AddRange(GetFileSystemInfosRecursively(dir.GetFileSystemInfos()));          
    }
    //else do nothing, it is a file we already know about
  }
  //resultingFiles now contains all sub items
  //It does not include the directories and files in files however, so we add them as well
  resultingFiles.AddRange(files);

  return resultingFiles;
}

I used this with a program where the user could choose multiple directories or files to be compressed. I had to handle the case where they explicitely added a directory, and then added a subdirectory/subfile(pointlessly) of that directory. So I wrote this so that you could pass in multiple directory and files in an array, and as it expands them out it will make sure none are duplicated.

Upvotes: 0

Arsen Mkrtchyan
Arsen Mkrtchyan

Reputation: 50712

to copy recursively use this method

static public void CopyFolder( string sourceFolder, string destFolder )
{
     if (!Directory.Exists( destFolder ))
     Directory.CreateDirectory( destFolder );
     string[] files = Directory.GetFiles( sourceFolder );
     foreach (string file in files)
     {
        string name = Path.GetFileName( file );
        string dest = Path.Combine( destFolder, name );
        File.Copy( file, dest );
     }
     string[] folders = Directory.GetDirectories( sourceFolder );
     foreach (string folder in folders)
     {
         string name = Path.GetFileName( folder );
         string dest = Path.Combine( destFolder, name );
         CopyFolder( folder, dest );
   }

}

Upvotes: 2

Related Questions