在我的应用程序中,有几个协同例程正在并行下载文件,并且它们有可能尝试将同一文件下载到同一路径-导致冲突和访问异常。我尝试通过使用静态集合private static List<string> filesBeingDownloadedNow = new List<string>();
解决此问题,该集合为当前正在下载的文件保存了filePath。
它看起来像这样:
private static List<string> filesBeingDownloadedNow = new List<string>();
private IEnumerator DoDownloadCoroutine(string url, string filePath)
{
filesBeingDownloadedNow.Add(filePath);
var webRequest = new UnityWebRequest(url)
{
method = UnityWebRequest.kHttpVerbGET,
downloadHandler = new DownloadHandlerFile(filePath)
{
removeFileOnAbort = true
}
};
yield return webRequest.SendWebRequest();
if (webRequest.isNetworkError || webRequest.isHttpError)
{
// do something if the file failed to download
}
else
{
// do something with the downloaded file
}
filesBeingDownloadedNow.Remove(filePath);
}
和其他地方:
if (filesBeingDownloadedNow.Contains(filePath))
{
// start another coroutine which simply waits until
// filesBeingDownloadedNow doesn't contain filePath anymore
// and then works with the downloaded file
// as if this coroutine downloaded it itself
}
else
{
StartCoroutine(DoDownloadCoroutine(url, filePath));
}
现在,这工作得很好,但是在极少数情况下,可以在文件下载协程完成之前销毁运行此协程的gameObject。因此,yield return webRequest.SendWebRequest();
将是这里有史以来的最后一件事,无法检查成功或失败,并且永远无法达到filesBeingDownloadedNow.Remove(filePath);
。
我对此进行了测试,看来UnityWebRequest.SendWebRequest
仍会完整下载文件-但是,尚不清楚何时结束或是否成功下载了文件。它只是“在以太里迷路了”。
我可以简单地尝试围绕File.Open进行异常处理,或者我想对下载的文件进行其他任何处理(实际上无论如何都应该这样做)。但是,UnityWebRequest不允许处理异常,因为它是用yield return
调用的。
即使在调用webRequest.SendWebRequest();
之前,我也会检查文件if (File.Existst(filePath))
是否已存在,但是如果2个不同的UnityWebRequests尝试几乎同时下载同一文件,这也无济于事。可能是第一个UnityWebRequest只是刚刚连接到服务器,还没有在filePath上创建文件,第二个协程将看到该文件不存在,并假设现在没有人下载它,并且仍然尝试使用webRequest.SendWebRequest();
下载,导致冲突和我无法处理的异常。
因此,基本上,有多种因素结合在一起:
坦白说,我也确实不喜欢这里的静态列表,但是似乎文件仍然是全局资源,因此使其成为非静态无法解决任何问题。无论我对该列表进行什么操作,UnityWebRequest.SendWebRequest都会继续自行下载文件。
答案 0 :(得分:2)
您从不等待下载处理程序完成,如果您尝试在下载处理程序完成之前使用它,有时会导致奇怪的行为,在处理程序isDone
标志为true之前,最好产生null,即它完成处理下载的数据,取决于其类型。
是,请求完成下载,但有时处理程序未完成其“处理”,即完成下载的同一瞬间。
UnityWebRequest webRequest = UnityWebRequest.Get(url);
webRequest.downloadHandler = new DownloadHandlerFile(filePath) { removeFileOnAbort = true };
// 1) Wait until the download is done.
yield return webRequest.SendWebRequest();
if (webRequest.isNetworkError || webRequest.isHttpError)
{
// do something if the file failed to download
}
else
{
// 2) Wait until the handler itself finishes.
while (!webRequest.downloadHandler.isDone)
yield return null;
// Now you can safely do something with the downloaded file
}