How to wait till file get downloaded completely. C# - c#

I'm downloading one file using WebClient in one of the method.
public static void DownloadServicePackage()
{
FilePath = #"C:\Users\userName\AppData\TestExe.zip".Replace("userName", userName);
string extractPath = #"C:\Users\userName\AppData".Replace("userName", userName);
WebClient webClient = new WebClient();
webClient.DownloadFile("https://stg.test.com/downloadScript/TestExe.zip", FilePath);
ZipFile.ExtractToDirectory(FilePath, extractPath);
}
public MainWindow()
{
DownloadServicePackage();
DownloadFile();
}
I need to wait in this method until zip file gets downloaded completely. So that I can extract further.
Any suggestions? How can I achieve this as I don't want to proceed till file get downloaded. Also file size can differ from time to time.
Thanks in advance!

Related

Waiting for a file until it is downloaded using C#

I'm using C# to download different files via url and run them afterwards from a physical filepath in the system, however I need to wait for the file until it is completely written and only then run it. The reason is that some files would need more time than others to be saved and I can't really use Thread.Sleep() for this purpose.
I tried this code but it is not that flexible for some reason, as I can't really tell how many tries or how much time it should be until the file is saved. This depends always on the internet connection as well as on the file size.
WebClient client = new WebClient();
var downloadTask = client.DownloadFileTaskAsync(new Uri(url), filepath);
var checkFile = Task.Run(async () => await downloadTask);
WaitForFile(filepath, FileMode.CreateNew);
—
FileStream WaitForFile(string fullPath, FileMode mode)
{
for (int numTries = 0; numTries < 15; numTries++)
{
FileStream fs = null;
try
{
fs = new FileStream(fullPath, mode);
return fs;
}
catch (IOException)
{
if (fs != null)
{
fs.Dispose();
}
Thread.Sleep(50);
}
}
return null;
}
Is there a way to keep waiting until the File.Length > 0?
I would appreciate any help.
Thanks.
You're not awaiting for the file to complete download. Or better said, you're awaiting, in a different thread, and then throwing that result away. Just wait in the very same method and you no longer need a separate way to know when the file is downloaded
WebClient client = new WebClient();
await client.DownloadFileTaskAsync(new Uri(url), filepath);
You can use FileSystemWatcher to get an event when file changes its size or a new file appear https://learn.microsoft.com/en-us/dotnet/api/system.io.filesystemwatcher.onchanged?view=netcore-3.1
But you can't really tell if the file is fully downloaded this way unless you know its size.
You should just change the code that downloads the file so that it notifies when the file is downloaded.
I think this is all you have to do:
WebClient client = new WebClient();
await client.DownloadFileTaskAsync(new Uri(url), filepath);
// code continues when the file finishes downloading

Cannot access file after downloading it with Webclient

I have downloaded a zip file using this code from a web server:
client.DownloadFileAsync(url, savePath);
Then, in another method, during the same session I try and extract the file with this method:
ZipFile.ExtractToDirectory(zipPath, extractDir);
This throws the error:
System.IO.IOException: 'The process cannot access the file
'C:\ProgramData\ZipFile.zip' because it is being used by another process.'
If I restart the program then unzip the file (without redownloading it) it extracts without any problem.
This doesn't make much sense to me because the Webclient client is located in another method and hence should be destroyed...
There is nothing else accessing that file other than the 2 lines of code provided above.
Is there any way to free the file?
You need to extract the files when the download completed, to do this, you need to use DownloadFileCompleted event of webclient
private void DownloadPackageFromServer(string downloadLink)
{
ClearTempFolder();
var address = new Uri(Constants.BaseUrl + downloadLink);
using (var wc = new WebClient())
{
_downloadLink = downloadLink;
wc.DownloadFileCompleted += Wc_DownloadFileCompleted;
wc.DownloadFileAsync(address, GetLocalFilePath(downloadLink));
wc.Dispose();
}
}
private void Wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
UnZipDownloadedPackage(_downloadLink);
}
private void UnZipDownloadedPackage(string downloadLink)
{
var fileName = GetLocalFilePath(downloadLink);
ZipFile.ExtractToDirectory(fileName, Constants.TemporaryMusicFolderPath);
}

StreamReader Could not find file (Because it is not being created)

I am trying to create a file for the further write to and read from.
I use Directory.CreateDirectory and File.Create but neither path nor file are being created.
On the Page which part I show here below I check if File exists, and if not, I create a File. On Second Page (that I dont show here) I add new lines to the file using StreamWrite. When saved, first Page comes to focus again and lists the content of the File(only one row in this study).
Here is my code for the part in question:
public async Task ReadFileAsync()
{
string directoryName = Path.GetDirectoryName(#"C:\Users\...\DataBase\");
Task.Run(async() => Directory.CreateDirectory(directoryName));
Task.Run(async() => File.Create(directoryName + "ProductsDatabase.txt"));
//code for reading from file
string path = (directoryName + "ProductsDatabase.txt");
using (StreamReader ProductsDatabaseRead = new StreamReader(File.OpenRead(path)))
{
ProductOneTextBlock.Text = ProductsDatabaseRead.ReadLine();
}
if (ProductOneTextBlock.Text == "")
{
ProductOneTextBlock.Text = "Nothing to show";
}
}
The file and folder are not being created.
I don't get any error.
I tried also different folders on the drive in case if there was READ ONLY folder in solution folder. No difference.
Anyone could help?
(I found many threads about this problem but here I cannot resolve it with none of the solutions.
Physical file is not being created.
When I attempt to write to it (from another page) I get error that the file could not be found(because it is not there indeed).
It seems that program loses itself somewhere between
Task.Run(async() => Directory.CreateDirectory(directoryName));
Task.Run(async() => File.Create(directoryName + "ProductsDatabase.txt"));
and:
using (StreamReader ProductsDatabaseRead = new StreamReader(File.OpenRead(path)))
{
ProductOneTextBlock.Text = ProductsDatabaseRead.ReadLine();
}
, as TextBlock is not being updated even if ProductsDatabaseRead is null.
If I put
ProductOneTextBlock.Text = "Nothing to show";
a the begining of the method, TextBlock gets updated.
SO, why the
using (StreamReader ProductsDatabaseRead = new StreamReader(File.OpenRead(path)))
does not work?
You're not waiting for Task.Run to complete. Your directory creation, file creation and attempt to open a "as you think newly created file" are out of order. That's why you're probably not able to open a file (it still does not exist at this point).
Task.Run returns a task that will be completed when the work is done. You need to wait for completion.
public void ReadFile()
{
string folderPath = #"C:\Users\patri\source\repos\DietMate\";
string fileName = "ProductsDatabase.txt";
string fullPath = Path.Combine(folderPath, fileName);
//insert code to check whether file exists.
// use Exists()
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
File.Create(fullPath);
}
//if yes, follow with code below
//insert code for reading from file
using (StreamReader ProductsDatabaseRead = new StreamReader(fullPath))
{
ProductTest.Text = ProductsDatabaseRead.ReadLine();
}
}

WebClient using file (file in use error)

I'm new to WinForms/C#/VB.NET and all and am trying to put together a simple application which downloads an MP3 file and edits its ID3 tags. This is what I've come up with so far :
Uri link = new System.Uri("URL");
wc.DownloadFileAsync(link, #"C:/music.mp3");
handle.WaitOne();
var file = TagLib.File.Create(#"C:/music.mp3");
file.Tag.Title = "Title";
file.Save();
The top section downloads the file with a pre-defined WebClient, but when I try to open the file in the first line of the second half, I run into this error The process cannot access the file 'C:\music.mp3' because it is being used by another process. which I'm guessing is due to the WebClient.
Any ideas on how to fix this? Thanks.
If using WebClient.DownloadFileAsync you should subscribe to the DownloadFileCompleted event and perform the remainder of your processing from that event.
Quick and dirty:
WebClient wc = new WebClient();
wc.DownloadfileCompleted += completedHandler;
Uri link = new System.Uri("URL");
wc.DownloadFileAsync(link, #"C:/music.mp3");
//handle.WaitOne(); // dunno what this is doing in here.
function completedHandler(Object sender, AsyncCompletedEventArgs e) {
var file = TagLib.File.Create(#"C:/music.mp3");
file.Tag.Title = "Title";
file.Save();
}

Wait until file is downloaded from URL via webClient

I have struggle with downloading few MB excel file from URL and then work with it. Im using VS2010 so i cant use await keyword.
My code follows:
using (WebClient webClient = new WebClient())
{
// setting Windows Authentication
webClient.UseDefaultCredentials = true;
// event fired ExcelToCsv after file is downloaded
webClient.DownloadFileCompleted += (sender, e) => ExcelToCsv(fileName);
// start download
webClient.DownloadFileAsync(new Uri("http://serverx/something/Export.ashx"), exportPath);
}
The line in ExcelToCsv() method
using (FileStream stream = new FileStream(filePath, FileMode.Open))
Throws me an error:
System.IO.IOException: The process cannot access the file because it
is being used by another process.
I tried webClient.DownloadFile() only without an event but it throws same error. Same error is throwed if i do not dispose too. What can i do ?
Temporary workaround may be Sleep() method but its not bullet proof.
Thank you
EDIT:
I tried second approach with standard handling but i have mistake in the code
using (WebClient webClient = new WebClient())
{
// nastaveni ze webClient ma pouzit Windows Authentication
webClient.UseDefaultCredentials = true;
// <--- I HAVE CONVERT ASYNC ERROR IN THIS LINE
webClient.DownloadFileCompleted += new DownloadDataCompletedEventHandler(HandleDownloadDataCompleted);
// spusteni stahovani
webClient.DownloadFile(new Uri("http://czprga2001/Logio_ZelenyKyblik/Export.ashx"), TempDirectory + PSFileName);
}
public delegate void DownloadDataCompletedEventHandler(string fileName);
public event DownloadDataCompletedEventHandler DownloadDataCompleted;
static void HandleDownloadDataCompleted(string fileName)
{
ExcelToCsv(fileName);
}
EDIT: approach 3
I tried this code
while (true)
{
if (isFileLocked(downloadedFile))
{
System.Threading.Thread.Sleep(5000); //wait 5s
ExcelToCsv(fileName);
break;
}
}
and it seems that it is never accessible :/ I dont get it.
Try to use DownloadFile instead of DownloadFileAsync, as you do in Edit 1, like this:
string filename=Path.Combine(TempDirectory, PSFileName);
using (WebClient webClient = new WebClient())
{
// nastaveni ze webClient ma pouzit Windows Authentication
webClient.UseDefaultCredentials = true;
// spusteni stahovani
webClient.DownloadFile(new Uri("http://czprga2001/Logio_ZelenyKyblik/Export.ashx"), filename);
}
ExcelToCsv(filename); //No need to create the event handler if it is not async
From your example it seems that you do not need asynchronous download, so use synchronous download and avoid possible related problems like here.
Also use Path.Combine to combine parts of a path like folder and filename.
There is also a chance that it is locked by something else, use Sysinternals Process Explorer's Find DLL or Handle function to check it.
Use local disk to store downloaded file to prevent problems with network.

Categories