I have made a download program in C#. It is a queue downloader.
You can see how it works here: Click Express Downloader
Is there any faster method to download?
Here is the method i use, it must support resume support.
private void Download(object startPoint)
{
try
{
try
{
//int startPointInt = Convert.ToInt32(startPoint);
Int64 startPointInt = Convert.ToInt64(startPoint);
webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.AddRange(startPointInt);
webRequest.Credentials = CredentialCache.DefaultCredentials;
webResponse = (HttpWebResponse)webRequest.GetResponse();
Int64 fileSize = webResponse.ContentLength;
strResponse = webResponse.GetResponseStream();
if (startPointInt == 0)
{
strLocal = new FileStream(txtPath.Text + "\\" + filename, FileMode.Create, FileAccess.Write, FileShare.None);
}
else
{
strLocal = new FileStream(txtPath.Text + "\\" + filename, FileMode.Append, FileAccess.Write, FileShare.None);
}
int bytesSize = 0;
byte[] downBuffer = new byte[4096];
while ((bytesSize = strResponse.Read(downBuffer, 0, downBuffer.Length)) > 0)
{
strLocal.Write(downBuffer, 0, bytesSize);
this.Invoke(new UpdateProgessCallback(this.UpdateProgress), new object[] { strLocal.Length, fileSize + startPointInt });
if (goPause == true)
{
break;
}
}
}
catch { }
}
finally
{
strResponse.Close();
strLocal.Close();
}
}
You have to do two things,
Get faster bandwidth
Change block size from 4096 to something like 8192 or any number which can be hold in memory easily.
Related
I am using ftp for downloading a zip file(size 10 MB to 70 MB) from server it was perfectly downloading but, when the network is slow, the error the operation has timed out in ftp is showing and then it comes to catch(Exception ex) in that the download() is called once again so it is redownloading again and again.
This project is created in .NET framework 4.0
I have increased the time of ftpWebRequest.Timeout = 6000; but still it doesn't work
public void Download(string localDirectory,string localFilename,string remoteDirectory,string remoteFileName)
{
string client_path=Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(localDirectory)));
string appPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
string configFile = System.IO.Path.Combine(appPath, "PACS.exe.config");
ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
configFileMap.ExeConfigFilename = configFile;
System.Configuration.Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
config.AppSettings.Settings["client_path"].Value = client_path;
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
string str = Path.Combine(localDirectory, localFilename);
FileInfo fileInfo = new FileInfo(str);
FileStream fileStream = (FileStream)null;
WebException webException;
try
{
string path = Path.GetDirectoryName(Path.GetDirectoryName(remoteDirectory));
string path1 = Path.GetDirectoryName(Path.GetDirectoryName(localDirectory));
WebRequest sizeRequest = WebRequest.Create("ftp://" + "IP" + ":" + "port" + "/" + "C:\\KINSOLUTIONS\\Team\\Images\\1" + ".zip");
sizeRequest.Credentials = (ICredentials)new NetworkCredential("UserName", "Password");
sizeRequest.Method = WebRequestMethods.Ftp.GetFileSize;
int size = (int)sizeRequest.GetResponse().ContentLength;
FtpWebRequest ftpWebRequest = WebRequest.Create(new Uri("ftp://" + "IP" + ":" + "port" + "/" + "C:\\KINSOLUTIONS\\Team\\Images\\1" + ".zip")) as FtpWebRequest;
ftpWebRequest.Credentials = (ICredentials)new NetworkCredential("UserName", "Password");
ftpWebRequest.UsePassive = true;
ftpWebRequest.Timeout = 6000;
ftpWebRequest.KeepAlive = false;
ftpWebRequest.Method = "RETR";
ftpWebRequest.UseBinary = true;
fileStream = new FileStream(path1 + ".zip", FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
using(Stream responseStream = (ftpWebRequest.GetResponse() as FtpWebResponse).GetResponseStream())
{
byte[] buffer = new byte[32768];
int count = responseStream.Read(buffer, 0, 32768);
long num = (long)count;
int post = 0;
while (size != post || count != 0 )
{
bool result = System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();
while (!result)
{
result = System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();
if (result)
{
fileStream.Close();
Download(localDirectory, localFilename, remoteDirectory, remoteFileName);
}
}
fileStream.Write(buffer, 0, count);
count = responseStream.Read(buffer, 0, 32768);
int position = (int)fileStream.Position;
num += (long)count;
post = position;
}
fileStream.Close();
}
}
catch (WebException ex)
{
if (fileStream != null)
fileStream.Close();
this.Download(localDirectory, localFilename, remoteDirectory, remoteFileName);
}
finally
{
if (fileStream != null)
fileStream.Close();
}
}
Is there any other option for downloading the zip file in slow network?
I am re-developing an app for a scanner used for stocktakes to allow it to work while offline. In order to do so, I need to be able to download a file from a laptop which is acting as a server. I got to a point at which it works, but only downloads that are of size 9.53mb max. How can I tweak the code to allow for larger files. I would need to allow for a maximum size of around 30mb.
Here is my code:
try
{
string full_url = App.prouductUrl + App.stStocktakeId + ".db";
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(full_url);
httpRequest.Credentials = CredentialCache.DefaultCredentials;
HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse();
System.IO.Stream dataStream = httpResponse.GetResponseStream();
// Dim str As Stream = cdsMobileLibrary2.http_download.getfile(filename)
//50 meg
byte[] inBuf = new byte[10000001];
int bytesToRead = Convert.ToInt32(inBuf.Length);
int bytesRead = 0;
while (bytesToRead > 0)
{
int n = dataStream.Read(inBuf, bytesRead, bytesToRead);
if (n == 0)
{
break; // TODO: might not be correct. Was : Exit While
}
bytesRead += n;
bytesToRead -= n;
}
FileStream fstr = new FileStream(#"\productdb\" + App.stStocktakeId + ".db", FileMode.OpenOrCreate, FileAccess.Write);
fstr.Write(inBuf, 0, bytesRead);
dataStream.Close();
fstr.Close();
string size = loginRes.getFromJSON("size");
FileInfo fi = new FileInfo(#"\productdb\" + App.stStocktakeId + ".db");
MessageBox.Show("File Size is:" + fi.Length + "Compared to:" + size);
}
catch { }
I wrote a simple C# program to transfer ACCDE files from a FTP server to a client's desktop. The transferring seems to work fine, however, when I open the file and try to use the program, it gives me the message "Requested type library or wizard is not a VBA project."
When I transfer the ACCDB source code, it seems to work fine. This is the transfer function:
private void DownloadFileFTP(string fileName, string localFilePath, bool isXmlSchema)
{
string ftpFilePath = redacted;
if (isXmlSchema)
{
ftpFilePath = ftpFilePath + fileName;
label3.Text = "Fetching update information...";
}
else
{
ftpFilePath = ftpFilePath + Properties.Settings.Default.Customer + "/" + fileName;
label3.Text = "Updating " + fileName;
}
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpFilePath);
request.Credentials = new NetworkCredential(redacted, redacted);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.EnableSsl = Properties.Settings.Default.SSL;
request.UsePassive = Properties.Settings.Default.Passive;
int bytesRead = 0;
byte[] buffer = new byte[2048];
Stream reader = request.GetResponse().GetResponseStream();
FileStream fs = new FileStream(localFilePath, FileMode.Create);
while(true)
{
bytesRead = reader.Read(buffer, 0, buffer.Length);
if (bytesRead == 0)
break;
fs.Write(buffer, 0, bytesRead);
}
fs.Close();
}
My questions, I suppose, are: am I doing something wrong here? Do ACCDE files not play nice with FileStreams or something? I am still quite new to .NET so any help would be very appreciated.
EDIT: It seems one of the references was causing the problem.
You didn't close stream and ftpWebRequest.
Try this, made with you script, just copy/paste (fix some error if it have :) ):
private void DownloadFileFTP(string fileName, string localFilePath, bool isXmlSchema)
{
FileStream fs = null;
try
{
fileName = Regex.Replace(fileName.ToString(), #"\s.*$", "").Trim();
string ftpFilePath = redacted;
if (isXmlSchema)
{
ftpFilePath = ftpFilePath + fileName;
label3.Text = "Fetching update information...";
}
else
{
ftpFilePath = ftpFilePath + Properties.Settings.Default.Customer + "/" + fileName;
label3.Text = "Updating " + fileName;
}
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpFilePath);
request.Credentials = new NetworkCredential(redacted, redacted);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.EnableSsl = Properties.Settings.Default.SSL;
request.UsePassive = Properties.Settings.Default.Passive;
int bytesRead = 0;
int bufferSize = 2048;
byte[] buffer = new byte[bufferSize];
Stream reader = request.GetResponseStream();
bytesRead = reader.Read(buffer, 0, bufferSize);
fs = new FileStream(localFilePath, FileMode.Create);
while (bytesRead > 0)
{
fs.Write(buffer, 0, bytesRead);
bytesRead = reader.Read(buffer, 0, bufferSize);
}
reader.Close();
request.Close();
}
catch (Exception ex)
{
label3.Text = "Error: " + ex.ToString;
}
finally
{
if (fs != null)
{
fs.Close();
}
}
}
I'm having a network stream which is having filename and filedata in it. I'm sending files in some chunks and each chunk carries the filename for easy identification. Can you please help me in reading the network stream properly and writing all of the data to the file stream.
I seem to miss few bytes when i write the data from network stream.
Say for example filename length will be in oth index and filename will start from 4th index.
Client:
int NoOfPackets = Convert.ToInt32
(Math.Ceiling((Convert.ToDouble(Fs.Length))/ Convert.ToDouble(BufferSize)));
int TotalLength = (NoOfPackets *4+fileNameByte.Length) +(int)Fs.Length, CurrentPacketLength, counter = 0;
netstream1 = client.GetStream();
for (int i = 0; i < NoOfPackets+1 ; i++)
{
if (TotalLength > BufferSize)
{
CurrentPacketLength = BufferSize;
TotalLength = TotalLength - CurrentPacketLength;
}
else
CurrentPacketLength = TotalLength;
SendingBuffer = new byte[CurrentPacketLength];
fileNameLength.CopyTo(SendingBuffer, 0);
fileNameByte.CopyTo(SendingBuffer, 4);
Fs.Read(SendingBuffer, 4 + fileNameByte.Length, CurrentPacketLength - (4 + fileNameByte.Length));
netstream1.Write(SendingBuffer, 0, SendingBuffer.Length);
netstream1.Flush();
}
Listener Code:
client = Listener.AcceptTcpClient();
client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
//client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, true);
client.Client.LingerState = new LingerOption(true, 300);
client.Client.SendTimeout = 300000;
client.Client.ReceiveTimeout = 300000;
client.NoDelay = true;
NetworkStream netstream = client.GetStream();
MemoryStream ms = new MemoryStream();
bool first = true;
string fullPath = "";
byte[] RecData = new byte[512000];
while ((RecBytes = netstream.Read
(RecData, 0, RecData.Length)) > 0)
{
int fileNameLen = RecData[0];
if (fileNameLen > 0 && first)
{
string name1 = "", name2 = "";
first = false;
name1 = Encoding.UTF8.GetString(RecData, 4, fileNameLen);
name2 = name1;
string folderName = "";
if (name2.Contains("\\"))
{
folderName = name2.Substring(0, name2.LastIndexOf("\\"));
if (!Directory.Exists("D:\\123\\" + folderName))
Directory.CreateDirectory("D:\\123\\" + folderName);
}
if (folderName != "")
fullPath = "D:\\123\\" + folderName + "\\" + name2.Substring(name2.LastIndexOf("\\") + 1);
else
fullPath = "D:\\123\\" + name2.Substring(name2.LastIndexOf("\\") + 1);
}
if (!File.Exists(fullPath))
{
//file = new FileStream(fullPath, FileMode.OpenOrCreate, FileAccess.Write);
while (true)
{
try
{
using (FileStream file = new FileStream(fullPath, FileMode.OpenOrCreate, FileAccess.Write))
{
if (RecBytes - (4 + fileNameLen) > 0)
file.Write(RecData, 4 + fileNameLen, RecBytes - (4 + fileNameLen));
break;
}
}
catch (IOException)
{
Thread.Sleep(20);
}
}
//using (file = File.Create(fullPath))
//{
// file.Write(data, 4 + fileNameLen, (int)data.Length - (4 + fileNameLen));
//}
}
else
{
while (true)
{
try
{
using (FileStream file = new FileStream(fullPath, FileMode.Append, FileAccess.Write))
{
if (RecBytes - (4 + fileNameLen) > 0)
file.Write(RecData, 4 + fileNameLen, RecBytes - (4 + fileNameLen));
break;
}
}
catch (IOException)
{
Thread.Sleep(20);
}
}
}
}
ms.Close();
netstream.Close();
client.Close();
even though you are as vague as anyone can be, still I would suggest that you create a structure so that serialization and de-serialization of data could be done in a known format!! and data loss could be avoided!!
Again if your approach is known it would be great help in answering your question.
I have a bit of code that uses a Task to transfer a file over a web service. However if the network drops or a timeout occurs it results in an incomplete file. I'm really trying to make this service as reliable as possible, but I'm not really sure where to even really start to add code that will trap when a chunk was not sent, and then attempt to resend it multiple times but also not send the next chunk until that is done. And maybe if it cannot resend that chunk over X times, fail completely and log an event.
Can anyone suggest anything?
Action<Guid, string> action = (smGuid, pubAttFullPath) =>
{
try
{
//Set filename from object
string FileName;
FileName = System.IO.Path.GetFileName(pubAttFullPath.ToString());
//Declare Web Service
TransferFile.TransferFileSoapClient ws_TransferFile = new TransferFile.TransferFileSoapClient();
//
bool transfercompleted = false;
using (FileStream fs = new FileStream(
pubAttFullPath.ToString(),
FileMode.Open,
FileAccess.Read,
FileShare.Read))
{
//Declare Buffers and Counts
byte[] buffer = new byte[49152];
long fileSize = fs.Length;
long totalReadCount = 0;
int readCount;
float percentageComplete = 0;
//Loop and copy file until it changes to not exactly the same byte count as the buffer
//which means the file is about to complete.
while ((readCount = fs.Read(buffer, 0, buffer.Length)) > 0)
{
if (!transfercompleted)
{
totalReadCount += readCount;
byte[] bytesToTransfer;
if (readCount == buffer.Length)
{
//Copy bytes until buffer is different
bytesToTransfer = buffer;
ws_TransferFile.WriteBinaryFile("ABCD", bytesToTransfer, FileName);
percentageComplete = (totalReadCount / (float)fileSize * 100);
percentageComplete = (float)Math.Round(percentageComplete, 2, MidpointRounding.ToEven);
//Update progress to DB
InsertProgress.InsertProgressSoapClient ws_InsertProgress = new InsertProgress.InsertProgressSoapClient();
if (percentageComplete == 10.00)
{
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 10.0);
}
if (percentageComplete == 20.00)
{
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 20.0);
}
if (percentageComplete == 30.00)
{
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 30.0);
}
if (percentageComplete == 40.00)
{
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 40.0);
}
if (percentageComplete == 50.00)
{
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 50.0);
}
if (percentageComplete == 60.00)
{
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 60.0);
}
if (percentageComplete == 70.00)
{
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 70.0);
}
if (percentageComplete == 80.00)
{
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 80.0);
}
if (percentageComplete == 90.00)
{
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 90.0);
}
}
else
{
// Only a part is requred to upload,
// copy that part.
List<byte> b = new List<byte>(buffer);
bytesToTransfer = b.GetRange(0, readCount).ToArray();
ws_TransferFile.WriteBinaryFile("ABCD", bytesToTransfer, FileName);
percentageComplete = 100;
//Insert Progress as complete
InsertProgress.InsertProgressSoapClient ws_InsertProgress = new InsertProgress.InsertProgressSoapClient();
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 100);
transfercompleted = true;
fs.Close();
break;
}
}
}
}
}
catch (Exception ex)
{
EventLog.WriteEntry("Application", ex.Message.ToString(), EventLogEntryType.Error);
}
Web service is bad idea for file transfer. I used it few times, but amount of additional data transfered is making size of transfered data 1,5-2 times bigger then sending file using simple handler. Handler will allow you to the same without issues. It causes al lot of problem with proper progress handling and resume. You realy should reconsider using httphandler. If you like to use webservice, here is good example:
http://msdn.microsoft.com/en-us/library/ms172362%28v=vs.85%29.aspx
If you decide to use IHttpHandler see:
http://msdn.microsoft.com/en-us/library/ms228090%28v=vs.100%29.aspx
And then you can use following piece of code to proper handle retry/resume:
using (Stream stream = new FileStream(
pubAttFullPath.ToString(),
FileMode.Open,
FileAccess.Read,
FileShare.Read))
{
context.Response.AddHeader("Accept-Ranges", "bytes");
context.Response.Buffer = false;
if (context.Request.Headers["Range"] != null)
{
context.Response.StatusCode = 206;
string[] range = context.Request.Headers["Range"].Split(new[] { '=', '-' });
startBytes = Convert.ToInt32(range[1]);
}
int dataToRead = size - startBytes;
context.Response.ContentType = "application/octet-stream";
context.Response.AddHeader("Content-Length", dataToRead.ToString());
context.Response.AddHeader("Connection", "Keep-Alive");
context.Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(fileName, Encoding.UTF8));
if (startBytes > 0)
{
context.Response.AddHeader("Content-Range", string.Format(" bytes {0}-{1}/{2}", startBytes, size - 1, size));
stream.Seek(startBytes, SeekOrigin.Begin);
}
while (dataToRead > 0)
{
// Verify that the client is connected.
if (context.Response.IsClientConnected)
{
// Read the data in buffer.
int length = stream.Read(buffer, 0, buffer.Length);
// Write the data to the current output stream.
context.Response.OutputStream.Write(buffer, 0, length);
// Flush the data to the HTML output.
context.Response.Flush();
dataToRead = dataToRead - length;
}
else
{
// prevent infinite loop if user disconnects
dataToRead = -1;
}
}
}