You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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设备能力声明:

  1. 打开Package.appxmanifest,切换到XML视图,添加以下内容:
<Capabilities>
    <DeviceCapability Name="usb">
        <Device Id="vidpid:XXXX XXXX"> <!-- 替换成你的设备VID和PID,或者用"any"匹配所有设备 -->
            <Function Type="classId:08 * *" />
        </Device>
    </DeviceCapability>
</Capabilities>
  1. 然后用以下代码访问设备:
// 获取所有便携存储设备的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 09:32:31