C# Downloading a range of files - c#

I know a few similar questions have been asked on how to download files using WebClient. I can download individual files perfectly fine, but I want to download a range of files. Anywhere from 1-6000 files. I can download them just fine into my current directory, but I am stumped on how to download them to a different directory based upon where they're being downloaded from. Do I need to temporarily change the current working directory just before downloading them?
And slightly on the same topic, I'm stuck on how to verify the files exist before downloading them. I don't want to waste bandwidth or diskspace with empty files.. Here's what I have so far:
for (int x = 1; x <= 6000; x++)
{
pbsscount = x.ToString();
// Used for downloading file
string directoryName = textBox1.Text.ToString().Replace(":", "_");
if (!Directory.Exists(textBox1.Text))
Directory.CreateDirectory(directoryName.Substring(7));
string wholePBSSurl = textBox1.Text + "/" + "pb" + pbsscount.PadLeft(6, '0') + ".png";
// Used for saving file, file name in directory
string partPBSSurl = "pb" + pbsscount.PadLeft(6, '0') + ".png";
Uri uri2 = new Uri(wholePBSSurl);
//if (fileExists(wholePBSSurl))
//{
// Initialize downloading info, grab progressbar info
WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
// Save file to folder
//webClient.DownloadFileAsync(uri2, textBox1.Text + "/" + partPBSSurl);
webClient.DownloadFileAsync(uri2, partPBSSurl);
//}
}

Do I need to temporarily change the current working directory just before downloading them?
The second parameter can be a full path #"C:\folder\file.png". If you're fine with relative path to your current directory, just change the code to webClient.DownloadFileAsync(uri2, directoryName + partPBSSurl); or even better use System.Path.Combine(directoryName, partPBSSurl)
Sure you can know the size before If sever supports that. See: How to get the file size from http headers
I don't want to waste bandwidth or diskspace with empty files.
I wouldn't worry about that. The performance slow down is negligible.

There is no need to change the current directory. You are already using an overload of DownloadFileAsync that accepts a file path as the second parameter.
Just ensure that partPBSSurl contains a full path to the destination file, including both the directory and filename.
With regard to your second question of avoiding wasted time if the file does not exist, it so happens that I asked the same question recently:
Fail Fast with WebClient
Finally, I recently extended WebClient to provide simpler progress change events and allow for the timeout to be changed. I posed that code here:
https://stackoverflow.com/a/9763976/141172

Related

How to read and write csv file when it is opened with Excel by the user in parallel with C#?

This is the first question I asked on stackoverflow, very exciting. So sorry about my grammar and other type mistakes, I would appreciate if you correct them. I want to write a program that reads a csv file if it exists in the specific folder first, stores it in List variable, add some new lines and writes it to the same file. This process will be repeated continuously in a while block.
While the file is being read and written by the program, if it is opened with Notepad, it doesn't give an error and the program could access the file in parallel. But if it is opened with Office Excel, program gives error that says "file access is denied because it is used by another process..". I want to ask you that:
1) Is it possible to give priority to the program, so program can still access the file but user cannot? Or is it possible both program and user can access the file?
2) If the solution is opening the file with Notepad, is there a way to set default program for this file as Notepad? Or how can I change default program for csv files as Notepad from C#?
Reading and writing parts of the code is as bellows:
List<string> csvLines = new List<string>();
string address = folderpath + #"\PLC_LOGLARI";
if (!Directory.Exists(address))
Directory.CreateDirectory(address);
string fileAddress = address + #"\" + fileName + "_" + machineNo + "_1.csv";
if (Directory.EnumerateFiles(address).Any(f => f.Contains(fileName + "_" + machineNo)))
{
string[] addressArray = Directory.GetFiles(address, fileName + "_" + machineNo + "*.*");
FileInfo fileInformation = new FileInfo(addressArray[addressArray.Length - 1]);
long fileSize = fileInformation.Length;
if (fileSize > 5000000)
{
int fileNo = int.Parse(addressArray[addressArray.Length - 1].Substring(addressArray[addressArray.Length - 1].LastIndexOf('_') + 1, 1)) + 1;
fileAddress = addressArray[addressArray.Length - 1].Substring(0, addressArray[addressArray.Length - 1].LastIndexOf('_') + 1) + fileNo.ToString() + ".csv";
}
else
{
fileAddress = addressArray[addressArray.Length - 1];
csvLines = File.ReadAllLines(address).ToList();
}
}
else
{
string[] headings = makeHeadings();
csvLines.Add(headings[0]);
csvLines.Add(headings[1]);
}
string newLine = "";
// some operations and calculations for newLine
// some operations and calculations for newLine
// some operations and calculations for newLine
newLine = newLine.Substring(1, newLine.Length-1);
csvLines.Add(newLine);
File.WriteAllLines(fileAddress, csvLines.ToArray());
Thanks for your help.
For question 2: In order to change the default program, if you are using Windows, you could click start and find/type 'Default Programs'. Depending on the version of windows, basically find 'Associate a file type of protocol with a program' or 'choose a default application by file type' and adjust the csv file to use a new default program.
I would be very careful if both program and notepad are able accessing the file in the same time. The reason why it was blocked in the first place was to prevent overridding the content of the file, thus probably test it first if you open it in the program and notepad. Then the program make some update - and you also make a different update with the notepad. Would both changes be recorded? As I suspect the 'last save' win in which you may lost some of your changes.
For question 1: I was guessing that whoever open the file first got the lock of that file. As such, if Excel was opening the file - then the program would have that error. Vice versa, if the program had opened the file - then the Excel may have problem opening that file. I'm not sure how to give priority to the program.

WebClient.FileDownlOad GIVIn error that the file a is accessed by another process

I am trying to download a file using webclient method DownloadFile But its giving me error that
The process cannot access the file '...\d915877c-cb7c-4eeb-97d8-41d49b75aa27.docx' because it is being used by another process.
But when I open the file by clicking it, it opening.
There are same question requesting same info but none are accepted answers.
any help will be appreciated
It may be oS that is not letting file go. Whatever it is but after searching a lot I am unable to find solution
Here is the code to create a file
Document d = new Document();
d.Save(HttpContext.Current.Server.MapPath(#"Invoice\" + iname + ".docx"));
I am using aspose word dll
and following way I am accessing it
using (var client = new System.Net.WebClient())
{
client.UseDefaultCredentials = true;
client.DownloadFile(Server.MapPath("invoice/" + Request.QueryString["id"].ToString() + ".docx"),Server.MapPath("invoice/" +Request.QueryString["id"].ToString() + ".docx"));
client.Dispose();
}
and BTW its giving same error even to files that are not creaated using code.
Give a different path where to save the download file which is different from the download source path. If you want to replace the file do it after disposing the webclient by using File.replace() method.
string downloadPath = "Your download path";
string destinationPath = "the path where the file should be saved";`//this should be different from "download path"
File.Download(downloadPath,destinationPath);

C# Download an image from URL

I use a website to get stats on wifi usage. The website creates an image of a graph representation of the data. The way it does this is by the user, setting a date. So for example, lets say it was last months statistics. The website generates a URL which is then sent to the server and the server returns an image. an examples of the link is like this:
https://www.example.com/graph/daily_usage?time_from=2015-06-01+00%3A00%3A00+%2B0100&time_to=2015-06-30+23%3A59%3A59+%2B0100&tsp=1436519988
The problem is, I am making a third party program that will download this image to be used in my program. However, I cannot use the file. It is as if the file is corrupt or something. I have tried a few methods but maybe someone can suggest a different approach. Basically, how do I download an image that is generated by a server from a URL link?
P.S.
Just noticed that if I download the file by right clicking through a browser and save, the image downloads with a size of 17.something kilobytes. But if I use the WebClient method to download the image, it only downloads 1.5kb. Why would that be? Seems like the WebClient method does not download completely.
Currently my code
if (hrefAtt == "Usage Graph")
{
string url = element.getAttribute("src");
WebClient client = new WebClient();
client.DownloadFile(url, tempFolderPath + "\\" + currentAcc + "_UsageSummary.png");
wd.AddImagesToDoc(tempFolderPath + "\\" + currentAcc + "_UsageSummary.png");
wd.SaveDocument();
}
TempFolderPath is my desktop\TempFolder\
UPDATE
Out of random, I decided to see the raw data of the file with notepad and interestingly, the image data was actually a copy of the websites homepage html code, not the raw data of the image :S how does that make sense?
This will download the Google logo:
var img = Bitmap.FromStream(new MemoryStream(new WebClient().DownloadData("https://www.google.co.uk/images/srpr/logo11w.png")));
First of all, you have to understand link texture. If all links are same or close to each other, you have to use substring/remove/datetime etc. methods to make your new request link. For example;
string today = DateTime.Now.ToShortDateString();
string generatedLink = #"http://www.yoururl.com/image + " + today + ".jpg";
string generatedFileName = #"C:\Usage\usage + " + today + ".jpg";
WebClient wClient = new WebClient();
wClient.DownloadFile(generatedLink, generatedFileName);

Trouble saving a downloaded file to the desktop in WPF C#

When I use:
WebClient web = new WebClient();
web.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChangedWeb);
web.DownloadFileAsync(new Uri("http://www.website.com/Webs.exe"),
Environment.SpecialFolder.Desktop + #"\Webs.exe");
...Nothing downloads.
But if i change it to"
WebClient web = new WebClient();
web.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChangedWeb);
web.DownloadFileAsync(new Uri("http://www.website.com/Webs.exe"),
Environment.SpecialFolder.Desktop + "Webs.exe");
Then It downloads, but I get a file named "desktopWebs.exe". So How can I save a file to the desktop?
Thanks
What you want is this...
Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + #"\Webs.exe";
Otherwise you are just tacking on the word desktop instead of the actual path.
You can use Path.Combine
web.DownloadFileAsync(new Uri("http://www.website.com/Webs.exe"),
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "Webs.exe"));
This function will automatically insert (or remove) slashes as well as adapt to any file system being used
You should also consider using Environment.SpecialFolder.DesktopDirectory, this points to the actual physical location of the desktop folder on the disk.

C# how to lock the file

We are using an application that reads the file and inserts into database. For some reason, we set the creation time to a particular time. and when we create the file the application picks up the file before we even change the creation time. Is there anyway that we can lock the file until we change its creation time.
The error i am getting is at File.SetCreationTime as the file is being used by other process or the file is archived.
//Copy signal file
s = filePath + "s";
newS = targetFullPath2 + "s";
File.Copy(s, newS, true);
//
//new creation ts
dtFileCreation = File.GetCreationTime(s);
//retain creation time
File.SetCreationTime(newS, dtFileCreation);
Please advice.
The common solution to this is to create the file (and set its timestamp) in a different directory or under a different name first, and then move or rename it when it’s ready so the other process can pick it up. The move/rename is an atomic operation on NTFS (unless of course you move files between separate partitions).
For example:
s = filePath + "s";
newS = targetFullPath2 + "s";
File.Copy(s, newS + "_", true); // add the _ so the other process
// doesn’t “see” the file yet
dtFileCreation = File.GetCreationTime(s);
File.SetCreationTime(newS + "_", dtFileCreation);
// We’re done with the file, now rename it to its intended final name
File.Move(newS + "_", newS);
That error indicates someone (it could be you or another program) is locking the file; therefore, I do not think locking the file will solve your problem. What kind of file is it? Is your code reading the file and forgetting to close the stream after it is done?

Categories