How to zip PDF and XML files which are in memorystreams - stream

I'm working with VS2015 and ASP.Net on a webservice application which is installed in the AWS cloud.
In one of my methods i got two files, a PDF and a XML.
These files just exist as instances of type MemoryStream.
Now i have to compress these two "files" in a ZIP file before adding the zip as attachment to an E-mail (class MailMessage).
It seems that i have to save the memorystreams to files before adding them as entries to the zip.
Is ist true or do i have another possibility to add the streams as entries to the zip?
Thanks in advance!

The answer is no.
It is not necessary to save the files before adding them to the stream for the ZIP file.
I have found a solution with the Nuget package DotNetZip.
Here is a code example how to use it.
In that example there two files which only exist in MemoryStream objects, not on a local disc.
It is important to reset the Position property of the streams to zero before adding them to the ZIP stream.
At last i save the ZIP stream as a file in my local folder to control the results.
//DotNetZip from Nuget
//http://shahvaibhav.com/create-zip-file-in-memory-using-dotnetzip/
string zipFileName = System.IO.Path.GetFileNameWithoutExtension(xmlFileName) + ".zip";
var zipMemStream = new MemoryStream();
zipMemStream.Position = 0;
using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
{
textFileStream.Position = 0;
zip.AddEntry(System.IO.Path.GetFileNameWithoutExtension(xmlFileName) + ".txt", textFileStream);
xmlFileStream.Position = 0;
zip.AddEntry(xmlFileName, xmlFileStream);
zip.Save(zipMemStream);
// Try to save the ZIP-Stream as a ZIP file. And suddenly: It works!
var zipFs = new FileStream(zipFileName, FileMode.Create);
zipMemStream.Position = 0;
zipMemStream.CopyTo(zipFs);
zipMemStream.WriteTo(zipFs);
}

Related

Stream multiple Excel files as one file

I want to deliver large Excel files using a webservice or httphandler.
As the Excel files can be very big in size, I want to split them up into smaller files, to decrease the memory footprint.
So I will have a master excelfile that contains the column headers and data.
And further files which will only contain data.
During download, I want to stream the master excel file first and then append all other related excel files as one download stream.
I don't want to zip them! It should be one file at the end
Is this possible?
Master excel file with headers:
All other files will look like this (without headers):
This will indeed return crap:
void Main()
{
CombineMultipleFilesIntoSingleFile();
}
// Define other methods and classes here
private static void CombineMultipleFilesIntoSingleFile(string outputFilePath= #"C:\exceltest\main.xlsx", string inputDirectoryPath = #"C:\exceltest", string inputFileNamePattern="*.xlsx")
{
string[] inputFilePaths = Directory.GetFiles(inputDirectoryPath, inputFileNamePattern);
Console.WriteLine("Number of files: {0}.", inputFilePaths.Length);
using (var outputStream = File.Create(outputFilePath))
{
foreach (var inputFilePath in inputFilePaths)
{
using (var inputStream = File.OpenRead(inputFilePath))
{
// Buffer size can be passed as the second argument.
inputStream.CopyTo(outputStream);
}
Console.WriteLine("The file {0} has been processed.", inputFilePath);
}
}
}
When you are requesting for file, do not download it at first request.
Request for file names to be downloaded in AJAX request.
For each file name received, prepare its path to the server.
Create hidden iFrames for each file path and specify src as file path for each file to be downloaded.
When iFrame's src attribute is set, it will navigate to the file path and each iFrame will download single file, so multiple iFrame downloads multiple files.
You cannot download multiple files in single request. As if you will append the stream of multiple files, it will create a garbage file, a single garbage file.

How to generate multiple reports in Grails using Export plugin?

I am using the Export plugin in Grails for generating PDF/Excel report. I am able to generate single report on PDF/Excel button click. But, now I want to generate multiple reports on single button click. I tried for loop, method calls but no luck.
Reference links are ok. I don't expect entire code, needs reference only.
If you take a look at the source code for the ExportService in the plugin you will notice there are various export methods. Two of which support OutputStreams. Using either of these methods (depending on your requirements for the other parameters) will allow you to render a report to an output stream. Then using those output streams you can create a zip file which you can deliver to the HTTP client.
Here is a very rough example, which was written off the top of my head so it's really just an idea rather than working code:
// Assumes you have a list of maps.
// Each map will have two keys.
// outputStream and fileName
List files = []
// call the exportService and populate your list of files
// ByteArrayOutputStream outputStream = new ByteArrayOutputStream()
// exportService.export('pdf', outputStream, ...)
// files.add([outputStream: outputStream, fileName: 'whatever.pdf'])
// ByteArrayOutputStream outputStream2 = new ByteArrayOutputStream()
// exportService.export('pdf', outputStream2, ...)
// files.add([outputStream: outputStream2, fileName: 'another.pdf'])
// create a tempoary file for the zip file
File tempZipFile = File.createTempFile("temp", "zip")
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(tempZipFile))
// set the compression ratio
out.setLevel(Deflater.BEST_SPEED);
// Iterate through the list of files adding them to the ZIP file
files.each { file ->
// Associate an input stream for the current file
ByteArrayInputStream input = new ByteArrayInputStream(file.outputStream.toByteArray())
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(file.fileName))
// Transfer bytes from the current file to the ZIP file
org.apache.commons.io.IOUtils.copy(input, out);
// Close the current entry
out.closeEntry()
// Close the current input stream
input.close()
}
// close the ZIP file
out.close()
// next you need to deliver the zip file to the HTTP client
response.setContentType("application/zip")
response.setHeader("Content-disposition", "attachment;filename=WhateverFilename.zip")
org.apache.commons.io.IOUtils.copy((new FileInputStream(tempZipFile), response.outputStream)
response.outputStream.flush()
response.outputStream.close()
That should give you an idea of how to approach this. Again, the above is just for demonstration purposes and isn't production ready code, nor have I even attempted to compile it.

Launch Excel from MVC with actual file, not download copy

I need to be able to launch Excel and open and eiut a specific file from an MVC application.
The application is for internal use only and users will have access to the folder containing the excel file.
I have looked at the File method below
var dir = location + "Filename.xlsx";
var cd = new ContentDisposition
{
FileName = "Excel Spreadsheet",
Inline = true
};
Response.AppendHeader("Content-Disposition", cd.ToString());
return File(dir, "application/vnd.ms-excel");
However, this opens Excel with a copy of the file downloaded to the users's download directory. So if they make any changes, these do not update to the original.
Is what I'm trying to do possible? If so, how?
Many thanks,
Chris.

Cocoa/iOS: How to add a file as attachment to a PDF document?

PDF files support embedding arbitrary files as attachments (see here).
I would like to do just that in a Mac and an iPhone application using Objective-C:
Add a file as attachment to a PDF
Read the list of attached files from a PDF and extract one
Use case:
My app uses a custom document format that can only be opened by the app. I'd like to export the document as PDF and embed the original, custom document so that users who happen to have the app installed can modify the document. Everybody else can still open and print the PDF.
You can do this easily with the iOS version of the Debenu Quick PDF Library. Download the sample project and modify it with the sample code below:
How to embed a file
[DQPL LoadFromFile:path_of_my_PDF_file :#""]; //load your existing PDF file
[DQPL EmbedFile:#"Original_custom_document" :path_of_the_original_custom_document :#""]; //specify the name and the location of the attachment
[DQPL SaveToFile:new_path];
How to find the filenames of the attachments (skip if you have only one attached file)
[DQPL LoadFromFile:new_path :#""];
NSString *listItem;
int fileCount = [DQPL EmbeddedFileCount]; //returns the number of attached files
for( int count = 1; count <= fileCount; count++ ){
listItem = [DQPL GetEmbeddedFileStrProperty:count :1]; //returns the filename of the attached file
//show/read or save the returned filenames and the index of it...
}
How to extract an attached file
[DQPL LoadFromFile:new_path :#""];
[DQPL GetEmbeddedFileContentToFile:1 :path_and_filename_to_write_the_extracted_attachment]; //specify where do you want to save the extracted attachment (in this case the index of the attachment is 1)
Pal
(Debenu Team)

Copying file from local to SharePoint server location

Now on my PC I can use explorer to open a location on our SP server (location eg http://sp.myhost.com/site/Documents/). And from there I can copy/paste a file from eg my C:\ drive.
I need to replicate the copy process progmatically. FileCopy() doesn't do it - seems to be the http:// bit that's causing problems!
Does the server allow WebDAV access? If yes, there are WebDAV clients for Delphi available, including Indy 10.
In case if you are not using BLOB storage all SharePoint files are stored in the database as BLOB objects.
When you access your files with explorer you are using windows service which is reading files from SharePoiont and render it to you. This way you can copy and paste as soon as donwload them from an to SharePoint manually.
To be able to do this automatically you should achive this using the next SP API code:
using (SPSite site = new SPSite("http://testsite.dev"))
{
using (SPWeb web = site.OpenWeb())
{
using (FileStream fs = File.OpenRead(#"C:\Debug.txt"))
{
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, (int) fs.Length);
SPList list = web.GetList("Lists/Test AAD");
SPFile f = list.RootFolder.Files.Add("/Shared Documents/"+Path.GetFileName(fs.Name), buffer);
}
}
}
This will add new "Debug.txt" file to the "Shared Documents" library read from the disk C. To do this for each file just loop through each file in the folder. You can open web only once and do the loop each time when you add file...
Hope it helps,
Andrew

Resources