c# 无法获取部分文件路径错误

标签 c#

我正在尝试递归复制所有文件和目录,这是我的类代码。我找不到部分路径。我假设这可能是因为目录中有大约 20 个子目录(路径如\game\resour.zip\shared\effects\materials\等。)任何帮助将不胜感激。

    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];
                }
            }
        }
    }

最佳答案

在 .NET 中,文件的完整路径不能超过 260 个字符,如果您不想使用更长的路径,则必须使用 UNC 路径直接调用 Win API,并且文件路径的长度可以是 32,767 个字符,我添加了一个执行此操作的 .NET 类,我最初没有编写此代码,但遗憾的是我今天查找时没有找到原始文章,因此我将在此处输入修改后的代码以进行演示,该代码稍有改动原始代码并具有一些额外的功能。

/* 
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);
        }
    }
}

关于c# 无法获取部分文件路径错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1248597/

相关文章:

c# - 从 double 转换为十进制时避免 OverflowException

c# - 有没有办法在2.0中执行C#4.0可选参数?

c# - 一区多格

c# - 服务器上的 System.InvalidCastException

c# - 带有 Firebird 的 NHibernate ...是否启用了这些功能?

c# - 如何创建 IOptions<MyOption> 的模拟实例?

c# - List<T> Sort 是否修改集合?

c# - 获取表达式树中方法参数的值

c# - 为什么 DataTable 是可序列化的?

c# - 调用异步函数的结果是否会导致无限期阻塞?