获取文件路径的正确方式是什么?

15

我在已知文件夹.视频库中有两个同名的文件,因此无法通过其名称访问该文件,因此只会返回第一个文件。那么除了解析文件夹中的所有文件之外,是否还有其他方法可以获取文件?

// this return two files 
var files = (await KnownFolders.VideosLibrary.GetFilesAsync()).Where(x => x.Name == "test.txt").ToArray();
// with this I can get only one file
StorageFile file = await KnownFolders.VideosLibrary.GetFileAsync("test.txt");
// of course I can parse it with query, but I would like to avoid it
// StorageFile myFile = (await KnownFolders.VideosLibrary.GetFilesAsync()).FirstOrDefault(x => x.FolderRelativeId == "something");

我知道FutureAccessList,但它只能容纳1000个文件,对我来说不够。


根据请求提供一些澄清:

例如,假设应用程序在带有SD卡的手机上运行。 我有一个名为test.txt的文件位于手机存储器中的视频文件夹中,同名文件也存在于视频文件夹中的SD卡上。

在这种情况下,当您调用上面的第一行代码时,您将获得两个文件,为了区分它们,系统提供了FolderRelativeId,因此相同名称的文件可以存在于一个“位置”中。 如果您查看每个文件夹的完整路径,其中一个文件夹可能会有C:\ Viedos \ test.txt,而第二个文件夹则为D:\ Videos \ test.txt

现在在第一次运行时,用户使用FilePicker选择了一个文件,并且我记住了它的路径,例如D:\ Videos \ test.txt。 在应用程序的第二次运行中,我希望通过使用其路径(或其他方法,除了有限的FutureAccessList)访问此文件。 在过去,我通常会通过StorageFile.GetFileFromPathAsync(path);来执行此操作 - 但似乎它在W10中开始抛出UnauthorizedAccessException异常。


为什么不使用循环来处理文件列表中的每个文件?files变量的类型是什么?另外一个问题是,如何可能存在两个同名的文件? - Tomasz Pikć
@TomaszPikć 如果我知道文件路径,但仍需要使用循环,则会影响性能。想象一下,当我有一个包含1000个文件的目录并且需要执行少量文件操作时。至于第二件事-库是虚拟位置,很容易出现相同的文件-例如,在手机存储器和SD卡上的视频中可能具有相同的名称,然后在VideosLibrary中它们将具有相同的名称,但具有不同的relativefolderid。 - Romasz
因此,有没有其他方法可以获取文件而不是解析文件夹中的所有文件呢?- 你已经回答了自己的问题。StorageFolder.GetFileAsync将返回您正在搜索的文件。如果这不是您要寻找的内容,请更具体地说明您的问题。 - Herdo
@Herdo 我已经编辑了这个问题以提供更多的澄清。如果您需要更多信息,请告诉我。 - Romasz
你的代码将返回所有具有给定名称的文件。除非您知道有关文件的其他信息,例如路径、创建日期、大小或其他信息,否则我不认为您可以做任何其他操作,除了对它们进行迭代。 - Tony Vitabile
@TonyVitabile 我知道文件的确切路径,例如 C:\Videos\test.txt,但是假设我不能假定它属于 VideosLibrary。现在 GetFileFromPathAsync() 抛出异常 - 所以我正在寻找其他方法。此外 - 我可以知道文件的所有信息,因为它已经被第一次选择了。现在在应用程序的第二次运行中,我希望能够访问该文件,而不需要再次提示用户。 - Romasz
4个回答

2
你可以通过以下方式获取 IStorageFile 实例。
// If your have a StorageFile objece file then 
//fileUri = new Uri(file.Path);

string uri = fileUri.LocalPath;
int end = uri.LastIndexOf('\\');
uri = uri.Substring(0, end + 1);

string name = Path.GetFileName(fileUri.LocalPath);
var folder = await StorageFolder.GetFolderFromPathAsync(uri);
IStorageFile file = await folder.GetFileAsync(name);
// Do something with file object

我有一些疑问,不知道它是否能够工作 - 因为同样的原因 - 用户权限。 - Romasz

0

我猜可以通过理性思考来解释在调用StorageFile.GetFileFromPathAsync(path)时抛出的UnauthorizedAccessException,因为你的应用程序无法访问根驱动器字母,所以不允许以这种方式导航文件夹结构。但这只是一个猜测。

至于你的问题,为什么你不能做到这一点呢?

var file = (await KnownFolders.VideosLibrary.GetFilesAsync()).FirstOrDefault(x => x.Path == "D:\Videos\test.txt");

其中D:\Videos\test.txt是您从用户使用选择器选择的文件中获取的.Path属性值。

当VideosLibrary上有数百万个文件时,您可能会发现它运行速度稍慢。


似乎你提出的方法与我在问题代码中注释掉的方法相同。我想避免解析文件夹。顺便说一下,在8.1中是可能的,但似乎在UWP中由于安全原因已经改变了。 - Romasz

0
根据微软的this文档,应用程序可以选择不允许文件存储在SD卡上。因此,媒体库可以分布在设备的内部存储和SD卡上。
如果我理解正确,您的解决方案将是:
  • 退出上述功能
  • 现在只应在本地设备上搜索,而不是在SD卡上搜索
    • 这将导致每个目录中有唯一的文件名
  • 如果您的用例需要在SD卡上搜索文件,现在必须访问SD卡并查询此处的文件
我不确定,如果单独访问SD卡的编码开销是否值得通过仅查询本地存储获得的性能提升。

我无法选择不拆分库,因为这不取决于我 - 用户决定在哪里存储文件。此外,我已经了解到您选择搜索文件,而我想避免这种情况,因为我已经通过路径知道文件的存在位置。问题是 StorageFile.GetFileFromPathAsync(path) 似乎不再起作用。 - Romasz

0

当您在Windows 8.1应用程序中使用文件选择器打开文件时(我假设Windows 10的工作方式相同),您将获得该文件夹的权限令牌,该令牌持续一段时间,或直到您退出应用程序。当您重新打开应用程序时,您必须重新获取文件夹的令牌。

阅读有关StorageApplicationPermissions对象的文章。


问题在于如何重新获取该令牌。在W/WP8.1中,可以通过StorageFile.GetFileFromPath来实现,在W10中会抛出异常。因此,我正在寻找其他可能性。 - Romasz
它会抛出什么异常? - The Sharp Ninja
你说得对@Romasz,在Windows 10中,即使是从8.1应用程序中,这种行为也发生了变化。我想我们需要深入挖掘一下。 - The Sharp Ninja
你可以在退出应用程序之前记住文件。使用StorageApplicationPermissions.MostRecentlyUsedList.Add(storageFile)获取它的字符串令牌。稍后,您可以使用StorageApplicationPermissions.MostRecentlyUsedList.GetFileAsync(stringToken)将文件取回。将令牌放入LocalSettings中。请注意,MostRecentlyUsedList中可以保存的文件数量有限,因此如果您一遍又一遍地执行此操作,则必须清除列表。 - sjb-sjb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接