If I have a pdf file as a Stream, how can I write it to the response output stream?
Since you are using MVC, the best way is to use FileStreamResult:
return new FileStreamResult(stream, "application/pdf")
{
FileDownloadName = "file.pdf"
};
Playing with Response.Write or Response.OutputStream from your controller is non-idiomatic and there's no reason to write your own ActionResult when one already exists.
One way to do it is as follows:
//assuming you have your FileStream handle already - named fs
byte[] buffer = new byte[4096];
long count = 0;
while ((count = fs.Read(buffer, 0, buffer.Length)) > 0)
{
response.OutputStream.Write(buffer, 0, count);
response.Flush();
}
You can also use GZIP compression to speed the transfer of the file to the client (less bytes streamed).
In asp.net this is the way to download a pdf file
Dim MyFileStream As FileStream
Dim FileSize As Long
MyFileStream = New FileStream(filePath, FileMode.Open)
FileSize = MyFileStream.Length
Dim Buffer(CInt(FileSize)) As Byte
MyFileStream.Read(Buffer, 0, CInt(FileSize))
MyFileStream.Close()
Response.ContentType = "application/pdf"
Response.OutputStream.Write(Buffer, 0, FileSize)
Response.Flush()
Response.Close()
The HTTP Response is a stream exposed to you through the HttpContext.Response.OutputStream property, so if you have the PDF file in a stream you can simply copy the data from one stream to the other:
CopyStream(pdfStream, response.OutputStream);
For an implementation of CopyStream see Best way to copy between two Stream instances - C#
Please try this one:
protected void Page_Load(object sender, EventArgs e) {
Context.Response.Buffer = false;
FileStream inStr = null;
byte[] buffer = new byte[1024];
long byteCount; inStr = File.OpenRead(#"C:\Users\Downloads\sample.pdf");
while ((byteCount = inStr.Read(buffer, 0, buffer.Length)) > 0) {
if (Context.Response.IsClientConnected) {
Context.Response.ContentType = "application/pdf";
Context.Response.OutputStream.Write(buffer, 0, buffer.Length);
Context.Response.Flush();
}
}
}
Related
My question is similar to this question:
Does File() In asp.net mvc close the stream?
I have the follows in C# MVC 4.
FileStream fs = new FileStream(pathToFileOnDisk, FileMode.Open);
FileStreamResult fsResult = new FileStreamResult(fs, "Text");
return fsResult;
Will fs be closed automatically by FileStreamResult? thanks!
Yes. It uses a using block around the stream, and that ensures that the resource will dispose.
Here is the internal implementation of the FileStreamResult WriteFile method:
protected override void WriteFile(HttpResponseBase response)
{
// grab chunks of data and write to the output stream
Stream outputStream = response.OutputStream;
using (FileStream)
{
byte[] buffer = new byte[BufferSize];
while (true)
{
int bytesRead = FileStream.Read(buffer, 0, BufferSize);
if (bytesRead == 0)
{
// no more data
break;
}
outputStream.Write(buffer, 0, bytesRead);
}
}
}
I'm trying code from http://www.paraesthesia.com/archive/2009/12/16/posting-multipartform-data-using-.net-webrequest.aspx to do a POST through httpwebrequest.
If I try this same code with a text file, it's fine. However if I do it with a zip file, then when re-download that file it's saying it's not a valid zip. I assume the zip portion is likely getting uploaded as text rather than binary. However, that page does say " It's OK to include binary content here. Don't base-64 encode it or anything, just stream it on in." But this doesn't seem to be working with the given code. I'm assuming I have to change the portion that reads the file to the stream:
using (FileStream fileStream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
stream.Write(buffer, 0, bytesRead);
}
fileStream.Close();
}
Maybe to use BinaryReader? I'm a bit confused on how to use that in this context though, or if it's even what I need to do. A nudge in the right direction would be awesome. Thanks!
BinaryReader should work indeed:
FileInfo fInfo = new FileInfo(file.FullName);
//
long numBytes = fInfo.Length;
FileStream fStream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fStream);
byte[] bdata = br.ReadBytes((int)numBytes);
br.Close();
fStream.Close();
// Write bdata to the HttpStream
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("url-here");
// Additional webRequest parameters settings.
HttpStream stream = (Stream)webRequest.GetRequestStream();
stream .Write(bdata, 0, bdata.Length);
stream.Close();
HttpWebResponse response = (HttpWebRewponse)webRequest.GetResponse();
I have a method for FTP download file, but I do not save file locally rather I parse the file in memory through ftp response. My question is, is returning stream reader after getting ftp response stream a good practice? Because do not want to do parsing and other stuff in the same method.
var uri = new Uri(string.Format("ftp://{0}/{1}/{2}", "somevalue", remotefolderpath, remotefilename));
var request = (FtpWebRequest)FtpWebRequest.Create(uri);
request.Credentials = new NetworkCredential(userName, password);
request.Method = WebRequestMethods.Ftp.DownloadFile;
var ftpResponse = (FtpWebResponse)request.GetResponse();
/* Get the FTP Server's Response Stream */
ftpStream = ftpResponse.GetResponseStream();
return responseStream = new StreamReader(ftpStream);
For me there are 2 disadvantages of using the stream directly, if you can live with them, you shouldn't waste memory or disk space.
In this stream you can not seek to a specific position, you can only read the contents as it comes in;
Your internet connection could suddenly drop and you will get an exception while parsing and processing your file, either split the parsing and processing or make sure your processing routine can handle the case that a file is processed for a second time (after a failure halfway through the first attempt).
To work around these issues, you could copy the stream to a MemoryStream:
using (var ftpStream = ftpResponse.GetResponseStream())
{
var memoryStream = new MemoryStream()
while ((bytesRead = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
{
memoryStream.Write(buffer, 0, bytesRead);
}
memoryStream.Flush();
memoryStream.Position = 0;
return memoryStream;
}
If you are working with larger files I prefer writing it to a file, this way you minimize the memory footprint of your application:
using (var ftpStream = ftpResponse.GetResponseStream())
{
var fileStream = new FileStream(Path.GetTempFileName(), FileMode.CreateNew)
while ((bytesRead = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
{
fileStream.Write(buffer, 0, bytesRead);
}
fileStream.Flush();
fileStream.Position = 0;
return fileStream;
}
I see more practical returning a responseStream when you are performing an HttpWebRequest. If you are using FtpWebRequest it means you are working with files. I would read the responseStream to byte[] and return the byte file content of the downloaded file, so you can easily work with the System.IO.Fileclasses to handle the file.
Thanks Carlos it was really helpful . I just return the byte[]
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
memoryStream=ms;
}
return memoryStream.ToArray();
and used byte[] in the method like this
public async Task ParseReport(byte[] bytesRead)
{
Stream stream = new MemoryStream(bytesRead);
using (StreamReader reader = new StreamReader(stream))
{
string line = null;
while (null != (line = reader.ReadLine()))
{
string[] values = line.Split(';');
}
}
stream.Close();
}
I have a web page with a "download" link on it.
Using jQuery I do an Ajax Get to a ASHX file.
In the ASHX I get the Stream of the file. I then convert the stream to a byte array and return the byte array back to the calling html page;
jQuery
$(".DownloadConvertedPDF").click(function () {
var bookId = $(this).attr("bookId");
$.get('/UserControls/download.ashx?format=pdf&bookId=' + bookId, {}, function (data) { });
});
C#
context.Response.ContentType = "Application/pdf";
Stream fileStream = publishBookManager.GetFile(documentId);
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = fileStream.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
}
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
I don't get an error but also the PDF doesn't display on screen.
Ideally I'd like the pdf returned and the jQuery to launch the pdf in a seperate tab within the browser.
How can I make this happen or what am I doing wrong?
Try this (do not use .get):
window.open('/UserControls/download.ashx?format=pdf&bookId=' + bookId, "pdfViewer");
To prevent the "File does not begin with '%PDF" error, use Response.BinaryWrite:
context.Response.Clear();
context.Response.ClearContent();
context.Response.ClearHeaders();
context.Response.ContentType = "application/pdf";
Stream fileStream = publishBookManager.GetFile(documentId);
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = fileStream.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
}
context.Response.BinaryWrite(data);
context.Response.Flush();
Through use of context.Response.TransmitFile, a more concise way to serve a PDF from an ashx web handler is:
context.Response.Clear();
context.Response.ContentType = "application/pdf";
string filePath = System.Web.HttpContext.Current.Server.MapPath(#"~\path-to\your-file.pdf");
context.Response.TransmitFile(filePath);
i am also using window.open for getting the pdf. but it is always displayed while try to use same URL through address bar directly without logged in. how to solve this one.
I have the following code which downloads video content:
WebRequest wreq = (HttpWebRequest)WebRequest.Create(url);
using (HttpWebResponse wresp = (HttpWebResponse)wreq.GetResponse())
using (Stream mystream = wresp.GetResponseStream())
{
using (BinaryReader reader = new BinaryReader(mystream))
{
int length = Convert.ToInt32(wresp.ContentLength);
byte[] buffer = new byte[length];
buffer = reader.ReadBytes(length);
Response.Clear();
Response.Buffer = false;
Response.ContentType = "video/mp4";
//Response.BinaryWrite(buffer);
Response.OutputStream.Write(buffer, 0, buffer.Length);
Response.End();
}
}
But the problem is that the whole file downloads before being played. How can I make it stream and play as it's still downloading? Or is this up to the client/receiver application to manage?
You're reading the entire file into a single buffer, then sending the entire byte array at once.
You should read into a smaller buffer in a while loop.
For example:
byte[] buffer = new byte[4096];
while(true) {
int bytesRead = myStream.Read(buffer, 0, buffer.Length);
if (bytesRead == 0) break;
Response.OutputStream.Write(buffer, 0, bytesRead);
}
This is more efficient for you especially if you need to stream a video from a file on your server or even this file is hosted at another server
File On your server:
context.Response.BinaryWrite(File.ReadAllBytes(HTTPContext.Current.Server.MapPath(_video.Location)));
File on external server:
var wc = new WebClient();
context.Response.BinaryWrite(wc.DownloadData(new Uri("http://mysite/video.mp4")));
Have you looked at Smooth Streaming?
Look at sample code here