UWP读取便携设备文件触发Access Denied异常,求替代方案
解决UWP中读取便携设备文件时的权限拒绝问题
嘿,我之前做UWP项目时也踩过这个权限的坑,明明权限都加了,还是报E_ACCESSDENIED,给你梳理下问题原因和可行的替代方案:
为什么你的代码会报错?
虽然你给应用配置了权限,但UWP对KnownFolders.RemovableDevices的访问有严格限制:它只允许访问应用在Package.appxmanifest中声明过的文件类型。如果你的代码尝试读取未声明的文件类型,就会触发权限拒绝异常。
替代方案
方案1:用文件/文件夹选择器让用户授权(最稳妥)
UWP的安全模型更倾向于用户主动授权,通过FileOpenPicker或FolderPicker让用户手动选择要访问的文件/文件夹,这样应用就能获得对应内容的访问权限,而且不受文件类型限制。
示例代码:
// 选择多个文件 var filePicker = new FileOpenPicker(); filePicker.FileTypeFilter.Add("*"); // 允许所有类型,也可以指定具体后缀比如".txt" filePicker.SuggestedStartLocation = PickerLocationId.RemovableDevices; var selectedFiles = await filePicker.PickMultipleFilesAsync(); foreach (var file in selectedFiles) { System.Diagnostics.Debug.WriteLine($"选中文件:{file.Name}"); // 这里可以执行复制到PC的操作 } // 如果需要访问整个文件夹(包括子文件夹) var folderPicker = new FolderPicker(); folderPicker.FileTypeFilter.Add("*"); folderPicker.SuggestedStartLocation = PickerLocationId.RemovableDevices; var selectedFolder = await folderPicker.PickSingleFolderAsync(); if (selectedFolder != null) { // 把文件夹添加到FutureAccessList,下次启动应用可以直接访问,不用重新选择 Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.Add(selectedFolder); // 递归遍历文件夹内的所有文件 await TraverseFolder(selectedFolder); } // 递归遍历文件夹的辅助方法 async Task TraverseFolder(StorageFolder folder) { var files = await folder.GetFilesAsync(); foreach (var file in files) { System.Diagnostics.Debug.WriteLine($"文件:{file.Name}"); // 执行复制操作,比如复制到本地文件夹 await file.CopyAsync(Windows.Storage.ApplicationData.Current.LocalFolder, file.Name, NameCollisionOption.ReplaceExisting); } var subFolders = await folder.GetFoldersAsync(); foreach (var subFolder in subFolders) { await TraverseFolder(subFolder); } }
方案2:使用Windows.Devices.Portable.StorageDevice API
这个API是专门针对便携存储设备设计的,需要在清单中添加USB设备能力声明:
- 打开Package.appxmanifest,切换到XML视图,添加以下内容:
<Capabilities> <DeviceCapability Name="usb"> <Device Id="vidpid:XXXX XXXX"> <!-- 替换成你的设备VID和PID,或者用"any"匹配所有设备 --> <Function Type="classId:08 * *" /> </Device> </DeviceCapability> </Capabilities>
- 然后用以下代码访问设备:
// 获取所有便携存储设备的ID列表 var deviceIds = await Windows.Devices.Portable.StorageDevice.GetDevicesAsync(); foreach (var deviceId in deviceIds) { try { // 通过设备ID获取根文件夹 StorageDevice rootDevice = await Windows.Devices.Portable.StorageDevice.FromIdAsync(deviceId); if (rootDevice != null) { StorageFolder rootFolder = rootDevice.RootFolder; // 同样可以用上面的TraverseFolder方法遍历文件 await TraverseFolder(rootFolder); } } catch (UnauthorizedAccessException ex) { System.Diagnostics.Debug.WriteLine($"权限拒绝:{ex.Message}"); // 这里可能需要提示用户授权,或者检查设备能力声明是否正确 } }
额外注意事项
如果坚持用KnownFolders.RemovableDevices,需要在Package.appxmanifest中添加对应文件类型的关联,比如:
<Extensions> <uap:Extension Category="windows.fileTypeAssociation"> <uap:FileTypeAssociation Name="myfiles"> <uap:SupportedFileTypes> <uap:FileType>.txt</uap:FileType> <uap:FileType>.jpg</uap:FileType> <!-- 添加你需要访问的所有文件类型 --> </uap:SupportedFileTypes> </uap:FileTypeAssociation> </uap:Extension> </Extensions>
但这种方法只能访问声明过的文件类型,灵活性不如用户授权的方式。
内容的提问来源于stack exchange,提问作者Aasish
相关产品推荐
相关产品推荐

