in an app I am making some of the files required are torrent files but i'm having an odd issue, whenever I download a torrent file through the app the files ends up corrupt and wont open in any torrent app, I used wptools to extract them to a pc and test it and still corrupt here is my code I can't see what 'im doing wrong, I am fairly new to using webclient. I assume it has something to do with the way im saving the file any help would be great thanks.
private void tbLink_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
string[] linkInfo = (sender as TextBlock).Tag as string[];
fileurl = linkInfo[0];
System.Diagnostics.Debug.WriteLine(fileurl);
WebClient client = new WebClient();
client.OpenReadCompleted += client_OpenReadCompleted;
client.OpenReadAsync(new Uri(fileurl), linkInfo);
client.AllowReadStreamBuffering = true;
}
async void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
string[] linkInfo = e.UserState as string[];
filetitle = linkInfo[1];
filesave = (filetitle);
var isolatedfile = IsolatedStorageFile.GetUserStoreForApplication();
using (IsolatedStorageFileStream stream = isolatedfile.OpenFile(filesave, System.IO.FileMode.Create))
{
byte[] buffer = new byte[e.Result.Length];
while (e.Result.Read(buffer, 0, buffer.Length) > 0)
{
stream.Write(buffer, 0, buffer.Length);
}
}
try
{
StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;
StorageFile torrentfile = await local.GetFileAsync(filesave);
Windows.System.Launcher.LaunchFileAsync(torrentfile);
}
catch (Exception)
{
MessageBox.Show("File Not Found");
}
This is incorrect:
byte[] buffer = new byte[e.Result.Length];
while (e.Result.Read(buffer, 0, buffer.Length) > 0)
{
stream.Write(buffer, 0, buffer.Length);
}
The Read method will return the number of bytes read, it can be less than buffer.Length. So the code should read:
int byteCount;
// Select an appropriate buffer size.
// This is a buffer, not space for the entire file.
byte[] buffer = new byte[4096];
while ((byteCount = e.Result.Read(buffer, 0, buffer.Length)) > 0)
{
stream.Write(buffer, 0, byteCount);
}
UPDATE: If the data is compressed, as in the question that you posted in your comment, then you can decompress the stream:
int byteCount;
byte[] buffer = new byte[4096];
using (GZipStream zs = new GZipStream(e.Result, CompressionMode.Decompress))
{
while ((byteCount = zs.Read(buffer, 0, buffer.Length)) > 0)
{
stream.Write(buffer, 0, byteCount);
}
}
Note that I have not tested this code, I'm assuming that e.Result is a stream.
Related
I made a button in WinForms to download file from FTP and it works fine but I don't understand what Stream.Read() method is doing in the while loop in the code below (in DownLoadFileFromFtp method):
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private static void DownloadFileFromFtp (string serverURI, string pathToLocalFile)
{
FileStream localFileStream = File.Open(pathToLocalFile, FileMode.OpenOrCreate);
FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create(serverURI);
ftpRequest.Method = WebRequestMethods.Ftp.DownloadFile;
ftpRequest.Credentials = new NetworkCredential("demo", "password");
WebResponse ftpResponse = ftpRequest.GetResponse();
Stream ftpResponseStream = ftpResponse.GetResponseStream();
byte[] buffer = new byte[2048];
Console.WriteLine($"\nBuffer length is: {buffer.Length}");
int bytesRead = ftpResponseStream.Read(buffer, 0, buffer.Length);
while(bytesRead > 0)
{
localFileStream.Write(buffer, 0, buffer.Length);
bytesRead = ftpResponseStream.Read(buffer, 0, buffer.Length);
}
localFileStream.Close();
ftpResponseStream.Close();
}
private void Form1_Load(object sender, EventArgs e)
{
if(NetworkInterface.GetIsNetworkAvailable())
{
toolStripStatusLabel1.Text = "Connected";
}
else
{
toolStripStatusLabel1.Text = "Disconnected";
}
}
private void DownloadFile_Click(object sender, EventArgs e)
{
DownloadFileFromFtp("ftp://test.rebex.net/pub/example/readme.txt", #"C:\Users\nstelmak\Downloads\testFile.txt");
}
}
Can anybody explain what this piece of code doing (bytesRead = ftpResponseStream.Read(buffer, 0, buffer.Length);) in a while loop? If I don use this piece of code then it seems like download is infinite and the file began to be bloated.
Thanks in advance!
Comments in code
// Take initial read. The return value is number of bytes you had read from the ftp stream.
// it is not guarantee what that number will be
int bytesRead = ftpResponseStream.Read(buffer, 0, buffer.Length);
// Now you need to keep reading until the return value is '0'. If you call
// stream.read() and got '0', it means that you came to the end of stream
while(bytesRead > 0)
{
localFileStream.Write(buffer, 0, buffer.Length);
// here you're going to keep reading bytes in the loop
// until you come to the end of stream and can't read no more
bytesRead = ftpResponseStream.Read(buffer, 0, buffer.Length);
}
When I send a file with the code below, some data (small amout) is missing. The file size doess not match on the receiver side. Sending a regular string is fine so theres no connection issue here. Im just looking for a minimal improvement to fix the issue, I will add error checking etc later. Thanks! The code is mostly copied from some tutorial but i dont remember which though...
Client is the std .Net TcpClient class
Client.Client is it's socket
public void SendFile2(string fileName)
{
using (FileStream fs = File.OpenRead(fileName))
{
byte[] lenBytes = BitConverter.GetBytes((int)fs.Length);
Client.Client.Send(lenBytes);
byte[] buffer = new byte[1024];
int bytesRead;
fs.Position = 0;
while ((bytesRead = fs.Read(buffer, 0, 1024)) > 0)
Client.Client.Send(buffer, bytesRead, SocketFlags.None);
}
}
public bool ReceiveFile2(string fileName)
{
using (FileStream fs = File.Create(fileName))
{
byte[] lenBytes = new byte[4];
if (Client.Client.Receive(lenBytes) < 4)
return false;
long len = BitConverter.ToInt32(lenBytes, 0);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = Client.Client.Receive(buffer)) > 0)
fs.Write(buffer, 0, bytesRead);
return len == fs.Position;
}
}
SOLUTION:
public void SendFile(string fileName)
{
using (FileStream fs = File.OpenRead(fileName))
{
byte[] lenBytes = BitConverter.GetBytes((int)fs.Length);
Client.Client.Send(lenBytes);
byte[] buffer = new byte[1024];
int bytesRead;
fs.Position = 0;
while ((bytesRead = fs.Read(buffer, 0, 1024)) > 0)
Client.Client.Send(buffer, bytesRead, SocketFlags.None);
}
}
public bool ReceiveFile(string fileName)
{
using (FileStream fs = File.Create(fileName))
{
byte[] lenBytes = new byte[4];
if (Client.Client.Receive(lenBytes) < 4)
return false;
long len = BitConverter.ToInt32(lenBytes, 0);
byte[] buffer = new byte[1024];
int bytesRead;
// Changed from here
while (fs.Position < len)
{
bytesRead = Client.Client.Receive(buffer);
fs.Write(buffer, 0, bytesRead);
}
// To here
return len == fs.Position;
}
}
I think this line can be a problem.
if (Client.Client.Receive(lenBytes) < 4)
and
while ((bytesRead = Client.Client.Receive(buffer)) > 0)
You have two receives in your code.
So you drop first bytes.
That can explain the differences you see in files sizes.
Help again please. I managed to upload a file from ASP.NET to my WCF service and it works like a charm. Now I want to do the same thing from WinRT without success. My file upload service is based on this post http://www.seesharpdot.net/?p=214. From ASP.NET I upload the file using this code
string filePath = Server.MapPath("~/Files/Happy.jpg");
string fileName = "Happy.jpg";
ServiceReference1.FileMetaData metadata = new ServiceReference1.FileMetaData();
metadata.LocalFilename = fileName;
metadata.FileType = ".jpg";
fileStream = new FileInfo(filePath).OpenRead();
oService.UploadFile(metadata, fileStream);
byte[] buffer = new byte[2048];
int bytesRead = fileStream.Read(buffer, 0, 2048);
while (bytesRead > 0)
{
fileStream.Write(buffer, 0, 2048);
bytesRead = fileStream.Read(buffer, 0, 2048);
}
From WinRT I thought this will work but it does not. No exception is thrown.
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
openPicker.FileTypeFilter.Add(".jpg");
openPicker.FileTypeFilter.Add(".jpeg");
openPicker.FileTypeFilter.Add(".png");
StorageFile file = await openPicker.PickSingleFileAsync();
if (file != null)
{
byte[] bytes = await GetByteFromFile(file);
await App.ServiceInstance.UploadFileAsync(bytes);
}
// This is the method to convert the StorageFile to a Byte[]
private async Task<byte[]> GetByteFromFile(StorageFile storageFile)
{
var stream = await storageFile.OpenReadAsync();
using (var dataReader = new DataReader(stream))
{
var bytes = new byte[stream.Size];
await dataReader.LoadAsync((uint)stream.Size);
dataReader.ReadBytes(bytes);
return bytes;
}
}
What is interesting is that my WCF Service method only accepts a byte array (byte[]) as parameter and ignores the messageContract. Do I need to change my WCF service? How would you recommend I go about to fix this? Any help appreciated.
My WCF Service:
public void UploadFile(FileUploadMessage request)
{
Stream fileStream = null;
Stream outputStream = null;
try
{
fileStream = request.FileByteStream;
string rootPath = HttpContext.Current.Server.MapPath("~\\Files"); ; // ConfigurationManager.AppSettings["RootPath"].ToString();
string newFileName = Path.Combine(rootPath, request.MetaData.LocalFileName);
outputStream = new FileInfo(newFileName).OpenWrite();
const int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int bytesRead = fileStream.Read(buffer, 0, bufferSize);
while (bytesRead > 0)
{
outputStream.Write(buffer, 0, bytesRead);
bytesRead = fileStream.Read(buffer, 0, bufferSize);
}
}
catch (IOException ex)
{
throw new FaultException<IOException>(ex, new FaultReason(ex.Message));
}
finally
{
if (fileStream != null)
{
fileStream.Close();
}
if (outputStream != null)
{
outputStream.Close();
}
}
}
I had to implement the same, but the WinRT generation of the library is different as to the one for desktop (Console application).
I had to take out Mtom in the binding, and leave the WCF service parameter as a Stream type.
This still allowed me to upload the document as required. However, on the service, i named the file to the md5 checksum value. The windows 8 app then sent another message to the service, with the parameter being the md5 checksum (calculated on the WinRt device) along with the file metadata. The WCF service then looked for the file with the md5 checksum and renamed the file.
So its a 2 step process from what I see as an immediate workaround, which I think i am happy with.
Happy to share the code for the md5 checksum on the service and WinRt side if required.
//convert photo to baos
var memoryStream = new System.IO.MemoryStream();
e.ChosenPhoto.CopyTo(memoryStream);
//string baos = memoryStream.ToString();
byte[] result = memoryStream.ToArray();
String base64 = System.Convert.ToBase64String(result);
String post_data = "&image=" + base64;
...
wc.UploadStringAsync(imgur_api,"POST",post_data);
I am using this code to upload an image to the Imgur API v3 using WebClient. The image being selected is either one of the 7 photos provided by the Windows Phone 7.1 emulator, or the simulated camera images. When I try to load the images, they are a largely-grey corrupted mess. Am I generating the base64 properly and/or do I need to render a Bitmap of the picture first before creating the byte[] and base64?
Thanks in advance!
Use something like Uri.EscapeDataString to escape the data so that special URL characters are not interpreted.
I use this
private void PhotoChooserTaskCompleted(object sender, PhotoResult e)
{
if (e.TaskResult != TaskResult.OK) return;
var bimg = new BitmapImage();
bimg.SetSource(e.ChosenPhoto);
var sbytedata = ReadToEnd(e.ChosenPhoto);
}
public static byte[] ReadToEnd(System.IO.Stream stream)
{
long originalPosition = stream.Position;
stream.Position = 0;
try
{
byte[] readBuffer = new byte[4096];
int totalBytesRead = 0;
int bytesRead;
while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
{
totalBytesRead += bytesRead;
if (totalBytesRead == readBuffer.Length)
{
int nextByte = stream.ReadByte();
if (nextByte != -1)
{
byte[] temp = new byte[readBuffer.Length * 2];
Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
readBuffer = temp;
totalBytesRead++;
}
}
}
byte[] buffer = readBuffer;
if (readBuffer.Length != totalBytesRead)
{
buffer = new byte[totalBytesRead];
Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
}
return buffer;
}
finally
{
stream.Position = originalPosition;
}
}
And upload byte[] to server. Hope it's help
I am trying to download a file to my computer and in the same time save it to Byte Array:
try
{
var req = (HttpWebRequest)HttpWebRequest.Create(url);
var fileStream = new FileStream(filePath,
FileMode.Create, FileAccess.Write, FileShare.Write);
using (var resp = req.GetResponse())
{
using (var stream = resp.GetResponseStream())
{
byte[] buffer = new byte[0x10000];
int len;
while ((len = stream.Read(buffer, 0, buffer.Length)) > 0)
{
//Do with the content whatever you want
// ***YOUR CODE***
MemoryStream memoryStream = new MemoryStream();
if (len > 0)
{
memoryStream.Write(buffer, 0, len);
len = stream.Read(buffer, 0, buffer.Length);
}
file = memoryStream.ToArray();
fileStream.Write(buffer, 0, len);
}
}
}
fileStream.Close();
}
catch (Exception exc) { }
And i noticed that it's not download all the file with this.
I wan to do it because i want to download a file and in the same time work with it.
Any idea why this problem happen?
There is a much easier way to get the file bytes by using the System.Net.WebClient.WebClient():
private static byte[] DownloadFile(string absoluteUrl)
{
using (var client = new System.Net.WebClient())
{
return client.DownloadData(absoluteUrl);
}
}
Usage:
var bytes = DownloadFile(absoluteUrl);
The problem looks to be double-reading - you are putting different things into the memory-stream / file-stream - it should be more like:
// declare file/memory stream here
while ((len = stream.Read(buffer, 0, buffer.Length)) > 0)
{
memoryStream.Write(buffer, 0, len);
fileStream.Write(buffer, 0, len);
// if you need to process "len" bytes, do it here
}
You might be able to lose "memoryStream" completely if you are processing the "len" bytes immediately. If it fits in-memory, it may be easier to just use WebClient.DownloadData and then File.WriteAllBytes.