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;
});
}