FileUpload to FileStream - c#

I am in process of sending the file along with HttpWebRequest. My file will be from FileUpload UI. Here I need to convert the File Upload to filestream to send the stream along with HttpWebRequest. How do I convert the FileUpload to a filestream?

Since FileUpload.PostedFile.InputStream gives me Stream, I used the following code to convert it to byte array
public static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[input.Length];
//byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}

Might be better to pipe the input stream directly to the output stream:
inputStream.CopyTo(outputStream);
This way, you are not caching the entire file in memory before re-transmission. For example, here is how you would write it to a FileStream:
FileUpload fu; // Get the FileUpload object.
using (FileStream fs = File.OpenWrite("file.dat"))
{
fu.PostedFile.InputStream.CopyTo(fs);
fs.Flush();
}
If you wanted to write it directly to another web request, you could do the following:
FileUpload fu; // Get the FileUpload object for the current connection here.
HttpWebRequest hr; // Set up your outgoing connection here.
using (Stream s = hr.GetRequestStream())
{
fu.PostedFile.InputStream.CopyTo(s);
s.Flush();
}
That will be more efficient, as you will be directly streaming the input file to the destination host, without first caching in memory or on disk.

You can't convert a FileUpload into a FileStream. You can, however, get a MemoryStream from that FileUpload's PostedFile property. You can then use that MemoryStream to fill your HttpWebRequest.

You can put a FileUpload file directly into a MemoryStream by using FileBytes (simplified answer from Tech Jerk)
using (MemoryStream ms = new MemoryStream(FileUpload1.FileBytes))
{
//do stuff
}
Or if you do not need a memoryStream
byte[] bin = FileUpload1.FileBytes;

Related

What is an efficient way in C# of doing MD5 and download all at once?

I'm working on download and then MD5 check to ensure the download is successful. I have the following code which should work, but isn't the most efficient - especially for large files.
using (var client = new System.Net.WebClient())
{
client.DownloadFile(url, destinationFile);
}
var fileHash = GetMD5HashAsStringFromFile(destinationFile);
var successful = expectedHash.Equals(fileHash, StringComparison.OrdinalIgnoreCase);
My concern is that the bytes are all streamed through to disk, and then the MD5 ComputeHash() has to open the file and read all the bytes again. Is there a good, clean way of computing the MD5 as part of the download stream? Ideally, the MD5 should just fall out of the DownloadFile() function as a side effect of sorts. A function with a signature like this:
string DownloadFileAndComputeHash(string url, string filename, HashTypeEnum hashType);
Edit: Adds code for GetMD5HashAsStringFromFile()
public string GetMD5HashAsStringFromFile(string filename)
{
using (FileStream file = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var md5er = System.Security.Cryptography.MD5.Create();
var md5HashBytes = md5er.ComputeHash(file);
return BitConverter
.ToString(md5HashBytes)
.Replace("-", string.Empty)
.ToLower();
}
}
Is there a good, clean way of computing the MD5 as part of the download stream? Ideally, the MD5 should just fall out of the DownloadFile() function as a side effect of sorts.
You could follow this strategy, to do "chunked" calculation and minimize memory pressure (and duplication):
Open the response stream on the web client.
Open the destination file stream.
Repeat while there is data available:
Read chunk from response stream into byte buffer
Write it to the destination file stream.
Use the TransformBlock method to add the bytes to the hash calculation
Use TransformFinalBlock to get the calculated hash code.
The sample code below shows how this could be achieved.
public static byte[] DownloadAndGetHash(Uri file, string destFilePath, int bufferSize)
{
using (var md5 = MD5.Create())
using (var client = new System.Net.WebClient())
{
using (var src = client.OpenRead(file))
using (var dest = File.Create(destFilePath, bufferSize))
{
md5.Initialize();
var buffer = new byte[bufferSize];
while (true)
{
var read = src.Read(buffer, 0, buffer.Length);
if (read > 0)
{
dest.Write(buffer, 0, read);
md5.TransformBlock(buffer, 0, read, null, 0);
}
else // reached the end.
{
md5.TransformFinalBlock(buffer, 0, 0);
return md5.Hash;
}
}
}
}
}
If you're talking about large files (I'm assuming over 1GB), you'll want to read the data in chunks, then process each chunk through the MD5 algorithm, and then store it to the disk. It's doable, but I don't know how much of the default .NET classes will help you with that.
One approach might be with a custom stream wrapper. First you get a Stream from WebClient (via GetWebResponse() and then GetResponseStream()), then you wrap it, and then pass it to ComputeHash(stream). When MD5 calls Read() on your wrapper, the wrapper would call Read on the network stream, write the data out when it's received, and then pass it back to MD5.
I don't know what problems would await you if you try and do this.
Something like this.
byte[] result;
using (var webClient = new System.Net.WebClient())
{
result = webClient.DownloadData("http://some.url");
}
byte[] hash = ((HashAlgorithm)CryptoConfig.CreateFromName("MD5")).ComputeHash(result);

Accessing Stream at the same time

I am attempting to reuse the same Stream multiple times. One for resizing the image, and the other for uploading the image. Whilst it does work for resizing the image, it seems to be locking out the other method for uploading the file. I have tried to copy the Stream using Stream.CopyTo(MemoryStream), then using that for uploading, but it still doesn't make a different.
I am opening a Stream using the PhotoChooserTask. I then pass the Stream to a ImageThumbnail method which creates a thumbnail of the image and then saves it to IsolatedStorage as shown below:
public static void SaveThumbnail(Stream imageStream, string fileName, double imageMaxHeight, double imageMaxWidth)
{
var bitmapImage = new BitmapImage();
bitmapImage.SetSource(imageStream);
var resizedImage = new WriteableBitmap(bitmapImage);
using (var isolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
double scaleX = 1;
using (var fileStream = isolatedStorage.CreateFile(fileName))
{
//do stuff for resizing here...
resizedImage.SaveJpeg(fileStream, newWidth1, newHeight1, 0, 100);
}
}
}
At the same time, I am reusing the same Stream from the PhotoChooserTask for uploading the image. EItherway, it seems to be locking eachother out, and no error is being thrown.
Any tips?
You need to copy the stream into a byte array, because streams change during use and can't be cloned.
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
while (true)
{
int read = input.Read (buffer, 0, buffer.Length);
if (read <= 0)
return;
output.Write (buffer, 0, read);
}
}
Copying to a MemoryStream should do the trick. To reuse the memory stream, you need to reset the position back to the beginning, by setting the Position property back to 0.

How to save FileSteam as PDF file

I am using a third party tool to get the scanned content from the scanner. On button click it executes the code and gives the content as a FileStream. Now I need to save this FileStream content as a pdf file in to a specified folder.
After saving I need to open the file in browser. How can I save the FileStream as a PDF file?
You can write the stream directly to the output buffer of the response.
So if you're at the point in your code where you have the filestream from the scanner. Simply read bytes from the scanner filestream and write them to the Response.OutputStream
Set the contentType to application/pdf
Make sure you return nothing else. The users browser will do whatever it is configured to do now, either save to disk or show in the browser. You can also save to disk on the server at this point as well in case you wanted a backup.
I'm assuming your file stream is already a pdf, otherwise you'll need to use something like itextsharp to create the pdf.
Edit
Here's some rough and ready code to do it. You'll want to tidy this up, like adding exception trapping to make sure the file stream gets cleaned up properly.
public void SaveToOutput(Stream dataStream)
{
dataStream.Seek(0, SeekOrigin.Begin);
FileStream fileout = File.Create("somepath/file.pdf");
const int chunk = 512;
byte[] buffer = new byte[512];
int bytesread = dataStream.Read(buffer,0,chunk);
while (bytesread == chunk)
{
HttpContext.Current.Response.OutputStream.Write(buffer, 0, chunk);
fileout.Write(buffer, 0, chunk);
bytesread = dataStream.Read(buffer, 0, chunk);
}
HttpContext.Current.Response.OutputStream.Write(buffer, 0, bytesread);
fileout.Write(buffer, 0, bytesread);
fileout.Close();
HttpContext.Current.Response.ContentType = "application/pdf";
}
Simon
You might want to take a look at the C# PDF Library on SourceForge: http://sourceforge.net/projects/pdflibrary/
If I'm understanding you correctly, the third party library is handing you a stream containing the data for the scanned document and you need to write it to a file? If that's the case you need to look up file I/O in C#. Here's a link and an example:
Stream sourceStream = scanner.GetOutput(); // whereever the source stream is
FileStream targetStream = File.OpenWrite(filename, FileMode.Create());
int bytesRead = 0;
byte[] buffer = new byte[2048];
while (true) {
bytesRead = sourceStream.Read(buffer, 0, buffer.length);
if (bytesRead == 0)
break;
targetStream.Write(buffer, 0, bytesRead);
}
sourceStream.Close();
targetStream.Close();
not sure, but maybe check this
http://sourceforge.net/projects/itextsharp/
iTextSharp + FileStream = Corrupt PDF file
Another prominent PDF library (which I have used in the past as well) is iTextSharp. You can take a look at this tutorial on how to convert your Stream to PDF then have the user download it.

create file and save to it using memorystream

How can i create a file and write to it using the memory stream?
I need to use the memorystream to prevent other threads from trying to access the file.
The data i'm trying to save to a file is html.
How can this be done?
(Presuming you mean how to copy a file's content to a memory stream)
If you are using framework 4:
var memoryStream = new MemoryStream();
using var fileStream = new FileStream(FilePath, FileMode.Open, FileAccess.Read);
fileStream.CopyTo(memoryStream);
Here are code to create file
byte[] data = System.Text.Encoding.ASCII.GetBytes("This is a sample string");
System.IO.MemoryStream ms = new System.IO.MemoryStream();
ms.Write(data, 0, data.Length);
ms.Close();

How do I copy the contents of one stream to another?

What is the best way to copy the contents of one stream to another? Is there a standard utility method for this?
From .NET 4.5 on, there is the Stream.CopyToAsync method
input.CopyToAsync(output);
This will return a Task that can be continued on when completed, like so:
await input.CopyToAsync(output)
// Code from here on will be run in a continuation.
Note that depending on where the call to CopyToAsync is made, the code that follows may or may not continue on the same thread that called it.
The SynchronizationContext that was captured when calling await will determine what thread the continuation will be executed on.
Additionally, this call (and this is an implementation detail subject to change) still sequences reads and writes (it just doesn't waste a threads blocking on I/O completion).
From .NET 4.0 on, there's is the Stream.CopyTo method
input.CopyTo(output);
For .NET 3.5 and before
There isn't anything baked into the framework to assist with this; you have to copy the content manually, like so:
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write (buffer, 0, read);
}
}
Note 1: This method will allow you to report on progress (x bytes read so far ...)
Note 2: Why use a fixed buffer size and not input.Length? Because that Length may not be available! From the docs:
If a class derived from Stream does not support seeking, calls to Length, SetLength, Position, and Seek throw a NotSupportedException.
MemoryStream has .WriteTo(outstream);
and .NET 4.0 has .CopyTo on normal stream object.
.NET 4.0:
instream.CopyTo(outstream);
I use the following extension methods. They have optimized overloads for when one stream is a MemoryStream.
public static void CopyTo(this Stream src, Stream dest)
{
int size = (src.CanSeek) ? Math.Min((int)(src.Length - src.Position), 0x2000) : 0x2000;
byte[] buffer = new byte[size];
int n;
do
{
n = src.Read(buffer, 0, buffer.Length);
dest.Write(buffer, 0, n);
} while (n != 0);
}
public static void CopyTo(this MemoryStream src, Stream dest)
{
dest.Write(src.GetBuffer(), (int)src.Position, (int)(src.Length - src.Position));
}
public static void CopyTo(this Stream src, MemoryStream dest)
{
if (src.CanSeek)
{
int pos = (int)dest.Position;
int length = (int)(src.Length - src.Position) + pos;
dest.SetLength(length);
while(pos < length)
pos += src.Read(dest.GetBuffer(), pos, length - pos);
}
else
src.CopyTo((Stream)dest);
}
.NET Framework 4 introduce new "CopyTo" method of Stream Class of System.IO namespace. Using this method we can copy one stream to another stream of different stream class.
Here is example for this.
FileStream objFileStream = File.Open(Server.MapPath("TextFile.txt"), FileMode.Open);
Response.Write(string.Format("FileStream Content length: {0}", objFileStream.Length.ToString()));
MemoryStream objMemoryStream = new MemoryStream();
// Copy File Stream to Memory Stream using CopyTo method
objFileStream.CopyTo(objMemoryStream);
Response.Write("<br/><br/>");
Response.Write(string.Format("MemoryStream Content length: {0}", objMemoryStream.Length.ToString()));
Response.Write("<br/><br/>");
There is actually, a less heavy-handed way of doing a stream copy. Take note however, that this implies that you can store the entire file in memory. Don't try and use this if you are working with files that go into the hundreds of megabytes or more, without caution.
public static void CopySmallTextStream(Stream input, Stream output)
{
using (StreamReader reader = new StreamReader(input))
using (StreamWriter writer = new StreamWriter(output))
{
writer.Write(reader.ReadToEnd());
}
}
NOTE: There may also be some issues concerning binary data and character encodings.
The basic questions that differentiate implementations of "CopyStream" are:
size of the reading buffer
size of the writes
Can we use more than one thread (writing while we are reading).
The answers to these questions result in vastly different implementations of CopyStream and are dependent on what kind of streams you have and what you are trying to optimize. The "best" implementation would even need to know what specific hardware the streams were reading and writing to.
Unfortunately, there is no really simple solution. You can try something like that:
Stream s1, s2;
byte[] buffer = new byte[4096];
int bytesRead = 0;
while (bytesRead = s1.Read(buffer, 0, buffer.Length) > 0) s2.Write(buffer, 0, bytesRead);
s1.Close(); s2.Close();
But the problem with that that different implementation of the Stream class might behave differently if there is nothing to read. A stream reading a file from a local harddrive will probably block until the read operaition has read enough data from the disk to fill the buffer and only return less data if it reaches the end of file. On the other hand, a stream reading from the network might return less data even though there are more data left to be received.
Always check the documentation of the specific stream class you are using before using a generic solution.
There may be a way to do this more efficiently, depending on what kind of stream you're working with. If you can convert one or both of your streams to a MemoryStream, you can use the GetBuffer method to work directly with a byte array representing your data. This lets you use methods like Array.CopyTo, which abstract away all the issues raised by fryguybob. You can just trust .NET to know the optimal way to copy the data.
if you want a procdure to copy a stream to other the one that nick posted is fine but it is missing the position reset, it should be
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
long TempPos = input.Position;
while (true)
{
int read = input.Read (buffer, 0, buffer.Length);
if (read <= 0)
return;
output.Write (buffer, 0, read);
}
input.Position = TempPos;// or you make Position = 0 to set it at the start
}
but if it is in runtime not using a procedure you shpuld use memory stream
Stream output = new MemoryStream();
byte[] buffer = new byte[32768]; // or you specify the size you want of your buffer
long TempPos = input.Position;
while (true)
{
int read = input.Read (buffer, 0, buffer.Length);
if (read <= 0)
return;
output.Write (buffer, 0, read);
}
input.Position = TempPos;// or you make Position = 0 to set it at the start
Since none of the answers have covered an asynchronous way of copying from one stream to another, here is a pattern that I've successfully used in a port forwarding application to copy data from one network stream to another. It lacks exception handling to emphasize the pattern.
const int BUFFER_SIZE = 4096;
static byte[] bufferForRead = new byte[BUFFER_SIZE];
static byte[] bufferForWrite = new byte[BUFFER_SIZE];
static Stream sourceStream = new MemoryStream();
static Stream destinationStream = new MemoryStream();
static void Main(string[] args)
{
// Initial read from source stream
sourceStream.BeginRead(bufferForRead, 0, BUFFER_SIZE, BeginReadCallback, null);
}
private static void BeginReadCallback(IAsyncResult asyncRes)
{
// Finish reading from source stream
int bytesRead = sourceStream.EndRead(asyncRes);
// Make a copy of the buffer as we'll start another read immediately
Array.Copy(bufferForRead, 0, bufferForWrite, 0, bytesRead);
// Write copied buffer to destination stream
destinationStream.BeginWrite(bufferForWrite, 0, bytesRead, BeginWriteCallback, null);
// Start the next read (looks like async recursion I guess)
sourceStream.BeginRead(bufferForRead, 0, BUFFER_SIZE, BeginReadCallback, null);
}
private static void BeginWriteCallback(IAsyncResult asyncRes)
{
// Finish writing to destination stream
destinationStream.EndWrite(asyncRes);
}
For .NET 3.5 and before try :
MemoryStream1.WriteTo(MemoryStream2);
Easy and safe - make new stream from original source:
MemoryStream source = new MemoryStream(byteArray);
MemoryStream copy = new MemoryStream(byteArray);
The following code to solve the issue copy the Stream to MemoryStream using CopyTo
Stream stream = new MemoryStream();
//any function require input the stream. In mycase to save the PDF file as stream
document.Save(stream);
MemoryStream newMs = (MemoryStream)stream;
byte[] getByte = newMs.ToArray();
//Note - please dispose the stream in the finally block instead of inside using block as it will throw an error 'Access denied as the stream is closed'

Categories