音乐、图片和视频库中的文件和文件夹

将音乐、图片或视频的现有文件夹添加到相应的库。 还可以从库中删除文件夹、获取库中的文件夹列表,以及发现存储的照片、音乐和视频。

库是文件夹的虚拟集合,默认情况下包括已知文件夹,以及用户通过使用应用或内置应用添加到库的任何其他文件夹。 例如,“图片”库默认包含“图片”已知文件夹。 用户可以使用应用或内置照片应用向图片库添加文件夹或将其从中删除。

先决条件

  • 了解通用 Windows 平台(UWP)应用的异步编程

    了解如何在 C# 或 Visual Basic 中编写异步应用,请参阅 在 C# 或 Visual Basic 中调用异步 API。 若要了解如何在C++中编写异步应用,请参阅C++中的 异步编程。

  • 对位置 的访问权限

    在 Visual Studio 中,在清单设计器中打开应用清单文件。 在 功能 页上,选择应用管理的库。

    • 音乐库
    • 图片库
    • 视频资料库

    若要了解详细信息,请参阅 文件访问权限

获取对软件库的引用

注释

请记住声明适当的权限。 有关详细信息,请参阅 应用功能声明。  

若要获取对用户的音乐、图片或视频库的引用,请调用 StorageLibrary.GetLibraryAsync 方法。 提供 KnownLibraryId 枚举中的相应值。

var myPictures = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Pictures);

获取库中的文件夹列表

若要获取库中的文件夹列表,请获取 StorageLibrary.Folders 属性的值。

using Windows.Foundation.Collections;
IObservableVector<Windows.Storage.StorageFolder> myPictureFolders = myPictures.Folders;

获取库中默认保存新文件的文件夹

若要获取默认情况下保存新文件的库中的文件夹,请获取 StorageLibrary.SaveFolder 属性的值。

Windows.Storage.StorageFolder savePicturesFolder = myPictures.SaveFolder;

将现有文件夹添加到库

若要将文件夹添加到库,请调用 StorageLibrary.RequestAddFolderAsync。 以图片库为例,调用此方法会显示一个文件夹选择器,并带有一个将此文件夹添加到图片库中的按钮。 如果用户选取一个文件夹,则该文件夹将保留在磁盘上的原始位置,并且它将成为 StorageLibrary.Folders 属性(以及内置照片应用中)中的项,但文件夹不会显示为文件资源管理器中“图片”文件夹的子文件夹。

Windows.Storage.StorageFolder newFolder = await myPictures.RequestAddFolderAsync();

从库中删除文件夹

若要从库中删除文件夹,请调用 StorageLibrary.RequestRemoveFolderAsync 方法并指定要删除的文件夹。 可以使用 StorageLibrary.FoldersListView 控件(或类似)供用户选择要删除的文件夹。

调用 StorageLibrary.RequestRemoveFolderAsync时,用户会看到一个确认对话框,指出该文件夹“不再显示在图片中,但不会被删除”。这意味着,文件夹保留在磁盘上的原始位置,从 StorageLibrary.Folders 属性中删除,并且不再包含在内置照片应用中。

以下示例假定用户已选择要从名为 lvPictureFoldersListView 控件中删除的文件夹。

bool result = await myPictures.RequestRemoveFolderAsync(folder);

获取对库中文件夹列表的更改的通知

若要获取有关库中文件夹列表更改的通知,请为库的 StorageLibrary.DefinitionChanged 事件注册一个处理程序。

myPictures.DefinitionChanged += MyPictures_DefinitionChanged;

void HandleDefinitionChanged(Windows.Storage.StorageLibrary sender, object args)
{
    // ...
}

媒体库文件夹

设备为用户和应用提供五个预定义的位置来存储媒体文件。 内置应用将用户创建的媒体和下载的媒体存储在这些位置。

位置为:

  • 图片 文件夹。 包含图片。

    • 相册 文件夹。 包含内置相机的照片和视频。

    • 图片收藏夹 文件夹。 包含用户从其他应用保存的图片。

  • 音乐 文件夹。 包含歌曲、播客和音频书籍。

  • 视频 文件夹。 包含视频。

用户或应用还可以将媒体文件存储在 SD 卡上的媒体库文件夹之外。 若要在 SD 卡上可靠地查找媒体文件,请扫描 SD 卡的内容,或者要求用户使用文件选取器查找文件。 有关详细信息,请参阅 访问 SD 卡

查询媒体库

若要获取文件的集合,请指定库和所需的文件类型。

using Windows.Storage;
using Windows.Storage.Search;

private async void getSongs()
{
    QueryOptions queryOption = new QueryOptions
        (CommonFileQuery.OrderByTitle, new string[] { ".mp3", ".mp4", ".wma" });

    queryOption.FolderDepth = FolderDepth.Deep;

    Queue<IStorageFolder> folders = new Queue<IStorageFolder>();

    var files = await KnownFolders.MusicLibrary.CreateFileQueryWithOptions
      (queryOption).GetFilesAsync();

    foreach (var file in files)
    {
        // do something with the music files
    }
}

查询结果包括内部和可移动存储

默认情况下,用户可以选择将文件存储在可选的 SD 卡上。 但是,应用可以选择退出允许将文件存储在 SD 卡上。 因此,媒体库可以跨设备的内部存储和 SD 卡进行拆分。

无需编写其他代码来处理这种可能性。 Windows.Storage 命名空间中查询已知文件夹的方法以透明方式合并这两个位置的查询结果。 无需在应用清单文件中指定 removableStorage 功能即可获取这些组合结果。

请考虑下图中显示的设备存储的状态:

手机和 sd 卡上的图像

如果通过调用 await KnownFolders.PicturesLibrary.GetFilesAsync()查询图片库的内容,则结果包括 internalPic.jpg 和 SDPic.jpg。

处理照片

在相机保存低分辨率图像和每个图片的高分辨率图像的设备上,深度查询仅返回低分辨率图像。

相机滚动和已保存的图片文件夹不支持深度查询。

在捕获照片的应用中打开照片

如果您想让用户以后在拍摄照片的应用中再次打开这张照片,可以使用类似以下示例的代码,将 CreatorAppId 保存到照片的元数据中。 在此示例中,testPhoto 是一个 存储文件

IDictionary<string, object> propertiesToSave = new Dictionary<string, object>();

propertiesToSave.Add("System.CreatorOpenWithUIOptions", 1);
propertiesToSave.Add("System.CreatorAppId", appId);

testPhoto.Properties.SavePropertiesAsync(propertiesToSave).AsyncWait();   

使用流方法将文件添加到媒体库

使用已知文件夹(如 KnownFolders.PictureLibrary)访问媒体库时,使用流方法将文件添加到媒体库时,必须确保关闭代码打开的所有流。 否则,由于至少有一个流仍然持有文件的句柄,这些方法未能按预期将文件添加到媒体库。

例如,运行以下代码时,不会将文件添加到媒体库。 在代码行 using (var destinationStream = (await destinationFile.OpenAsync(FileAccessMode.ReadWrite)).GetOutputStreamAt(0))中,OpenAsync 方法和 GetOutputStreamAt 方法都用于打开一个流。 但是,只有由 using 语句打开的流才会因 GetOutputStreamAt 方法而被释放。 另一个流保持打开状态,并阻止保存文件。

StorageFolder testFolder = await StorageFolder.GetFolderFromPathAsync(@"C:\test");
StorageFile sourceFile = await testFolder.GetFileAsync("TestImage.jpg");
StorageFile destinationFile = await KnownFolders.CameraRoll.CreateFileAsync("MyTestImage.jpg");
using (var sourceStream = (await sourceFile.OpenReadAsync()).GetInputStreamAt(0))
{
    using (var destinationStream = (await destinationFile.OpenAsync(FileAccessMode.ReadWrite)).GetOutputStreamAt(0))
    {
        await RandomAccessStream.CopyAndCloseAsync(sourceStream, destinationStream);
    }
}

若要成功使用流方法将文件添加到媒体库,请确保关闭代码打开的所有流,如以下示例所示。

StorageFolder testFolder = await StorageFolder.GetFolderFromPathAsync(@"C:\test");
StorageFile sourceFile = await testFolder.GetFileAsync("TestImage.jpg");
StorageFile destinationFile = await KnownFolders.CameraRoll.CreateFileAsync("MyTestImage.jpg");

using (var sourceStream = await sourceFile.OpenReadAsync())
{
    using (var sourceInputStream = sourceStream.GetInputStreamAt(0))
    {
        using (var destinationStream = await destinationFile.OpenAsync(FileAccessMode.ReadWrite))
        {
            using (var destinationOutputStream = destinationStream.GetOutputStreamAt(0))
            {
                await RandomAccessStream.CopyAndCloseAsync(sourceInputStream, destinationStream);
            }
        }
    }
}