Scott Chamberlain's solution is the proper and the recommended way to do this in Unity since WWW
API handles threading issues in the background. You just have to use coroutine to download it then save it with manually with one of the File.WriteAllXXX
functions like Scott mentioned.
I am adding this answer since the question is specifically asking about WebClient
and there are times where using WebClient
is fine such as large data.
The problem is that you are yielding WebClient
. You don't have to yield WebClient
in a coroutine like you did. Just subscribe to its DownloadFileCompleted
event which will be called on another Thread. In order to use Unity function in that DownloadFileCompleted
callback function, you have to use UnityThread
script from this post and execute the Unity function with the help of the UnityThread.executeInUpdate
function..
Here is a complete example(UnityThread
is needed):
public Text text;
int fileID = 0;
void Awake()
{
UnityThread.initUnityThread();
}
void Start()
{
string url = "http://www.sample-videos.com/text/Sample-text-file-10kb.txt";
string savePath = Path.Combine(Application.dataPath, "file.txt");
downloadFile(url, savePath);
}
void downloadFile(string fileUrl, string savePath)
{
WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(DoSomethingOnFinish);
webClient.QueryString.Add("fileName", fileID.ToString());
Uri uri = new Uri(fileUrl);
webClient.DownloadFileAsync(uri, savePath);
fileID++;
}
//THIS FUNCTION IS CALLED IN ANOTHER THREAD BY WebClient when download is complete
void DoSomethingOnFinish(object sender, AsyncCompletedEventArgs e)
{
string myFileNameID = ((System.Net.WebClient)(sender)).QueryString["fileName"];
Debug.Log("Done downloading file: " + myFileNameID);
//Ssafety use Unity's API in another Thread with the help of UnityThread
UnityThread.executeInUpdate(() =>
{
text.text = "Done downloading file: " + myFileNameID;
});
}