write large HSSFWorkbook into OutputStream with ZipOutputStream - servlets

Really appreciate the assistance since I am stuck here
I am Trying to download .xls file/files in zip format
Works fine when there are small amount of data like 150 records in xls file
But once the data is huge it fails to download.
it redirects to a page which looks someting like this
Here is my code
HSSFWorkbook workbook = null;
out = response.getOutputStream(); //response is of type HttpServletResponse , out is of type java.io.OutputStream
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(out));
for(int i=0;i < selectedObjectsToDownload.length; i++){
//fetching data from DB
workbook = new HSSFWorkbook();
worksheet = workbook.createSheet("mySheet");
workbook= getWorkbook(//data from DB);
File fName=new File("File Path here");
ZipEntry entry = new ZipEntry(fName.getName());
zos.putNextEntry(entry);
workbook.write(zos);
}
response.setContentType("application/zip");
response.setHeader("Content-Disposition","attachment; filename=\"" + "exported filename.zip" + "\"");
zos.close();
out.flush();
out.close();

Ok, I found the issue.
Need to set character encoding before opening the workbook.
Here is the modified code
HSSFWorkbook workbook = null;
out = response.getOutputStream(); //response is of type HttpServletResponse , out is of type java.io.OutputStream
response.setContentType("application/zip");
response.setHeader("Content-Disposition","attachment; filename=\"" + "exported filename.zip" + "\"");
**response.setCharacterEncoding("UTF-8");**
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(out));
for(int i=0;i < selectedObjectsToDownload.length; i++){
//fetching data from DB
workbook = new HSSFWorkbook();
worksheet = workbook.createSheet("mySheet");
workbook= getWorkbook(//data from DB);
File fName=new File("File Path here");
ZipEntry entry = new ZipEntry(fName.getName());
zos.putNextEntry(entry);
workbook.write(zos);
}
zos.close();
out.flush();
out.close();

Related

Problems with downloading pdf file from web api service

I'm trying to set up a web api service that searches for a .pdf file in a directory and returns the file if it's found.
The controller
public class ProductsController : ApiController
{
[HttpPost]
public HttpResponseMessage Post([FromBody]string certificateId)
{
string fileName = certificateId + ".pdf";
var path = #"C:\Certificates\20487A" + fileName;
//check the directory for pdf matching the certid
if (File.Exists(path))
{
//if there is a match then return the file
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(path, FileMode.Open);
stream.Position = 0;
result.Content = new StreamContent(stream);
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment") { FileName = fileName };
result.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
result.Content.Headers.ContentDisposition.FileName = fileName;
return result;
}
else
{
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.Gone);
return result;
}
}
}
I'm calling the service with the following code
private void GetCertQueryResponse(string url, string serial)
{
string encodedParameters = "certificateId=" + serial.Replace(" ", "");
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
httpRequest.Method = "POST";
httpRequest.ContentType = "application/x-www-form-urlencoded";
httpRequest.AllowAutoRedirect = false;
byte[] bytedata = Encoding.UTF8.GetBytes(encodedParameters);
httpRequest.ContentLength = bytedata.Length;
Stream requestStream = httpRequest.GetRequestStream();
requestStream.Write(bytedata, 0, bytedata.Length);
requestStream.Close();
HttpWebResponse response = (HttpWebResponse)httpRequest.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
byte[] bytes = null;
using (Stream stream = response.GetResponseStream())
using (MemoryStream ms = new MemoryStream())
{
int count = 0;
do
{
byte[] buf = new byte[1024];
count = stream.Read(buf, 0, 1024);
ms.Write(buf, 0, count);
} while (stream.CanRead && count > 0);
ms.Position = 0;
bytes = ms.ToArray();
}
var filename = serial + ".pdf";
Response.ContentType = "application/pdf";
Response.Headers.Add("Content-Disposition", "attachment; filename=\"" + filename + "\"");
Response.BinaryWrite(bytes);
}
}
This appears to be working in the sense that the download file dialogue is shown with the correct file name and size etc, but the download takes only a couple of seconds (when the file sizes are >30mb) and the files are corrupt when I try to open them.
Any ideas what I'm doing wrong?
Your code looks similar to what Ive used in the past, but below is what I typically use:
Response.AddHeader("content-length", myfile.Length.ToString())
Response.AddHeader("content-disposition", "inline; filename=MyFilename")
Response.AddHeader("Expires", "0")
Response.AddHeader("Pragma", "Cache")
Response.AddHeader("Cache-Control", "private")
Response.ContentType = "application/pdf"
Response.BinaryWrite(finalForm)
I post this for 2 reasons. One, add the content-length header, you may have to indicate how large the file is so the application waits for the whole response.
If that doesn't fix it. Set a breakpoint, does the byte array content the appropriate length (aka, 30 million bytes for a 30 MB file)? Have you used fiddler to see how much content is coming back over the HTTP call?

BinaryReader.ReadBytes returning junk when converted to string

if I try to explain why I need to do what I'm trying to do it will take a long time, but basically it's this: I have FileUpload control for the user to choose a Jpeg file, I make the upload and after it I want to convert that file to bytes and use it as the source of an Image control.
My code is this one:
string fileName = Server.MapPath("~/TempImages") + #"\foto.jpg";
fileUpload1.SaveAs(fileName);
System.IO.FileStream fs = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
System.IO.BinaryReader binaryReader = new System.IO.BinaryReader(fs);
long byteLength = new System.IO.FileInfo(fileName).Length;
byte[] buffer = binaryReader.ReadBytes((Int32)byteLength);
fs.Close();
fs.Dispose();
string valor = System.Text.Encoding.UTF8.GetString(buffer);
img.ImageUrl = "data:image/jpg;base64," + valor;
The byte array is looking ok, but when I convert it to string it's full of unrecognized characters, I have another page where I do the same thing but instead of getting the bytes from the file I get it from a MySql database and using the same System.Text.Encoding.UTF8.GetString and it works withou a problem.
UPDATE
As asked, this is the code I use when retrieving the from the MySql database:
DataView dv = (DataView)SqlDataSource3.Select(DataSourceSelectArguments.Empty);
byte[] buffer = (byte[])dv.Table.Rows[0]["BIN_FOTO"];
string valor = System.Text.Encoding.UTF8.GetString(buffer);
img.ImageUrl = "data:image/jpg;base64," + valor;
The select of this SqlDataSource3 is a simple Select BIN_FOTO from temp_image. I store this value in the database from a webcam capture WPF program, the code I use to convert the image the webcam captured is:
private string ImageToBase64String(System.Drawing.Image imageData, ImageFormat format)
{
string base64;
MemoryStream memory = new MemoryStream();
imageData.Save(memory, format);
base64 = System.Convert.ToBase64String(memory.ToArray());
memory.Close();
memory.Dispose();
return base64;
}
Then I save the base64 variable to the database.
Hope this clarifies my problem
So you want to read the image file and convert to base 64. After your reading code, do this:
string valor = Convert.ToBase64String(buffer);
Your original code was flawed because you're saving the image, as bytes, to the file with this line of code:
fileUpload1.SaveAs(fileName);
That's not saved as base64, so you have to convert it to base 64 after you read it. Your MySql reading worked because the data was converted to base64 before being saved.
By the way, there's no need for the BinaryReader in this code:
System.IO.FileStream fs = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
System.IO.BinaryReader binaryReader = new System.IO.BinaryReader(fs);
long byteLength = new System.IO.FileInfo(fileName).Length;
byte[] buffer = binaryReader.ReadBytes((Int32)byteLength);
fs.Close();
fs.Dispose();
You can write this instead:
byte[] buffer;
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read)
{
long byteLength = fs.Length;
buffer = new byte[byteLength];
int bytesRead = fs.Read(buffer, 0, byteLength);
// optional error check to see that you got all the bytes
if (bytesRead != byteLength)
{
// handle error
}
}
string valor = Convert.ToBase64String(buffer);
I've found the problem, looking at the WPF code I used to convert the image to a Base64String. I just created the same function ImageToBase64String and now it works:
string fileName = Server.MapPath("~/TempImages") + #"\foto.jpg";
fileUpload1.SaveAs(fileName);
System.Drawing.Image teste = System.Drawing.Image.FromFile(fileName);
string valor = ImageToBase64String(teste, System.Drawing.Imaging.ImageFormat.Jpeg);
//System.IO.FileStream fs = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
//System.IO.BinaryReader binaryReader = new System.IO.BinaryReader(fs);
//long byteLength = new System.IO.FileInfo(fileName).Length;
//byte[] buffer = binaryReader.ReadBytes((Int32)byteLength);
//buffer = File.ReadAllBytes(fileName);
//fs.Close();
//fs.Dispose();
//string valor = System.Text.Encoding.UTF8.GetString(buffer);
img.ImageUrl = "data:image/jpg;base64," + valor;
But I still don't know what was wrong with my previous code, anyone can clarify?
This solution worked for me:
System.IO.BinaryReader binaryReader = new System.IO.BinaryReader(fs);
//Add this--------------------
fs.Seek(0, SeekOrigin.Begin);
//----------------------------
long byteLength = new System.IO.FileInfo(fileName).Length;
byte[] buffer = binaryReader.ReadBytes((Int32)byteLength);
Just add highlighted line.

ASP.NET MVC: C# Download file and save as dialog [duplicate]

This question already has answers here:
Setting mime type for excel document
(6 answers)
Closed 9 years ago.
i've written this code which will generate an excel spreadsheet and save it to a specified location. I want to then display a "Save as" dialogue box by reading the file from the stored location and then asking then user where they want to store it.
Excel.Application excelApp = null;
Excel.Workbook wb = null;
Excel.Worksheet ws = null;
Excel.Range range = null;
excelApp = new Excel.Application();
wb = excelApp.Workbooks.Add();
ws = wb.Worksheets.get_Item(1) as Excel.Worksheet;
for(int i = 0; i< 10;++i) {
ws.Cells[i, 1] = i+
}
wb.SaveAs(#"C:\test.xls", Excel.XlFileFormat.xlWorkbookNormal);
wb.Close(true);
excelApp.Quit();
How to download in the following format?
string str = "Hello, world";
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(str);
return File(bytes, "text/plain");
Given that is an Excel doc saved at c:\temp\excelDoc.xls and given that you have a WebForm that has a link like this
<asp:LinkButton runat="server" ID="GetExcel" OnClick="GetExcel_Click">Download</asp:LinkButton>
In your code-behind you can read the file from disk and send to the user by something like this
protected void GetExcel_Click(object sender, EventArgs e)
{
var fileName = "excelDoc.xls";
using (var cs = new FileStream(#"c:\temp\" + fileName, FileMode.Open))
{
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=" + fileName);
Response.ContentType = "application/vnd.ms-excel";
byte[] buffer = new byte[32768];
int read;
while ((read = cs.Read(buffer, 0, buffer.Length)) > 0)
{
Response.OutputStream.Write(buffer, 0, read);
}
Response.End();
Response.Flush();
}
}

Server.map path not working in asp.net

I am using this code to download a excel file which exist in my solution. I have added a folder FileUpload and added a excel file UploadCWF.xlsx. My code is workin in local host. But not working when I host this to server.I am getting error - Could not find a part of the path. My code -
string filePath = HttpContext.Current.Server.MapPath("~/FileUpload/");
string _DownloadableProductFileName = "UploadCWF.xlsx";
System.IO.FileInfo FileName = new System.IO.FileInfo(filePath + "\\" + _DownloadableProductFileName);
FileStream myFile = new FileStream(filePath + "\\" + _DownloadableProductFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
//Reads file as binary values
BinaryReader _BinaryReader = new BinaryReader(myFile);
//Check whether file exists in specified location
if (FileName.Exists)
{
try
{
long startBytes = 0;
string lastUpdateTiemStamp = File.GetLastWriteTimeUtc(filePath).ToString("r");
string _EncodedData = HttpUtility.UrlEncode(_DownloadableProductFileName, Encoding.UTF8) + lastUpdateTiemStamp;
Response.Clear();
Response.Buffer = false;
Response.AddHeader("Accept-Ranges", "bytes");
Response.AppendHeader("ETag", "\"" + _EncodedData + "\"");
Response.AppendHeader("Last-Modified", lastUpdateTiemStamp);
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment;filename=" + FileName.Name);
Response.AddHeader("Content-Length", (FileName.Length - startBytes).ToString());
Response.AddHeader("Connection", "Keep-Alive");
Response.ContentEncoding = Encoding.UTF8;
//Send data
_BinaryReader.BaseStream.Seek(startBytes, SeekOrigin.Begin);
//Dividing the data in 1024 bytes package
int maxCount = (int)Math.Ceiling((FileName.Length - startBytes + 0.0) / 1024);
//Download in block of 1024 bytes
int i;
for (i = 0; i < maxCount && Response.IsClientConnected; i++)
{
Response.BinaryWrite(_BinaryReader.ReadBytes(1024));
Response.Flush();
}
}
catch (Exception es)
{
throw es;
}
finally
{
Response.End();
_BinaryReader.Close();
myFile.Close();
}
}
else
System.Web.UI.ScriptManager.RegisterStartupScript(this, GetType(),
"FileNotFoundWarning", "alert('File is not available now!')", true);
Please some one help me.
You should first concat filepath and filename then get path using server.mappath.
You should write code like this
string filePath = HttpContext.Current.Server.MapPath("~/FileUpload/UploadCWF.xlsx");
System.IO.FileInfo FileName = new System.IO.FileInfo(filePath);

save multiple image to local from folder in asp.net

ive got a file download issue can you help me for that...
here is the code:
DirectoryInfo directoryInfo = new DirectoryInfo(Server.MapPath(#"/Bailiffs/BailiffFiles/"));
string cukurNumber = string.Empty;
if (txtCukurNumber.Text != string.Empty) {
cukurNumber = txtCukurNumber.Text;
}
FileInfo[] fileInfoEnum = directoryInfo.GetFiles(cukurNumber + "*");
Response.Clear();
Response.AddHeader("Content-Disposition", "attachment;filename=" + txtCukurNumber.Text + ".zip");
Response.ContentType = "application/zip";
using (ZipOutputStream zipStream = new ZipOutputStream(Response.OutputStream)) {
zipStream.SetLevel(9);
byte[] zipBuffer = new byte[4096];
foreach (FileInfo fileInfo in fileInfoEnum) {
string fileFullName = fileInfo.FullName;
ZipEntry zipEntry = new ZipEntry(Path.GetFileName(fileFullName));
zipEntry.DateTime = DateTime.Now;
zipStream.PutNextEntry(zipEntry);
using (FileStream fileStream = File.OpenRead(fileFullName)) {
int sourceBytes = 0;
do {
sourceBytes = fileStream.Read(zipBuffer, 0, zipBuffer.Length);
zipStream.Write(zipBuffer, 0, sourceBytes);
} while (sourceBytes > 0);
}
}
zipStream.Finish();
zipStream.Close();
Response.Flush();
Response.End();
}
this code must be get all image files by filter and save to disk but save file dialog of browser is opening just one time and one bizarre file is saving... where am i doing wrong...
thanks..
Edit : Bizzarre file issue is solved now the main issue is single file saving instead of multiple..
thanks again...
Although you are looping over each file in the directory, once you do your Response.End() on the first iteration of the loop, the response to the user is done. They would only get the first file that is found by the enumerator.
The browser doesn't have a concept of receiving multiple files in the way you are attempting.
You may consider collecting the various image files and putting them together in a ZIP file, and then returning a single ZIP back to the user.
Here is example code that will build a ZIP (using SharZipLib) of the images and reply with a single file called "images.zip"
Include these using statements for SharpZipLib:
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Checksums;
Then in the method where you want to stream back the ZIP file:
DirectoryInfo directoryInfo = new DirectoryInfo(Server.MapPath(#"/Bailiffs/BailiffFiles/"));
string cukurNumber = string.Empty;
if (txtCukurNumber.Text != string.Empty) {
cukurNumber = txtCukurNumber.Text;
}
IEnumerable<FileInfo> fileInfoEnum = directoryInfo.EnumerateFiles( cukurNumber + "*" );
Response.Clear();
Response.AddHeader( "Content-Disposition", "attachment;filename=images.zip" );
Response.ContentType = "application/zip";
using( ZipOutputStream zipstream = new ZipOutputStream( Response.OutputStream ) ) {
zipstream.SetLevel( 9 ); // 0-9, 9 being the highest compression
byte[] buffer = new byte[4096];
foreach( FileInfo fileInfo in fileInfoEnum ) {
string file = fileInfo.FullName;
ZipEntry entry = new
ZipEntry( Path.GetFileName( file ) );
entry.DateTime = DateTime.Now;
zipstream.PutNextEntry( entry );
using( FileStream fs = File.OpenRead( file ) ) {
int sourceBytes;
do {
sourceBytes = fs.Read( buffer, 0, buffer.Length );
zipstream.Write( buffer, 0, sourceBytes );
} while( sourceBytes > 0 );
}
}
zipstream.Finish();
zipstream.Close();
}
Response.Flush();
Response.End();

Resources