After a lot more of study and research i was suggested on Stackoverflow to betterly use FileStream to open a file on client machine ,send file-name before sending data to server(listening at a pre-defined port),read a fixed-sized data in a buffer chunk-by-chunk ,send it to the remote server.All these operations were tested by me using various buffer-size starting from 10kb to 100MB now.I tested it for small-files and it worked nice.I went with the useful idea of sending 2GB file.it took almost an hour .
Following is the brief coded-idea.
Client-side:
try
{
clientSocket.Connect(new IPEndPoint(ipaddrcl, port));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
NetworkStream netstream = clientSocket.GetStream();
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
try
{
TransmitFileName(netstream, Path.GetFileName(path));
int data_len = (int)fs.Length;
byte[] buffer = new byte[bufferSize];
int totalbytes = 0;
while (totalbytes < data_len)
{
var bytesread = fs.Read(buffer, 0, buffer.Length);
if (totalbytes == data_len)
{
break;
}
try
{
netstream.Write(buffer, 0, bytesread);
totalbytes += bytesread;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
pictureBox.Image = Properties.Resources.Warning;
labelProgress.Text = "Error in transmission";
}
}
}
finally
{
MessageBox.Show("Data transfer completed");
pictureBox.Image = Properties.Resources.Information;
labelProgress.Text = "Copying Done";
fs.Close();
netstream.Close();
// change button states
btnSend.Enabled = true;
btn_Cancel.Enabled = false;
}
}
Server-side:
Directory.CreateDirectory(Path.GetDirectoryName(fileloc));
try
{
using (FileStream fs = new FileStream(fileloc, FileMode.OpenOrCreate, FileAccess.Write))
{
netStream.CopyTo(fs);
pictureBox2.Image = Properties.Resources.spinningDisc1;
// label_server.Text = "Receiving Data";
}
}
catch (Exception e)
{
MessageBox.Show(e.Message.ToString());
}
finally
{
//check the size of file recieved
FileInfo fi = new FileInfo(fileloc);
long siz = fi.Length;
MessageBox.Show("Data Recieved: File Size is " + SizeSuffix(siz));
pictureBox2.Image = null;
// Thread();
}
In order to enhance speed ,i came across here and tested CopyFileEx for copying folders and trees on local-host and it worked superb.
Now the issue is,Can i use CopyFileEx on WLAN and if,yes, how will this ensures me to write a chunk-by-chunk piece of data and still ensures speedy process.
PS.I tried my best to not make it not so-lengthy but efforts are worth to show first before asking.I didn't find any working example for WLAN..if you have please give me a start-up with it.
Related
Hello I'm trying to implement a server and client couple that can transfer files of any kind and any size but there is a problem I somehow corrupt files. I tried lots of methods but can't figure it out. So basicly I can connect ,I can understand which file does client want, and can send it through sockets. When I try to open that file it shows me an error message(Tried winrar, mp4, avi files) Here is my code:
//Server
private void Receive(string receivedFileName, string fileSize)
{
try
{
int receivedBytesLen = 0;
byte[] incomingFile = new byte[int.Parse(fileSize)];
activity.AppendText("Preparing to download... \n");
while (incomingFile != null && int.Parse(fileSize) > receivedBytesLen)
{
tempSocket.Receive(incomingFile);
receivedBytesLen = incomingFile.Length;
int fileNameLen = BitConverter.ToInt32(incomingFile, 0);
File.WriteAllBytes(fileDir + "//" + receivedFileName, incomingFile);
}
activity.AppendText("File saved to " + fileDir + "\n");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
//////////////////////////////////////////////////////////////////////
//server option 2
private void Receive(string receivedFileName, string fileSize)
{
try
{
byte[] incomingFile = new byte[10124 * 5000];
activity.AppendText("Preparing to download... \n");
BinaryWriter bWrite = new BinaryWriter(File.Open(folderBrowserDialog1.SelectedPath + "//" + receivedFileName, FileMode.Append));
int receivedBytesLen = tempSocket.Receive(incomingFile, incomingFile.Length, 0);
int fileNameLen = BitConverter.ToInt32(incomingFile, 0);
//string fileName = Encoding.UTF8.GetString(incomingFile, 4, fileNameLen);
//bWrite.Write(incomingFile, 4 + fileNameLen, receivedBytesLen - 4 - fileNameLen);
while (receivedBytesLen > 0)
{
receivedBytesLen = tempSocket.Receive(incomingFile, incomingFile.Length, 0);
if (receivedBytesLen == 0)
{
bWrite.Close();
}
else
{
bWrite.Write(incomingFile, 0, receivedBytesLen);
}
}
activity.AppendText("File saved to " + fileDir + "\n");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
/////////////////////////////////////////////////////////////////////
//client
private void Upload_Click(object sender, EventArgs e)
{//Uploads selected file after clicking upload button.
try
{
if (clientSocket.Connected)
{
byte[] buffer = new byte[1024];
byte[] sendingFile = null;
sendingFile = File.ReadAllBytes(openFileDialog1.FileName);
FileInfo f = new FileInfo(openFileDialog1.FileName);
string fileSize = f.Length.ToString();
buffer = Encoding.Default.GetBytes(getUserName.Text + "Upload" + openFileDialog1.SafeFileName + "size" + fileSize + "end");
clientSocket.Send(buffer);
activityLog.AppendText("Sending File \n");
int bytesToBeSent = sendingFile.Length;
int bytesActuallySent = 0;
while(bytesActuallySent < bytesToBeSent){
bytesActuallySent += clientSocket.Send(sendingFile, bytesActuallySent, bytesToBeSent -bytesActuallySent, 0);
}
activityLog.AppendText("File Sent.\n");
}
}
catch(Exception ex){
MessageBox.Show(ex.Message);
}
}
server option #2 is better. But there are some improvements
socket receive buffer is limited decided by OS, generally is 8192
use FileStream in client and server and do not forget to close filestream after file download
client:
FileStream fileStream = new FileStream(filePath, FileMode.Open)
byte[] buff = new byte[8192];
do
{
bytesRead = fileStream.Read(buff, 0, buff.Length);
sock.send(dataSock, buff, bytesRead);
}while (bytesRead > 0);
fileStream.close();
server:
FileStream fileStream = new FileStream(filePath, FileMode.Open)
do
{
bytesRead = sock.receive(buff, 0, buff.Lenght);
fileStream.Write(buff, 0, bytesRead );
}while (bytesRead > 0);
fileStream.close();
In order to satisfy ANY sized file you need an option #3, one that reads a block of bytes til all bytes are received, your option #1 wouldn't do so well on a 3 GIG file running on 2 GIG box...
Here is a link: http://www.yoda.arachsys.com/csharp/readbinary.html
I like option #2 from this link.
However in the example they write to a memoryStream, you should write to a filestream, the target file.
I am developing a music player in wp7 using silverlight.My end users don't have good internet connection when they are roaming. I want to give them an option to download music in their phone.
For that i have written a download manager which they can use to download music when they have wifi connection.
I ussue i am facing is that,My music is stored on my server and i am downloading the music on the phone using WebCLient class.
if size of file goes beyond 68 MB , my application gets OutOfMemory exception.
here is the code:
public void DownloadKirtan(KirtanViewModel kirtanVm,bool QueueItem=true)
{
{
if (kirtanVm.LocationPath != null)
{
WebClient webClient = new WebClient();
//webClient.AllowWriteStreamBuffering = false;
// webClient.AllowReadStreamBuffering = false;
if (QueueItem == false)
{
//App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload[kirtanVm] = webClient;
// App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload.Add(kirtanVm//
webClient = App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload[kirtanVm];
kirtanVm.IsDownloadedForOfflineViewing = "Started";
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
webClient.OpenReadAsync(kirtanVm.LocationPath, kirtanVm);
}
else if (!App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload.ContainsKey(kirtanVm))
{
App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload.Add(kirtanVm, webClient);
kirtanVm.IsDownloadedForOfflineViewing = "Started";
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
webClient.OpenReadAsync(kirtanVm.LocationPath, kirtanVm);
}
// webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
}
}
}
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
KirtanViewModel kirtanVm = e.UserState as KirtanViewModel;
try
{
if (e.Cancelled == false)
{
if (e.Result != null)
{
((WebClient)sender).OpenReadCompleted -= webClient_OpenReadCompleted;
#region Isolated Storage Copy Code
IsolatedStorageFile isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication();
bool checkQuotaIncrease = IncreaseIsolatedStorageSpace(e.Result.Length);
if (checkQuotaIncrease)
{
string VideoFile = "";
VideoFile = GetUrlOfOfflineContent(kirtanVm);
using (IsolatedStorageFileStream isolatedStorageFileStream = new IsolatedStorageFileStream(VideoFile, FileMode.Create, isolatedStorageFile))
{
long VideoFileLength = (long)e.Result.Length;
byte[] byteImage = new byte[VideoFileLength];
e.Result.Read(byteImage, 0, byteImage.Length);
isolatedStorageFileStream.Write(byteImage, 0, byteImage.Length);
kirtanVm.IsDownloadedForOfflineViewing = "True";
kirtanVm.DownloadSize = "Size=" + (VideoFileLength / 1000000).ToString() + " MB";
kirtanVm.DownloadProgress = "100%";
Settings.OfflineKirtanContents.Value.Add(kirtanVm);
AddRemoveKirtanInOfflineModels(kirtanVm, true);
}
#endregion
}
else
{
kirtanVm.IsDownloadedForOfflineViewing = "False";
App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload.Remove(kirtanVm);
MessageBox.Show("There is not enough space in your phone to store this media. You need " + e.Result.Length + " bytes of storage.Please free some offline contents you have downloaded by going to Offline content managemnt screen in Settings Section and try again or increase the storage on your phone.");
}
// mediaFile.SetSource(isolatedStorageFileStream);
// mediaFile.Play();
// progressMedia.Visibility = Visibility.Collapsed;
}
}
}
catch (Exception ex)
{
kirtanVm.IsDownloadedForOfflineViewing = "Failed";
//App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload.Remove(kirtanVm);
MessageBox.Show(ex.ToString());
}
}
The problem i am having is When i get e.result which is a stream object. To write to isolatedStoreFileStream, i have to read it again to byte array and then save it to isolatedstoragefile. This is inefficient, it consumes double memory. Memory of 60 MB (for 60MB file) by WebClient e.result stream object and then 60 MB to convert to array. So memory consumtion is 128 MB . Is there is better way to download big files and store it to IsolatedStorage>
UPDATE : I am now using following code using the chunck size , instead of reading all in memory but i still get out of memory error on large files 100 MB
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
KirtanViewModel kirtanVm = e.UserState as KirtanViewModel;
try
{
if (e.Cancelled == false)
{
if (e.Result != null)
{
((WebClient)sender).OpenReadCompleted -= webClient_OpenReadCompleted;
#region Isolated Storage Copy Code
bool checkQuotaIncrease = IncreaseIsolatedStorageSpace(e.Result.Length);
if (checkQuotaIncrease)
{
string VideoFile = "";
VideoFile = GetUrlOfOfflineContent(kirtanVm);
ThreadPool.QueueUserWorkItem( k =>{
using (IsolatedStorageFile isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream isolatedStorageFileStream = new IsolatedStorageFileStream(VideoFile, FileMode.Create, isolatedStorageFile))
{
long VideoFileLength = (long)e.Result.Length;
using (BinaryWriter writer = new BinaryWriter(isolatedStorageFileStream))
{
Stream resourceStream = e.Result;//streamResourceInfo.Stream;
long length = resourceStream.Length;
byte[] buffer = new byte[32];
int readCount = 0;
using (BinaryReader reader = new BinaryReader(resourceStream))
{ // read file in chunks in order to reduce memory consumption and increase performance
while (readCount < length)
{
int actual = reader.Read(buffer, 0, buffer.Length);
readCount += actual;
writer.Write(buffer, 0, actual);
}
}
}
kirtanVm.IsDownloadedForOfflineViewing = "True";
kirtanVm.DownloadSize = "Size=" + (VideoFileLength / 1000000).ToString() + " MB";
kirtanVm.DownloadProgress = "100%";
Settings.OfflineKirtanContents.Value.Add(kirtanVm);
AddRemoveKirtanInOfflineModels(kirtanVm, true);
}
}
});
//byte[] byteImage = new byte[VideoFileLength];
//e.Result.Read(byteImage, 0, byteImage.Length);
// e.re
//ThreadPool.QueueUserWorkItem( k =>{
// isolatedStorageFileStream.Write(byteImage, 0, byteImage.Length);
//isolatedStorageFileStream.Close();
//Application.Current.RootVisual.Dispatcher.BeginInvoke( ()=>
// {
// kirtanVm.IsDownloadedForOfflineViewing = "True";
// kirtanVm.DownloadSize = "Size=" + (VideoFileLength / 1000000).ToString() + " MB";
// kirtanVm.DownloadProgress = "100%";
// Settings.OfflineKirtanContents.Value.Add(kirtanVm);
// AddRemoveKirtanInOfflineModels(kirtanVm, true);
// });
//});
//StreamWriter writer=new StreamWriter(isolatedStorageFileStream);
// writer.Write(e.Result);
// writer.Close();
// isolatedStorageFileStream.Write(
// e.Result.Write(
// isolatedStorageFileStream.Write(byteImage, 0, byteImage.Length);
// isolatedStorageFileStream.Close();
}
#endregion
else
{
kirtanVm.IsDownloadedForOfflineViewing = "False";
App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload.Remove(kirtanVm);
MessageBox.Show("There is not enough space in your phone to store this media. You need " + e.Result.Length + " bytes of storage.Please free some offline contents you have downloaded by going to Offline content managemnt screen in Settings Section and try again or increase the storage on your phone.");
}
}
}
else
{
lock (App.ViewModel.LockForCancelForCurrentOfflineDownload)
{
if (App.ViewModel.cancelInitiatedByUserForCurrentOfflineDownload)
{
kirtanVm.IsDownloadedForOfflineViewing = "False";
// kirtanVm.IsOfflineDownloadCancelled = false;
App.ViewModel.cancelInitiatedByUserForCurrentOfflineDownload = false;
}
else
{
if (kirtanVm.IsDownloadedForOfflineViewing == "Started")// don't queue things again
{
kirtanVm.IsDownloadedForOfflineViewing = "Failed";
// bool ItemExist = App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload.Any(k => k.Key.Kirtan.KirtanId == kirtanVm.Kirtan.KirtanId);
DownloadKirtan(kirtanVm, false);
}
}
}
}
}
catch (Exception ex)
{
kirtanVm.IsDownloadedForOfflineViewing = "Failed";
//App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload.Remove(kirtanVm);
MessageBox.Show(ex.ToString());
}
}
Thanks
Verinder
Finally i found the solution
turn on webClient.AllowReadStreamBuffering = false; in the above code which i shared and then in
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) {} method.. Remove all refrences to e.Result.Length. When using no buffering solution you cannot know the stream size in advance
long length = resourceStream.Length;
byte[] buffer = new byte[1024];
int readCount = 0;
using (BinaryReader reader = new BinaryReader(resourceStream)) { // read file in chunks in order to reduce memory consumption and increase performance
while (true)
{
int actual = reader.Read(buffer, 0, 1024);
if(actual==0)
{
break;
}
else
{
readCount += actual;
writer.Write(buffer, 0, actual);
}
}
}
Keep on reading the stream with 1024 bytes at a time unless you are done reading. This way WebClient will not buffer whole file in memory and max mem usage on your phone will be 1KB at a time. You can download Gigs of data like this. INcrease the buffer size to 1MB or 3 MB , if you want to read faster.
Make sure you run this code in ThreadPool instead of user thread
You need to write it one chunk at a time by reading into a 4KB (or so) array and writing that to isolated storage until you run out of data.
Its a very weird thing.
I created a client and a server to upload and download files. When uploading I can upload a lot of files without a problem but when I download a file the client for turn to not responding and doesn't show MessageBox.show("Downloaded"); its the first tie to see this :D.
The code that make the problem when used :
private void button3_Click(object sender, EventArgs e)
{
try
{
String fileToDownload = filePathDownload.Text;
TcpClient clientSocket = new TcpClient(serverIPDownload.Text, 8880);
NetworkStream networkStream = clientSocket.GetStream();
ASCIIEncoding asci = new ASCIIEncoding();
byte[] b = asci.GetBytes(fileToDownload + "?");
byte[] bb = asci.GetBytes("Download?");
int thisRead = 0;
int blockSize = 1024;
Byte[] dataByte = new Byte[blockSize];
networkStream.Write(bb, 0, bb.Length);
networkStream.Flush();
networkStream.Write(b, 0, b.Length);
networkStream.Flush();
using (FileStream fileStream = new FileStream(
"C:/Users/Laptop/Documents/Downloads/" + fileToDownload,
FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
{
while (true)
{
thisRead = networkStream.Read(dataByte, 0, blockSize);
fileStream.Write(dataByte, 0, thisRead);
if (thisRead == 0) break;
}
MessageBox.Show("File Downloaded");
fileStream.Close();
}
}
catch (Exception ex) { MessageBox.Show(ex.Message); }
}
Thanks. This maybe off topic but its the problem I faced.
Your code appears to be ok, so I suspect the problem is in the Download method you are reading from.
Also, I would personally move the loop termination (if (thisRead == 0) break;) before the fileStream.Write statement.
And for production code, I would add some sort of timeout limit so that you don't end up in an infinite loop.
Using c#, I am downloading a file from a url the user enters on the phone. When it is writing the file to the IsolatedStorage, it is writing too many bytes to the file and therefore, the program used to open these files will not open.
When I debug, the bit size is 451,258 bytes, but when the file is exported from IsolatedStorage it is 454,656 bytes. It is filling the remaining space with spaces. Is there anyway to adjust this file size? Trim off the extra space at the end and save?
Forgive my ignorance as I am new at C# and WP7 developoment. I would really appreciate the help.
Here is my code :
public void readCompleteCallback(Object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
try
{
//string fileName = txtUrl.Text.Substring(txtUrl.Text.LastIndexOf("/") + 1).Trim();
string fileName = "DownloadedNZB.nzb";
bool isSpaceAvailable = IsSpaceIsAvailable(e.Result.Length);
if (isSpaceAvailable)
{
// Save mp3 to Isolated Storage
using (var isfs = new IsolatedStorageFileStream(fileName,
FileMode.CreateNew,
IsolatedStorageFile.GetUserStoreForApplication()))
{
long fileLen = e.Result.Length;
byte[] b = new byte[fileLen];
e.Result.Read(b, 0, b.Length);
isfs.Write(b, 0, b.Length);
isfs.Flush();
isfs.Close();
MessageBox.Show("File downloaded successfully");
}
}
else
{
MessageBox.Show("Not enough to save space available to download the file");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
else
{
MessageBox.Show(e.Error.Message);
}
}
Replace
e.Result.Read(b, 0, b.Length);
isfs.Write(b, 0, b.Length);
isfs.Flush();
isfs.Close();
with
var numberOfBytesRead = e.Result.Read(b, 0, b.Length);
isfs.Write(b, 0, numberOfBytesRead);
isfs.Flush();
isfs.Close();
I'm saving an image from a web request and something really weird is happening. On roughly half of the 8,000 images I'm downloading I get IOEXCEPTION errors:
ERROR_ACCESS_DENIED (5)
INVALID_PARAMETER (87)
Before I save the file using file.open, I check to make sure the file does not exist. The exception is thrown at this line of code:
fileStream = File.Open(destination, FileMode.Create, FileAccess.Write, FileShare.None);
Below is the code:
public static bool DownloadFile(string url, string destination)
{
bool success = false;
System.Net.HttpWebRequest request = null;
System.Net.WebResponse response = null;
Stream responseStream = null;
FileStream fileStream = null;
try
{
request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
request.Method = "GET";
request.Timeout = 100000; // 100 seconds
request.Proxy = System.Net.GlobalProxySelection.GetEmptyWebProxy();
response = request.GetResponse();
responseStream = response.GetResponseStream();
fileStream = File.Open(destination, FileMode.Create, FileAccess.Write, FileShare.None);
//fileStream = File.Create(destination);
// read up to ten kilobytes at a time
int maxRead = 10240;
byte[] buffer = new byte[maxRead];
int bytesRead = 0;
int totalBytesRead = 0;
// loop until no data is returned
while ((bytesRead = responseStream.Read(buffer, 0, maxRead)) > 0)
{
totalBytesRead += bytesRead;
fileStream.Write(buffer, 0, bytesRead);
}
// we got to this point with no exception. Ok.
success = true;
}
catch (System.Net.WebException we)
{
// something went terribly wrong.
success = false;
//MessageBox.Show(exp.ToString());
writeErrFile(we.ToString(), url);
//Debug.WriteLine(exp);
}
catch (System.IO.IOException ie)
{
// something went terribly wrong.
success = false;
//MessageBox.Show(ie.InnerException.ToString());
writeErrFile(ie.ToString(), destination + " -- " + url);
//Debug.WriteLine(exp);
}
catch (Exception exp)
{
// something went terribly wrong.
success = false;
//MessageBox.Show(exp.ToString());
writeErrFile(exp.ToString(), destination + " -- " + url);
//Debug.WriteLine(exp);
}
finally
{
// cleanup all potentially open streams.
if (null != responseStream)
responseStream.Close();
if (null != response)
response.Close();
if (null != fileStream)
fileStream.Close();
}
// if part of the file was written and the transfer failed, delete the partial file
if (!success && File.Exists(destination))
File.Delete(destination);
return success;
}
I've been stuck on this for a couple of days. Any help would be appreciated in unimaginable orders of magnitude.
Use file.exists() to check if the file exists and file.create or file.openwrite to write the file.
From your code I can't see how you are checking the file exists.