I need to download a file attached to a URL using C# and I have written this piece of code:
var uri = new Uri("http://members.tsetmc.com/tsev2/excel/MarketWatchPlus.aspx?d=0");
var request = WebRequest.CreateHttp(uri);
var response = request.GetResponse();
string disposition = response.Headers["Content-Disposition"];
string filename = disposition.Substring(disposition.IndexOf("filename=") + 9).Replace("\"", "");
using (var fs = new FileStream(filename.Replace("/", "-"), FileMode.Create, FileAccess.Write, FileShare.None))
{
response.GetResponseStream().CopyTo(fs);
}
But the excel file saved in the path seems to be corrupted
I get a forbidden back when trying to call your URL. In my example I have used a different URL which is working fine.
var request = WebRequest.CreateHttp("http://spreadsheetpage.com/downloads/xl/king-james-bible.xlsm");
var response = request.GetResponse();
using (var fs = new FileStream("king-james-bible.xlsm", FileMode.Create, FileAccess.Write, FileShare.None))
{
using (var stream = response.GetResponseStream())
{
stream.CopyTo(fs);
}
}
Could it be that the file your retrieving itself is corrupt?
Updated based on the new information
Okay the link is now working for me. Your problem is that the Excel file is sent using a gzip encoding. The code sample below works with your URL.
var request = WebRequest.CreateHttp("http://members.tsetmc.com/tsev2/excel/MarketWatchPlus.aspx?d=0");//"http://spreadsheetpage.com/downloads/xl/king-james-bible.xlsm");
var response = request.GetResponse();
string disposition = response.Headers["Content-Disposition"];
string filename = disposition.Substring(disposition.IndexOf("filename=") + 9).Replace("\"", "");
using (var fs = new FileStream(filename.Replace("/", "-"), FileMode.Create, FileAccess.Write, FileShare.None))
{
using (var stream = response.GetResponseStream())
{
using (GZipStream zipStream = new GZipStream(stream, CompressionMode.Decompress))
{
byte[] tempBytes = new byte[4096];
int i;
while ((i = zipStream.Read(tempBytes, 0, tempBytes.Length)) != 0)
{
fs.Write(tempBytes, 0, i);
}
}
}
}
I have used the info from this post for the gzip decoding: How do you download and extract a gzipped file with C#?
Related
I'm not sure where and what am I doing wrong, but the zip that I'm creating using DotNetZip library, is creating a zip file whose contents are blank. Or the size of file in zip is showing as 0Kb and unable to open it.
Code:
public static async Task DotNetZipFileAsync(MemoryStream stream, string bucket, List<List<string>> pdfFileSet, IAmazonS3 s3Client)
{
using Ionic.Zip.ZipFile zip = new ZipFile();
foreach (var pdfFile in pdfFileSet)
{
foreach (var file in pdfFile)
{
GetObjectRequest request = new GetObjectRequest
{
BucketName = bucket,
Key = file
};
using GetObjectResponse response = await s3Client.GetObjectAsync(request);
using Stream responseStream = response.ResponseStream;
ZipEntry zipEntry = zip.AddEntry(file.Split('/')[^1], responseStream);
await responseStream.CopyToAsync(stream);
}
}
zip.Save(stream);
stream.Seek(0,SeekOrigin.Begin);
await stream.CopyToAsync(new FileStream(#"C:\LocalRepo\Temp.zip", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite));
}
}
}
Your code has at least two problems:
The read stream is completely consumed by the await responseStream.CopyToAsync(stream). You could rewind the responseStream to cope with this, but saving the data into the memory stream is completely useless.
The response stream is disposed before zip.Save is called.
What you could do: keep the streams open until Save is called and dispose them afterwards. As Alexey Rumyantsev discovered (see comments), also the GetObjectResponse objects need to be kept until the ZIP file is saved.
using Ionic.Zip.ZipFile zip = new ZipFile();
var disposables = List<IDisposable>();
try
{
foreach (var pdfFile in pdfFileSet)
{
foreach (var file in pdfFile)
{
GetObjectRequest request = new GetObjectRequest
{
BucketName = bucket,
Key = file
};
var response = await s3Client.GetObjectAsync(request);
disposables.Add(response);
var responseStream = response.ResponseStream;
disposables.Add(responseStream);
ZipEntry zipEntry = zip.AddEntry(file.Split('/')[^1], responseStream);
}
}
using var fileStream = new FileStream(#"C:\LocalRepo\Temp.zip", FileMode.Create, FileAccess.Write);
zip.Save(fileStream);
}
finally
{
foreach (var disposable in disposables)
{
disposable.Dispose();
}
}
The documentation has some hints ony how this could be made smarter.
public static async Task DotNetZipFileAsync(string bucket, List<List<string>> pdfFileSet, IAmazonS3 s3Client)
{
int read;
using Ionic.Zip.ZipFile zip = new ZipFile();
byte[] buffer = new byte[16 * 1024];
foreach (var pdfFile in pdfFileSet)
{
foreach (var file in pdfFile)
{
GetObjectRequest request = new GetObjectRequest
{
BucketName = bucket,
Key = file
};
using GetObjectResponse response = await s3Client.GetObjectAsync(request);
using Stream responseStream = response.ResponseStream;
using (MemoryStream ms = new MemoryStream())
{
while ((read = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
zip.AddEntry(file.Split('/')[^1], ms.ToArray());
}
}
}
using var fileStream = new FileStream(#"C:\LocalRepo\Temp.zip", FileMode.Create, FileAccess.Write);
zip.Save(fileStream);
}
I have built an asp net web api. I need to return a zipfile, as a result of some inner logic. I'm using this code and it works, but the resulting zip file, when unzipped manually, gave me this error "There are data after the end of the payload"
using (ZipFile zip = new ZipFile())
{
...
zip.Save(di.FullName + "\\" + "Update.zip");
}
string path = Path.Combine(Properties.Settings.Default.PathDisposizioniHTML, "Update.zip");
var response = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new System.IO.FileStream(path, System.IO.FileMode.Open);
response.Content = new StreamContent(stream);
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
This is how i receive the data in a .net console application:
using (Stream output = File.OpenWrite(#"C:\prova\MyFile.zip"))
using (Stream input = httpResponse.GetResponseStream())
{
input.CopyTo(output);
}
If you already have the zip file on your system, you shouldn't need to do anything special before sending it as a response.
This should work:
string filePath = #"C:\myfolder\myfile.zip";
return File(filePath, "application/zip");
If you're making the file on the fly, i.e. getting other files and programatically putting them into a zip file for the user, the following should work:
public IActionResult GetZipFile(){
//location of the file you want to compress
string filePath = #"C:\myfolder\myfile.ext";
//name of the zip file you will be creating
string zipFileName = "zipFile.zip";
byte[] result;
using (MemoryStream zipArchiveMemoryStream = new MemoryStream())
{
using (ZipArchive zipArchive = new ZipArchive(zipArchiveMemoryStream, ZipArchiveMode.Create, true))
{
ZipArchiveEntry zipEntry = zipArchive.CreateEntry(zipFileName);
using (Stream entryStream = zipEntry.Open())
{
using (MemoryStream tmpMemory = new MemoryStream(System.IO.File.ReadAllBytes(filePath)))
{
tmpMemory.CopyTo(entryStream);
};
}
}
zipArchiveMemoryStream.Seek(0, SeekOrigin.Begin);
result = zipArchiveMemoryStream.ToArray();
}
return File(result, "application/zip", zipFileName);
}
This is taken from a recent ASP.NET project of my own.
I am trying to save the byte array to a file. File contents are not being saved to that file.
HttpWebRequest lxRequest = (HttpWebRequest)WebRequest.Create("imageurl");
String lsResponse = string.Empty;
using (HttpWebResponse lxResponse = (HttpWebResponse)lxRequest.GetResponse())
{
using (BinaryReader reader = new BinaryReader(lxResponse.GetResponseStream()))
{
Byte[] lnByte = reader.ReadBytes(1 * 1024 * 1024 * 10);
String path = Application.StartupPath + "\\abc.jpg";
File.WriteAllBytes(path, lnByte);
}
}
Am i missing something here ?
using (Stream response = lxResponse.GetResponseStream())
using (FileStream fs = new FileStream(fileName, FileMode.CreateNew, FileAccess.Write, FileShare.Read))
{
response.CopyTo(fs);
}
Using several examples here on StackOverflow I thought the following code would decompress a gzip file then read the memory-stream and write it's content to the console. No errors occur but I get no output.
public static void Decompress(FileInfo fileToDecompress)
{
using (FileStream originalFileStream = fileToDecompress.OpenRead())
{
string currentFileName = fileToDecompress.FullName;
string newFileName = currentFileName.Remove(currentFileName.Length - fileToDecompress.Extension.Length);
using (FileStream decompressedFileStream = File.Create(newFileName))
{
using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress))
{
MemoryStream memStream = new MemoryStream();
memStream.SetLength(decompressedFileStream.Length);
decompressedFileStream.Read(memStream.GetBuffer(), 0, (int)decompressedFileStream.Length);
memStream.Position = 0;
var sr = new StreamReader(memStream);
var myStr = sr.ReadToEnd();
Console.WriteLine("Stream Output: " + myStr);
}
}
}
}
You are trying to copy an empty stream. "decompressedFileStream" is created by File.Create(), so it's empty. Swap "decompressedFileStream" to "decompressionStream" and you will be able to see your file content into "myStr".
public static void Decompress(FileInfo fileToDecompress)
{
using (FileStream originalFileStream = fileToDecompress.OpenRead())
{
string currentFileName = fileToDecompress.FullName;
string newFileName = currentFileName.Remove(currentFileName.Length - fileToDecompress.Extension.Length);
using (FileStream decompressedFileStream = File.Create(newFileName))
{
using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress))
{
MemoryStream memStream = new MemoryStream();
//memStream.SetLength(decompressedFileStream.Length); not necessary
decompressionStream.CopyTo(memStream);
memStream.Seek(0, SeekOrigin.Begin);
var sr = new StreamReader(memStream);
var myStr = sr.ReadToEnd();
Console.WriteLine("Stream Output: " + myStr);
}
}
}
}
Try this snippets. I use CopyTo instead of Read to copy the data to the memory stream and I use Seek() method instead of Position to return at the start of the memory stream.
I am trying to do this using C#(Winforms).
The code I am using is giving me a string as an output, but I need to have a zipped file.
I am using the following code
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(
"ftp:SITENAME/FILENAME.zip");
request.Method = WebRequestMethods.Ftp.DownloadFile;
// This example assumes the FTP site uses anonymous logon.
request.Credentials = new NetworkCredential("", "");
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
//StreamWriter writer = new StreamWriter(responseStream);
MessageBox.Show(reader.ReadtoEnd);
MessageBox.Show("Download Complete, status {0}" + response.StatusCode);
reader.Close();
response.Close();
}
catch (NotSupportedException ne)
{
MessageBox.Show(ne.Message);
}
I have an idea that I have to use Open source library from SharpZipLib to convert this string to a zipped file. But,I cannot find any sample code to show me how to do that.
I would really appreciate if someone can guide me through the process.
Thanks,
Sidhanshu
This might do just that.
using ICSharpCode.SharpZipLib.BZip2;
public static string Unzip(byte[] compressedbytes)
{
string result;
MemoryStream m_msBZip2 = null;
BZip2InputStream m_isBZip2 = null;
m_msBZip2 = new MemoryStream(compressedbytes);
// read final uncompressed string size stored in first 4 bytes
using (BinaryReader reader = new BinaryReader(m_msBZip2, System.Text.Encoding.ASCII))
{
Int32 size = reader.ReadInt32();
m_isBZip2 = new BZip2InputStream(m_msBZip2);
byte[] bytesUncompressed = new byte[size];
m_isBZip2.Read(bytesUncompressed, 0, bytesUncompressed.Length);
m_isBZip2.Close();
m_msBZip2.Close();
result = Encoding.ASCII.GetString(bytesUncompressed, 0, bytesUncompressed.Length);
reader.Close();
}
return result;
}
public static byte[] Zip(string sBuffer)
{
byte[] result;
using (MemoryStream m_msBZip2 = new MemoryStream())
{
Int32 size = sBuffer.Length;
// Prepend the compressed data with the length of the uncompressed data (firs 4 bytes)
using (BinaryWriter writer = new BinaryWriter(m_msBZip2, System.Text.Encoding.ASCII))
{
writer.Write(size);
using (BZip2OutputStream m_osBZip2 = new BZip2OutputStream(m_msBZip2))
{
m_osBZip2.Write(Encoding.ASCII.GetBytes(sBuffer), 0, sBuffer.Length);
m_osBZip2.Close();
}
writer.Close();
result = m_msBZip2.ToArray();
m_msBZip2.Close();
}
}
return result;
}