How do I programmatically save an image from a URL? I am using C# and need to be able grab images from a URL and store them locally. ...and no, I am not stealing :)
It would be easier to write something like this:
WebClient webClient = new WebClient();
webClient.DownloadFile(remoteFileUrl, localFileName);
You just need to make a basic http request using HttpWebRequest for the URI of the image then grab the resulting byte stream then save that stream to a file.
Here is an example on how to do this...
'As a side note if the image is very large you may want to break up br.ReadBytes(500000) into a loop and grab n bytes at a time writing each batch of bytes as you retrieve them.'
using System;
using System.IO;
using System.Net;
using System.Text;
namespace ImageDownloader
{
class Program
{
static void Main(string[] args)
{
string imageUrl = #"http://www.somedomain.com/image.jpg";
string saveLocation = #"C:\someImage.jpg";
byte[] imageBytes;
HttpWebRequest imageRequest = (HttpWebRequest)WebRequest.Create(imageUrl);
WebResponse imageResponse = imageRequest.GetResponse();
Stream responseStream = imageResponse.GetResponseStream();
using (BinaryReader br = new BinaryReader(responseStream ))
{
imageBytes = br.ReadBytes(500000);
br.Close();
}
responseStream.Close();
imageResponse.Close();
FileStream fs = new FileStream(saveLocation, FileMode.Create);
BinaryWriter bw = new BinaryWriter(fs);
try
{
bw.Write(imageBytes);
}
finally
{
fs.Close();
bw.Close();
}
}
}
}
An example in aspx (c#)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Net;
using System.IO;
public partial class download_file_from_url : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string url = "http://4rapiddev.com/wp-includes/images/logo.jpg";
string file_name = Server.MapPath(".") + "\\logo.jpg";
save_file_from_url(file_name, url);
Response.Write("The file has been saved at: " + file_name);
}
public void save_file_from_url(string file_name, string url)
{
byte[] content;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
WebResponse response = request.GetResponse();
Stream stream = response.GetResponseStream();
using (BinaryReader br = new BinaryReader(stream))
{
content = br.ReadBytes(500000);
br.Close();
}
response.Close();
FileStream fs = new FileStream(file_name, FileMode.Create);
BinaryWriter bw = new BinaryWriter(fs);
try
{
bw.Write(content);
}
finally
{
fs.Close();
bw.Close();
}
}
}
Author: HOAN HUYNH
ASP.Net C# Download Or Save Image File From URL
My solution is pre save the image to de disk and then usa as a normal saved image:
remoteFile = "http://xxx.yyy.com/image1.png";
localFile = "c:\myimage.png";
WebClient webClient = new WebClient();
webClient.DownloadFile(remoteFile, localFile);
Related
I have a dlm file and I want to create a .tar.gz file from the content in dlm file. When I am trying to create the file, it is created but when I manually unzip that it is failed. My code is below for creating .tar.gz file, targetFileName is like C:\Folder\xxx.tar.gz:
using (StreamWriter write = new StreamWriter(targetFileName, false, Encoding.Default))
{
write.Write(text.ToString());
write.Close();
}
In the above code text is content from dlm file. Is there anything that I am missing? please help.
try use SharpZipLib from Nuget
using System;
using System.IO;
using System.Text;
using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.Tar;
add method:
private static void CreateTarGZ(string tgzFilename, string innerFilename, string text)
{
var uncompressed = Encoding.UTF8.GetBytes(text);
using (Stream outStream = File.Create(tgzFilename))
{
using (GZipOutputStream gzoStream = new GZipOutputStream(outStream))
{
gzoStream.SetLevel(9);
using (TarOutputStream taroStream = new TarOutputStream(gzoStream, Encoding.UTF8))
{
taroStream.IsStreamOwner = false;
TarEntry entry = TarEntry.CreateTarEntry(innerFilename);
entry.Size = uncompressed.Length;
taroStream.PutNextEntry(entry);
taroStream.Write(uncompressed, 0, uncompressed.Length);
taroStream.CloseEntry();
taroStream.Close();
}
}
}
}
then call:
CreateTarGZ("test.tar.gz", "FileName.txt", "my text");
CreateTarGZ("c:\\temp\\test.tar.gz", "foo-folder\\FileName.txt", "my text");
This is a quick example to create a .tar.gz and .gz file that will include the file that you might be creating using the stream.
Note that I'm using SharpZipLib which you can find in Nuget Package Manager for you project. Then make sure to add reference in your code:
Making tar.gz
using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.Tar;
using System.IO;
using System.Text;
static void Main(string[] args)
{
string text = ".Net is Awesome";
string filename = "D:\\text.txt";
string tarfilename = "D:\\text.tar.gz";
using (StreamWriter write = new StreamWriter(filename, false, Encoding.Default))
{
//Writing a text file
write.Write(text.ToString());
write.Close();
//Creating a tar.gz Stream
Stream TarFileStream = File.Create(tarfilename);
Stream GZStream = new GZipOutputStream(TarFileStream);
TarArchive tarArchive = TarArchive.CreateOutputTarArchive(GZStream);
tarArchive.RootPath = "D:/"; //Setting the Root Path for the archive
//Creating a file entry for the tar archive
TarEntry tarEntry = TarEntry.CreateEntryFromFile(filename);
//Writing the entry in the archive.
tarArchive.WriteEntry(tarEntry, false); //set false to only add the concerned file in the archive.
tarArchive.Close();
}
}
Making only .gz
You can create a method to make it more reusable like:
private static void MakeGz(string targetFile)
{
string TargetGz = targetFile + ".gz";
using (Stream GzStream = new GZipOutputStream(File.Create(TargetGz)))
{
using (FileStream fs = File.OpenRead(targetFile))
{
byte[] FileBuffer = new byte[fs.Length];
fs.Read(FileBuffer, 0, (int)fs.Length);
GzStream.Write(FileBuffer, 0, FileBuffer.Length);
fs.Close();
GzStream.Close();
}
}
}
Then you can call this method whenever you are creating a file to make an archive for the same at the same time like:
MakeGz(filename);
I try to send by FTP one .zip file. First I take one .txt file and added to archive .zip.
When I try to send this file everything is OK. But when a file is coming on the machine and I want to uncompress the .zip file is broken.
On the sender machine .zip file is OK. Only on the ftp machine is broken.
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
namespace SEND_Plovdiv
{
public class WebRequestGetExample
{
public static void Main()
{
string[] lineOfContents = File.ReadAllLines(#"C:\\M\send.txt");
string username = "";
string password = "";
foreach (var line in lineOfContents)
{
string[] tokens = line.Split(',');
string user = tokens[0];
string pass = tokens[1];
username = user;
password = pass;
}
string pathFile = #"C:\M\Telegrami\";
string zipPath = #"C:\M\Plovdiv.zip";
if (File.Exists(zipPath))
{
File.Delete(zipPath);
}
ZipFile.CreateFromDirectory(pathFile, zipPath, CompressionLevel.Fastest, false);
// Get the object used to communicate with the server.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://199.199.199.199/Plovdiv.zip");
request.Method = WebRequestMethods.Ftp.UploadFile;
// This example assumes the FTP site uses anonymous logon.
request.Credentials = new NetworkCredential(username, password);
// Copy the contents of the file to the request stream.
StreamReader sourceStream = new StreamReader(#"C:\M\Plovdiv.zip");
byte[] fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
sourceStream.Close();
request.ContentLength = fileContents.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(fileContents, 0, fileContents.Length);
requestStream.Close();
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Console.WriteLine("Upload File Complete, status {0}", response.StatusDescription);
Console.ReadKey();
response.Close();
}
}
}
I dont know what exactly do this part of code:
StreamReader sourceStream = new StreamReader(#"C:\M\Plovdiv.zip");
Switch from using the StreamReader to BinaryReader. Zip files are binary files not UTF8.
Here's a sample:
using (FileStream fs = File.Open(#"c:\1.bin",FileMode.Open))
{
byte[] data = new BinaryReader(fs).ReadBytes((int)fs.Length);
Encoding.getstring....
}
StreamReader vs BinaryReader?
Can I extract the ZIP file in FTP and place this extracted file on the same location using C#?
It's not possible.
There's no API in the FTP protocol to un-ZIP a file on a server.
Though, it's not uncommon that one, in addition to an FTP access, have also an SSH access. If that's the case, you can connect with the SSH and execute the unzip shell command (or similar) on the server to decompress the files.
See C# send a simple SSH command.
If you need, you can then download the extracted files using the FTP protocol (Though if you have the SSH access, you will also have an SFTP access. Then, use the SFTP instead of the FTP.).
Some (very few) FTP servers offer an API to execute an arbitrary shell (or other) commands using the SITE EXEC command (or similar). But that's really very rare. You can use this API the same way as the SSH above.
If you want to download and unzip the file locally, you can do it in-memory, without storing the ZIP file to physical (temporary) file. For an example, see How to import data from a ZIP file stored on FTP server to database in C#.
Download via FTP to MemoryStream, then you can unzip, example shows how to get stream, just change to MemoryStream and unzip. Example doesn't use MemoryStream but if you are familiar with streams it should be trivial to modify these two examples to work for you.
example from: https://learn.microsoft.com/en-us/dotnet/framework/network-programming/how-to-download-files-with-ftp
using System;
using System.IO;
using System.Net;
using System.Text;
namespace Examples.System.Net
{
public class WebRequestGetExample
{
public static void Main ()
{
// Get the object used to communicate with the server.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://www.contoso.com/test.htm");
request.Method = WebRequestMethods.Ftp.DownloadFile;
// This example assumes the FTP site uses anonymous logon.
request.Credentials = new NetworkCredential ("anonymous","janeDoe#contoso.com");
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
Console.WriteLine(reader.ReadToEnd());
Console.WriteLine("Download Complete, status {0}", response.StatusDescription);
reader.Close();
response.Close();
}
}
}
decompress stream, example from: https://learn.microsoft.com/en-us/dotnet/standard/io/how-to-compress-and-extract-files
using System;
using System.IO;
using System.IO.Compression;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
using (FileStream zipToOpen = new FileStream(#"c:\users\exampleuser\release.zip", FileMode.Open))
{
using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update))
{
ZipArchiveEntry readmeEntry = archive.CreateEntry("Readme.txt");
using (StreamWriter writer = new StreamWriter(readmeEntry.Open()))
{
writer.WriteLine("Information about this package.");
writer.WriteLine("========================");
}
}
}
}
}
}
here is a working example of downloading zip file from ftp, decompressing that zip file and then uploading the compressed files back to the same ftp directory
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Text;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string location = #"ftp://localhost";
byte[] buffer = null;
using (MemoryStream ms = new MemoryStream())
{
FtpWebRequest fwrDownload = (FtpWebRequest)WebRequest.Create($"{location}/test.zip");
fwrDownload.Method = WebRequestMethods.Ftp.DownloadFile;
fwrDownload.Credentials = new NetworkCredential("anonymous", "janeDoe#contoso.com");
using (FtpWebResponse response = (FtpWebResponse)fwrDownload.GetResponse())
using (Stream stream = response.GetResponseStream())
{
//zipped data stream
//https://stackoverflow.com/a/4924357
byte[] buf = new byte[1024];
int byteCount;
do
{
byteCount = stream.Read(buf, 0, buf.Length);
ms.Write(buf, 0, byteCount);
} while (byteCount > 0);
//ms.Seek(0, SeekOrigin.Begin);
buffer = ms.ToArray();
}
}
//include System.IO.Compression AND System.IO.Compression.FileSystem assemblies
using (MemoryStream ms = new MemoryStream(buffer))
using (ZipArchive archive = new ZipArchive(ms, ZipArchiveMode.Update))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
FtpWebRequest fwrUpload = (FtpWebRequest)WebRequest.Create($"{location}/{entry.FullName}");
fwrUpload.Method = WebRequestMethods.Ftp.UploadFile;
fwrUpload.Credentials = new NetworkCredential("anonymous", "janeDoe#contoso.com");
byte[] fileContents = null;
using (StreamReader sr = new StreamReader(entry.Open()))
{
fileContents = Encoding.UTF8.GetBytes(sr.ReadToEnd());
}
if (fileContents != null)
{
fwrUpload.ContentLength = fileContents.Length;
try
{
using (Stream requestStream = fwrUpload.GetRequestStream())
{
requestStream.Write(fileContents, 0, fileContents.Length);
}
}
catch(WebException e)
{
string status = ((FtpWebResponse)e.Response).StatusDescription;
}
}
}
}
}
}
}
If you're trying to unzip the files in place after they have been ftp uploaded, you will need to run a server side script with proper permissions that can be fired from within your c# application, or c# ssh as already described earlier.
On my website, when a user clicks a certain button, a bunch of files have to be archived in a zip and sent out. The files themselves are generated by a third part and I only have the URLs.
I have partly succeeded in that, but I have some issues.
First, if there are a lot of files to zip, the server response is slow as it first builds the zip file, then sends it. It can even crash after a while (notably, I get the error "Overflow or underflow in the arithmetic operation.").
Second, right now the file only gets sent once the zip archive is complete. I would like the download to begin immediately instead. That is to say, as soon as the user has clicked "save" from the dialog, data begins sending and it keeps sending as the zip file is being created "on the fly". I have seen that feature on some websites, for example : http://download.muuto.com/
Problem is, I can't figure out how to do that.
I have used parts of code from this question : Creating a dynamic zip of a bunch of URLs on the fly
And from this blog post : http://dejanstojanovic.net/aspnet/2015/march/generate-zip-file-on-the-fly-in-aspnet-mvc-application/
The zip file itself is created and returned in an ASP.NET MVC Controller method. Here is my code :
using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
namespace MyProject.Controllers
{
public class MyController : Controller
{
public ActionResult DownloadFiles()
{
var files = SomeFunction();
byte[] buffer = new byte[4096];
var baseOutputStream = new MemoryStream();
ZipOutputStream zipOutputStream = new ZipOutputStream(baseOutputStream);
zipOutputStream.SetLevel(0); //0-9, 9 being the highest level of compression
zipOutputStream.UseZip64 = UseZip64.Off;
zipOutputStream.IsStreamOwner = false;
foreach (var file in files)
{
using (WebClient wc = new WebClient())
{
// We open the download stream of the file
using (Stream wcStream = wc.OpenRead(file.Url))
{
ZipEntry entry = new ZipEntry(ZipEntry.CleanName(file.FileName));
zipOutputStream.PutNextEntry(entry);
// As we read the stream, we add its content to the new zip entry
int count = wcStream.Read(buffer, 0, buffer.Length);
while (count > 0)
{
zipOutputStream.Write(buffer, 0, count);
count = wcStream.Read(buffer, 0, buffer.Length);
if (!Response.IsClientConnected)
{
break;
}
}
}
}
}
zipOutputStream.Finish();
zipOutputStream.Close();
// Set position to 0 so that cient start reading of the stream from the begining
baseOutputStream.Position = 0;
// Set custom headers to force browser to download the file instad of trying to open it
return new FileStreamResult(baseOutputStream, "application/x-zip-compressed")
{
FileDownloadName = "Archive.zip"
};
}
}
}
Ok by fiddling a bit with the response outputstream and buffering, I've arrived to a solution :
using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
namespace MyProject.Controllers
{
public class MyController : Controller
{
public ActionResult DownloadFiles()
{
var files = SomeFunction();
// Disable Buffer Output to start the download immediately
Response.BufferOutput = false;
// Set custom headers to force browser to download the file instad of trying to open it
Response.ContentType = "application/x-zip-compressed";
Response.AppendHeader("content-disposition", "attachment; filename=Archive.zip");
byte[] buffer = new byte[4096];
ZipOutputStream zipOutputStream = new ZipOutputStream(Response.OutputStream);
zipOutputStream.SetLevel(0); // No compression
zipOutputStream.UseZip64 = UseZip64.Off;
zipOutputStream.IsStreamOwner = false;
try
{
foreach (var file in files)
{
using (WebClient wc = new WebClient())
{
// We open the download stream of the image
using (Stream wcStream = wc.OpenRead(file.Url))
{
ZipEntry entry = new ZipEntry(ZipEntry.CleanName(file.FileName));
zipOutputStream.PutNextEntry(entry);
// As we read the stream, we add its content to the new zip entry
int count = wcStream.Read(buffer, 0, buffer.Length);
while (count > 0)
{
zipOutputStream.Write(buffer, 0, count);
count = wcStream.Read(buffer, 0, buffer.Length);
if (!Response.IsClientConnected)
{
break;
}
}
}
}
}
}
finally
{
zipOutputStream.Finish();
zipOutputStream.Close();
}
return new HttpStatusCodeResult(HttpStatusCode.OK);
}
}
}
I'm trying to use a local c# app to pull some images off a website to files on my local machine. I'm using the code listed below. I've tried both ASCII encoding and UTF8 encoding but the final file is not an correct. Does anyone see what I'm doing wrong? The url is active and correct and show the image just fine when I put the address in my browser.
private void button1_Click(object sender, EventArgs e)
{
HttpWebRequest lxRequest = (HttpWebRequest)WebRequest.Create("http://www.productimageswebsite.com/images/stock_jpgs/34891.jpg");
// returned values are returned as a stream, then read into a string
String lsResponse = string.Empty;
HttpWebResponse lxResponse = (HttpWebResponse)lxRequest.GetResponse();
using (StreamReader lxResponseStream = new StreamReader(lxResponse.GetResponseStream()))
{
lsResponse = lxResponseStream.ReadToEnd();
lxResponseStream.Close();
}
byte[] lnByte = System.Text.UTF8Encoding.UTF8.GetBytes(lsResponse);
System.IO.FileStream lxFS = new FileStream("34891.jpg", FileMode.Create);
lxFS.Write(lnByte, 0, lnByte.Length);
lxFS.Close();
MessageBox.Show("done");
}
nice image :D
try using the following code:
you needed to use a BinaryReader, 'cause an image file is binary data and thus not encoded in UTF or ASCII
edit: using'ified
HttpWebRequest lxRequest = (HttpWebRequest)WebRequest.Create(
"http://www.productimageswebsite.com/images/stock_jpgs/34891.jpg");
// returned values are returned as a stream, then read into a string
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);
using (FileStream lxFS = new FileStream("34891.jpg", FileMode.Create)) {
lxFS.Write(lnByte, 0, lnByte.Length);
}
}
}
MessageBox.Show("done");
Okay, here's the final answer. It uses a memorystream as a way to buffer the data from the reaponsestream.
private void button1_Click(object sender, EventArgs e)
{
byte[] lnBuffer;
byte[] lnFile;
HttpWebRequest lxRequest = (HttpWebRequest)WebRequest.Create("http://www.productimageswebsite.com/images/stock_jpgs/34891.jpg");
using (HttpWebResponse lxResponse = (HttpWebResponse)lxRequest.GetResponse())
{
using (BinaryReader lxBR = new BinaryReader(lxResponse.GetResponseStream()))
{
using (MemoryStream lxMS = new MemoryStream())
{
lnBuffer = lxBR.ReadBytes(1024);
while (lnBuffer.Length > 0)
{
lxMS.Write(lnBuffer, 0, lnBuffer.Length);
lnBuffer = lxBR.ReadBytes(1024);
}
lnFile = new byte[(int)lxMS.Length];
lxMS.Position = 0;
lxMS.Read(lnFile, 0, lnFile.Length);
}
}
}
using (System.IO.FileStream lxFS = new FileStream("34891.jpg", FileMode.Create))
{
lxFS.Write(lnFile, 0, lnFile.Length);
}
MessageBox.Show("done");
}
A variation of the answer, using async await for async file I/O. See Async File I/O on why this is important.
Download png and write to disk using BinaryReader/Writer
string outFile = System.IO.Path.Combine(outDir, fileName);
// Download file
var request = (HttpWebRequest) WebRequest.Create(imageUrl);
using (var response = await request.GetResponseAsync()){
using (var reader = new BinaryReader(response.GetResponseStream())) {
// Read file
Byte[] bytes = async reader.ReadAllBytes();
// Write to local folder
using (var fs = new FileStream(outFile, FileMode.Create)) {
await fs.WriteAsync(bytes, 0, bytes.Length);
}
}
}
Read all bytes extension method
public static class Extensions {
public static async Task<byte[]> ReadAllBytes(this BinaryReader reader)
{
const int bufferSize = 4096;
using (var ms = new MemoryStream())
{
byte[] buffer = new byte[bufferSize];
int count;
while ((count = reader.Read(buffer, 0, buffer.Length)) != 0) {
await ms.WriteAsync(buffer, 0, count);
}
return ms.ToArray();
}
}
}
You can use the following method to download an image from a web site and save it, using the Image class:
WebRequest req = WebRequest.Create(imageUrl);
WebResponse resp = req.GetResponse();
Image img = Image.FromStream(resp.GetResponseStream());
img.Save(filePath + fileName + ".jpg");