如何在应用程序启动时异步读取文件? [英] How do I read a file asynchronously at application start-up?

查看:161
本文介绍了如何在应用程序启动时异步读取文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对 FileStream.ReadAsync()有一个奇怪的问题。我调用一个函数,从我的主应用程序 OnStartup()的流中执行异步读取。当我异步读取时,应用程序不会显示其主窗口。如果我只是将读取更改为同步版本,则应用程序启动。



这是我的 OnStartup()覆盖:



I have a strange problem with FileStream.ReadAsync(). I call a function that performs an asynchronous read from a stream from my main application OnStartup(). When I read asynchronously, the application doesn't ever display its main window. If I simply change the read to a synchronous version, the application starts up.

This is my OnStartup() override:

protected override async void OnStartup( StartupEventArgs e )
{
	base.OnStartup( e );
	Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
	LogsEmailer logsEmailer = new LogsEmailer();
	string testString = await logsEmailer.TestReadFileAsync( Path.Combine( logsFolder, "TestFile.txt" ) );
	StartupUri = new Uri( "./View/MainWindow.xaml", UriKind.Relative );
}





应用程序永远不会启动此功能:





The application never starts with this function:

public async Task<string> TestReadFileAsync( string filePath )
{
	using( FileStream sourceStream = File.OpenRead( filePath ) )
	{
		byte[] copyBuffer = new byte[ 4096 ];
		bool doneCopying = false;
		while( !doneCopying )
		{
			int numSourceBytes = await sourceStream.ReadAsync( copyBuffer, 0, copyBuffer.Length );
			if( numSourceBytes == 0 )
				doneCopying = true;
		}
	}
	return "test string";
}





但它确实从这开始:





But it does start with this:

public async Task<string> TestReadFileAsync( string filePath )
{
	using( FileStream sourceStream = File.OpenRead( filePath ) )
	{
		byte[] copyBuffer = new byte[ 4096 ];
		bool doneCopying = false;
		while( !doneCopying )
		{
			int numSourceBytes = sourceStream.Read( copyBuffer, 0, copyBuffer.Length );
			if( numSourceBytes == 0 )
				doneCopying = true;
		}
	}
	return "test string";
}





显然,我确实收到第二段代码的警告,表示它会同步完成。当我说第二个版本有效时,我的意思是它只允许应用程序启动;我无法使用它,因为我尝试执行的操作需要很长时间才能在 OnStartup()中同步完成。



我想我在这里错过了一些愚蠢的东西。谁能告诉我什么?



我尝试过的事情:



我在上面提到的II,我尝试从流读取中删除异步并且应用程序启动正常。



我刚刚发现如果我改变了我的 OnStartup()覆盖如下,然后应用程序启动好了。





Obviously, I do get a warning with the second piece of code that says it will complete synchronously. And when I say that the second version works, I mean only that it allows the application to start; I can't use it because the operation I am trying to perform takes too long to be done synchronously in OnStartup().

I guess I am missing something silly here. Can anyone tell me what?

What I have tried:

I I mentioned above, I have tried removing the async from the stream-read and the application starts okay.

I have just discovered that if I change my OnStartup() override to be as follows then the application starts up okay.

protected override async void OnStartup( StartupEventArgs e )
{
	base.OnStartup( e );
	Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
	StartupUri = new Uri( "./View/MainWindow.xaml", UriKind.Relative );
	LogsEmailer logsEmailer = new LogsEmailer();
	string testString = await logEmailer.TestReadFileAsync( Path.Combine( logsFolder, "TestFile.txt" ) );
}

推荐答案

这是 async void 方法 - 方法在完成之前返回,并且调用者无法知道该方法仍在工作。



Application class引发 Startup 事件。处理程序返回时 - 在您的示例中第一个等待调用 - 然后调用私有 DoStartup 方法。这个方法读取你的代码尚未设置的 StartupUri ,所以它无关。



正如您所发现的那样,如果您移动分配 StartupUri 的行之前第一个等待调用,然后它将按预期工作。



理想情况下,您应该将 async 代码移动到任务 - 调整方法。然后,您可以将该任务存储在一个字段中,稍后代码可以等待它以确保它已完成。



避免异步空方法你被劫持了 [ ^ ]
This is one of the big problems with async void methods - the method returns before it has completed, and the caller has no way of knowing that the method is still doing work.

The Application class raises the Startup event. When the handler returns - at the first await call in your example - it then calls the private DoStartup method. This method reads the StartupUri, which you code hasn't set yet, so it has nothing to do.

As you discovered, if you move the line which assigns the StartupUri before the first await call, then it will work as expected.

Ideally, you should move the async code to a task-retuning method. You can then store that task in a field, and later code can await it to ensure that it has completed.

Avoid async void methods | You’ve Been Haacked[^]


我不确定你的代码,但我认为你是在应用程序启动阶段的早期这样做的。



如果你有一个显示状态的窗口,为什么不先让窗口加载并使用进度显示进行异步调用?我已经实现了一些演示如何工作的演示:



例如,参见 MainWindow.cs - > FilterTreeView.zip中的已加载事件演示:



C#/ VB.Net中的高级WPF TreeViews n的第3部分 [ ^ ]



下载:C#/ VB.Net中的高级WPF TreeViews n [ ^ ]
I am not sure about your code but I think you are doing this to early in the start-up phase of the application.

If you have a window to show with a status, why don't let the window load first and do the async call with a progress display? I have implemented a few demos that show how this could work:

See, for example, MainWindow.cs -> Loaded Event in FilterTreeView.zip demo:

Advanced WPF TreeViews in C#/VB.Net Part 3 of n[^]

Downloads: Advanced WPF TreeViews in C#/VB.Net Part 3 of n[^]


尝试将窗口作为资源加载到异步方法的延续部分。

Try loading your window as a resource in the continuation part of the async method.

protected override async void OnStartup( StartupEventArgs e )
{
	base.OnStartup( e );
	Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
	LogsEmailer logsEmailer = new LogsEmailer();
        //StartupUri = new Uri( "./View/MainWindow.xaml", UriKind.Relative );
	string testString = await logsEmailer.TestReadFileAsync( Path.Combine( logsFolder, "TestFile.txt" ) );
	Uri startUpUri = new Uri("MainWindow.xaml", UriKind.Relative);
        MainWindow=LoadComponent(startUpUri)as Window;
        MainWindow.Show();
}


这篇关于如何在应用程序启动时异步读取文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆