ZipFile解压高权限目录抛System.UnauthorizedAccessException求助
解压高权限文件夹时的权限异常解决方案
尝试将文件解压到C:\ProgramData\Tecan这类高权限目录时,持续触发UnauthorizedAccessException,目标是无需批量修改每台计算机的外部权限即可解决问题。
异常信息
System.Exception: Error transferring files ---> System.Exception: Error unzipping C:\TransferFiles\ZipFolder.zip to C:\ProgramData\Tecan ---> System.UnauthorizedAccessException: Access to the path C:\ProgramData\Tecan\SVNRoot\SystemSW_1.0\format is denied. at Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options) at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable1 unixCreateMode) at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable1 unixCreateMode) at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode) at System.IO.FileStream..ctor(String path, FileStreamOptions options) at System.IO.Compression.ZipFileExtensions.ExtractToFile(ZipArchiveEntry source, String destinationFileName, Boolean overwrite) at System.IO.Compression.ZipFileExtensions.ExtractRelativeToDirectory(ZipArchiveEntry source, String destinationDirectoryName, Boolean overwrite) at System.IO.Compression.ZipFileExtensions.ExtractToDirectory(ZipArchive source, String destinationDirectoryName, Boolean overwriteFiles) at System.IO.Compression.ZipFile.ExtractToDirectory(String sourceArchiveFileName, String destinationDirectoryName, Encoding entryNameEncoding, Boolean overwriteFiles)
已尝试操作
- 以管理员身份运行Visual Studio Code及程序,解决了其他权限问题,但未解决本次解压异常
- 怀疑无扩展名文件导致,但此类文件可正常解压到低权限目录
- 尝试通过C#代码修改目标目录的访问规则和所有者:
修改目录访问规则代码
DirectoryInfo directoryInfo = new DirectoryInfo(destination); DirectorySecurity directorySecurity = directoryInfo.GetAccessControl(); FileSystemAccessRule fileSystemAccessRule = new FileSystemAccessRule ( new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null), FileSystemRights.FullControl, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.InheritOnly, AccessControlType.Allow ); directorySecurity.AddAccessRule(fileSystemAccessRule); directoryInfo.SetAccessControl(directorySecurity);
修改目录所有者代码
DirectoryInfo directoryInfo = new DirectoryInfo(destination); DirectorySecurity directorySecurity = directoryInfo.GetAccessControl(); var owner = directorySecurity.GetOwner(typeof(NTAccount)); var newOwner = new NTAccount(WindowsIdentity.GetCurrent().Name); directorySecurity.SetOwner(newOwner); directoryInfo.SetAccessControl(directorySecurity);
可行解决方案
1. 先解压到临时目录再移动文件
先将ZIP包解压到用户权限可读写的临时目录(如C:\Users\[当前用户]\AppData\Local\Temp),再以管理员权限将文件移动到目标高权限目录。移动操作的权限检查逻辑与直接解压不同,更容易绕过目录权限限制。
示例代码:
string tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); ZipFile.ExtractToDirectory("C:\\TransferFiles\\ZipFolder.zip", tempDir); // 递归移动所有文件到目标目录 foreach (var file in Directory.GetFiles(tempDir, "*", SearchOption.AllDirectories)) { string relativePath = Path.GetRelativePath(tempDir, file); string destPath = Path.Combine("C:\\ProgramData\\Tecan", relativePath); // 创建目标父目录(如果不存在) Directory.CreateDirectory(Path.GetDirectoryName(destPath)); // 覆盖已存在的文件 File.Move(file, destPath, overwrite: true); } // 清理临时目录 Directory.Delete(tempDir, recursive: true);
2. 使用Windows Shell API执行文件操作
Windows的SHFileOperation或IFileOperationAPI原生支持权限提升逻辑,比.NET自带的文件操作更适配Windows权限模型。通过P/Invoke调用SHFileOperation实现文件复制:
示例代码:
using System.Runtime.InteropServices; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct SHFILEOPSTRUCT { public IntPtr hwnd; public uint wFunc; public string pFrom; public string pTo; public ushort fFlags; public bool fAnyOperationsAborted; public IntPtr hNameMappings; public string lpszProgressTitle; } [DllImport("shell32.dll", CharSet = CharSet.Unicode)] public static extern int SHFileOperation(ref SHFILEOPSTRUCT lpFileOp); // 使用示例 string tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); ZipFile.ExtractToDirectory("C:\\TransferFiles\\ZipFolder.zip", tempDir); var fileOp = new SHFILEOPSTRUCT { wFunc = 0x0002, // FO_COPY:执行复制操作 pFrom = tempDir + "\0\0", // 路径需以双NULL结尾 pTo = "C:\\ProgramData\\Tecan\0\0", fFlags = 0x0040 | 0x0008 // FOF_NOCONFIRMATION(不弹出确认框)| FOF_SILENT(静默执行) }; SHFileOperation(ref fileOp); // 清理临时目录 Directory.Delete(tempDir, recursive: true);
3. 逐个解压并手动设置文件权限
放弃使用ZipFile.ExtractToDirectory的批量解压,改为逐个处理ZIP条目,在创建文件/目录后立即为当前用户添加全控制权限,避免继承目标目录的受限权限。
示例代码:
using (var archive = ZipFile.OpenRead("C:\\TransferFiles\\ZipFolder.zip")) { foreach (var entry in archive.Entries) { string destPath = Path.Combine("C:\\ProgramData\\Tecan", entry.FullName); if (entry.FullName.EndsWith("/")) { // 处理目录 Directory.CreateDirectory(destPath); var dirInfo = new DirectoryInfo(destPath); var dirSec = dirInfo.GetAccessControl(); // 为当前用户添加全控制权限 dirSec.AddAccessRule(new FileSystemAccessRule( WindowsIdentity.GetCurrent().User, FileSystemRights.FullControl, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow)); dirInfo.SetAccessControl(dirSec); } else { // 处理文件 Directory.CreateDirectory(Path.GetDirectoryName(destPath)); // 写入文件 using (var fs = new FileStream(destPath, FileMode.Create, FileAccess.Write, FileShare.None)) using (var entryStream = entry.Open()) { entryStream.CopyTo(fs); } // 为当前用户添加文件全控制权限 var fileInfo = new FileInfo(destPath); var fileSec = fileInfo.GetAccessControl(); fileSec.AddAccessRule(new FileSystemAccessRule( WindowsIdentity.GetCurrent().User, FileSystemRights.FullControl, AccessControlType.Allow)); fileInfo.SetAccessControl(fileSec); } } }
内容的提问来源于stack exchange,提问作者Ricardo Noyola Lozano
相关产品推荐
相关产品推荐

