异步和LINQ查询:检索目录树中所有文件中的所有行



我正在努力维护一些UWP代码。它的目标是将保存在目录结构中的一些明文文件合并为一个XML文件。

为了做到这一点,我之前使用LINQ:获取目录结构中所有文件中的所有不同行

Imports System.IO
Async Function getAllLines() As IEnumerable(Of String)
Dim _folderPicker As New Windows.Storage.Pickers.FolderPicker()
_folderPicker.FileTypeFilter.Add("*") 'We must add this; it is a known bug
Dim _rootDir As Windows.Storage.StorageFolder = Await _folderPicker.PickSingleFolderAsync()
Dim allDistinctLines As IEnumerable(Of String) = From _file In Directory.GetFiles(_rootDir.Name, "*.txt", SearchOption.AllDirectories) From line In File.ReadAllLines(_file) Where line.Trim().Length > 0 Select line.Trim() Distinct
Return allDistinctLines
End Function

然而,自10月下旬以来,文件权限方面似乎发生了一些变化(来源(。大约一个月后,我回到代码中,发现它抛出了一个异常,说我以前可以写入的文件夹由于权限原因无法访问。文件夹是存在的,我从一个拾取器中抓取了文件夹,所以我觉得我很好。以前,只要我使用选择器获取了文件或文件夹,我仍然可以使用System.IO函数来枚举、读取或写入所述文件夹或目录。

现在,似乎你必须通过适当的UWP功能,这很好,但我不确定如何重写我的LINQ查询,因为UWP方法是异步的。

以下是我尝试过的:

Async Function getAllLines() As IEnumerable(Of String)
Dim _folderPicker As New Windows.Storage.Pickers.FolderPicker()
_folderPicker.FileTypeFilter.Add("*") 'We must add this; it is a known bug
Dim _rootDir As Windows.Storage.StorageFolder = Await _folderPicker.PickSingleFolderAsync()
Dim queryOptions As New Windows.Storage.Search.QueryOptions()
queryOptions.FileTypeFilter.Add(".txt")
queryOptions.FolderDepth = Windows.Storage.Search.FolderDepth.Deep
Dim allDistinctLines As IEnumerable(Of String) = From _file In Await _rootDir.CreateFileQueryWithOptions(queryOptions).GetFilesAsync() From line In Await Windows.Storage.FileIO.ReadLinesAsync(_file) Where line.Trim().Length > 0 Select line.Trim() Distinct
Return allDistinctLines
End Function

在上面的代码中,如果我在LINQ中注释掉第二个等待,我至少可以枚举文件夹。问题是,使用LINQ查询中的第二个Await,我无法编译为

'Await' may only be used in a query expression within the first collection expression of the initial 'From' clause or within the collection expression of a 'Join' clause.

所以我读了Join子句,它们似乎等同于不同的数据,而这并不是我真正想要的。

我读到了这个错误的一般情况,看起来LINQ查询和异步函数的功能有限。老实说,我对LINQ的了解还不足以真正做出这样的声明,但这就是我的感受。

我找到了这个答案,它使用Task.WWhenAll((来促进LINQ和异步函数的使用,但我无法准确地理解它将如何付诸实践。

如何在Linq查询中等待方法

所以我尝试了:

Async Function getAllLines() As IEnumerable(Of String)
Dim _folderPicker As New Windows.Storage.Pickers.FolderPicker()
_folderPicker.FileTypeFilter.Add("*") 'We must add this; it is a known bug
Dim _rootDir As Windows.Storage.StorageFolder = Await _folderPicker.PickSingleFolderAsync()
Dim queryOptions As New Windows.Storage.Search.QueryOptions()
queryOptions.FileTypeFilter.Add(".txt")
queryOptions.FolderDepth = Windows.Storage.Search.FolderDepth.Deep
Dim allFiles As IEnumerable(Of Windows.Storage.StorageFile) = From _file In Await _rootDir.CreateFileQueryWithOptions(queryOptions).GetFilesAsync() Select _file
Dim allDistinctLines As IEnumerable(Of String) = Task.WhenAll(allFiles.Select(Function(_file) Windows.Storage.FileIO.ReadLines.Async(_file).Where(Function(_line) _line.Trim().Length > 0).Distinct()))
Return allDistinctLines
End Function

但是返回类型不一样,它最终是一些奇怪的IList(Of String(((,这对我来说并不奇怪。也许这只是一个严重的误解。

无论如何,我们将为您提供任何有关异步文件操作的帮助!

正如Stephen在本线程中所说,LINQ对async/await的支持非常有限。我建议您将For EachWindows.Storageapi结合使用,如下所示:

Async Function getAllLines() As Task(Of IEnumerable(Of String))
Dim _folderPicker As New Windows.Storage.Pickers.FolderPicker()
_folderPicker.FileTypeFilter.Add("*") 'We must add this; it is a known bug
Dim _rootDir As Windows.Storage.StorageFolder = Await _folderPicker.PickSingleFolderAsync()
Dim queryOptions As New Windows.Storage.Search.QueryOptions()
queryOptions.FileTypeFilter.Add(".txt")
queryOptions.FolderDepth = Windows.Storage.Search.FolderDepth.Deep
Dim allDistinctLines As New List(Of String)
For Each file As StorageFile In Await _rootDir.CreateFileQueryWithOptions(queryOptions).GetFilesAsync()
For Each line In Await Windows.Storage.FileIO.ReadLinesAsync(file)
If line.Trim().Length > 0 Then
allDistinctLines.Add(line.Trim())
End If
Next
Next
Return allDistinctLines.Distinct()
End Function

最新更新