So I have achieved zipping the files but now I am having this another issues that the zip folder contains empty file. The size of the file zipped is 0 bytes.
This is how I am zipping my file
try
{
var outPutDirectory = AppDomain.CurrentDomain.BaseDirectory;
string logoimage = Path.Combine(outPutDirectory, "images\\error.png");
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.BufferOutput = false;
HttpContext.Current.Response.ContentType = "application/zip";
HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename=pauls_chapel_audio.zip");
using (MemoryStream ms = new MemoryStream())
{
// create new ZIP archive within prepared MemoryStream
using (ZipArchive zip = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
var demoFile = zip.CreateEntry(logoimage);
// add some files to ZIP archive
}
ms.WriteTo(HttpContext.Current.Response.OutputStream);
}
return true;
}
Another issue is that the zipped folder has the same path as that of the image. So it is like
ZippFolder/A/B/C/image...
I just need
ZipFolder/content
var demoFile = zip.CreateEntry(logoimage);
This creates an entry in the ZIP file that has the name logoimage (i.e. /A/B/C/images/error.png or whatever is the full path).
But you never write to that entry, so it’s empty. Also if you want to have a different path, you should specify it there:
var demoFile = zip.CreateEntry("content\\error.png");
using (StreamWriter writer = new StreamWriter(demoFile.Open()))
using (StreamReader reader = new StreamReader(logoimage))
{
writer.Write(reader.ReadToEnd());
}
Alternatively, you could also skip the StreamWriter completely, and just write to the stream directly:
using (Stream stream = demoFile.Open())
using (StreamReader reader = new StreamReader(logoimage))
{
reader.BaseStream.CopyTo(stream);
}
Btw. you can skip the outer MemoryStream in which you want to write your zip file first and then write that stream to the OutputStream. Instead, you can just write to that stream directly. Just pass it to the ZipFile constructor:
Stream output = HttpContext.Current.Response.OutputStream;
using (ZipArchive zip = new ZipArchive(output, ZipArchiveMode.Create, true))
{
…
}
Related
I am trying to create a ZipArchive in memory and append several entries with binary data from database. The problem is that after loop, zip sent to client is invalid/empty. Can you please check my code?
using (MemoryStream _memory_stream = new MemoryStream())
{
using (ZipArchive _archive = new ZipArchive(_memory_stream, ZipArchiveMode.Create, true))
{
foreach (byte[] binaryData in this.FileBinaries)
{
ZipArchiveEntry _entry = _archive.CreateEntry(str_filename, CompressionLevel.Optimal);
using (Stream _entryStream = _entry.Open())
{
using (StreamWriter _writer = new StreamWriter(_entryStream))
{
_writer.Write(binaryData);
}
_entryStream.Close();
}
}
}
Response.AppendHeader("content-disposition", "attachment; filename=certificates.zip");
Response.ContentType = "application/zip";
Response.Write(_memory_stream);
}
What I'm looking for is zip/compress S3 files without having them first downloaded to EFS or on a file system and then upload the zip file back to S3. Is there a C# way to achieve the same? I found the following post, but not sure its C# equivalent
https://www.antstack.io/blog/create-zip-using-lambda-with-files-streamed-from-s3/
I've written following code to zip files from a MemoryStream
public static void CreateZip(string zipFileName, List<FileInfo> filesToZip)
{
//zipFileName is the final zip file name
LambdaLogger.Log($"Zipping in progress for: {zipFileName}");
using (MemoryStream zipMS = new MemoryStream())
{
using (ZipArchive zipArchive = new ZipArchive(zipMS, ZipArchiveMode.Create, true))
{
//loop through files to add
foreach (var fileToZip in filesToZip)
{
//read the file bytes
byte[] fileToZipBytes = File.ReadAllBytes(fileToZip.FullName);
ZipArchiveEntry zipFileEntry = zipArchive.CreateEntry(fileToZip.Name);
//add the file contents
using (Stream zipEntryStream = zipFileEntry.Open())
using (BinaryWriter zipFileBinary = new BinaryWriter(zipEntryStream))
{
zipFileBinary.Write(fileToZipBytes);
}
}
}
using (FileStream finalZipFileStream = new FileStream(zipFileName, FileMode.Create))
{
zipMS.Seek(0, SeekOrigin.Begin);
zipMS.CopyTo(finalZipFileStream);
}
}
}
But problem is how to make it read file directly from S3 and upload the compressed file.
public static async Task CreateZipFile(List<List<KeyVersion>> keyVersions)
{
using MemoryStream zipMS = new MemoryStream();
using (ZipArchive zipArchive = new ZipArchive(zipMS, ZipArchiveMode.Create, true))
{
foreach (var key in keyVersions)
{
foreach (var fileToZip in key)
{
GetObjectRequest request = new GetObjectRequest
{
BucketName = "dev-s3-zip-bucket",
Key = fileToZip.Key
};
using GetObjectResponse response = await s3client.GetObjectAsync(request);
using Stream responseStream = response.ResponseStream;
ZipArchiveEntry zipFileEntry = zipArchive.CreateEntry(fileToZip.Key);
//add the file contents
using Stream zipEntryStream = zipFileEntry.Open();
await responseStream.CopyToAsync(zipEntryStream);
}
}
zipArchive.Dispose();
}
zipMS.Seek(0, SeekOrigin.Begin);
var fileTxfr = new TransferUtility(s3client);
await fileTxfr.UploadAsync(zipMS, "dev-s3-zip-bucket", "test.zip");
}
I am reading a docx file using DocumentFormat.OpenXml lib.
I am manipulating the file and need to write it to the disk.
Doing this using the openxml lib is no brainer, the problem is that I need to pass the file content (byte[]) to a different API in my code and this API is handling the save operation.
This api is using File.WriteAllBytes. When I try to save my file via File.WriteAllBytes I get XML inside the doc instead of the doc read content.
How can I extract the byte[] from the doc and save it to the disc using File.WriteAllBytes
var path = "path/to/doc.docx";
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(path, true))
{
string docText = null;
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
{
docText = sr.ReadToEnd();
}
docText = new Regex("BBB").Replace(docText, "CCC!");
// here i will manipuldate docText
MemoryStream ms = new MemoryStream();
using (WordprocessingDocument wordDocument =
WordprocessingDocument.Create(ms , WordprocessingDocumentType.Document, true))
{
MainDocumentPart mainPart = wordDocument.AddMainDocumentPart();
Body body = new Body(new Paragraph(new Run(new Text(docText))));
mainPart.Document = new Document(body);
}
File.WriteAllBytes("path/to/cloned.docx", ms.ToArray());
}
this should do the trick:
(tested with SampleDoc.docx from Github)
var path = #"path/to/doc.docx";
byte[] byteArray = File.ReadAllBytes(path);
using (MemoryStream stream = new MemoryStream())
{
stream.Write(byteArray, 0, (int)byteArray.Length);
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(stream, true))
{
Body body = wordDoc.MainDocumentPart.Document.Body;
foreach (var text in body.Descendants<Text>())
{
text.Text = text.Text.Replace("BBB", "CCC!");
}
wordDoc.Close();
}
File.WriteAllBytes(path+".mod.docx", stream.ToArray());
}
debug output:
It looks like you want to manipulate the raw XML, so you actually shouldn't use DocumentFormat.OpenXml at all--just treat your docx like the raw ZIP file that it is. Here is some sample code:
using System.IO;
using System.IO.Compression;
public static byte[] Change(string path)
{
// Make a temporary directory
var myTempDir = new DirectoryInfo(Path.Join(Path.GetTempPath(), Path.GetRandomFileName() ));
myTempDir.Create();
// Extract all the XML files in the docx to that temporary directory
using (ZipArchive zipArchive = ZipFile.OpenRead(path))
zipArchive.ExtractToDirectory(myTempDir.FullName);
// Read in the main document XML
FileInfo docFile = new FileInfo(Path.Join(myTempDir.FullName, "word", "document.xml"));
string rawXML = File.ReadAllText(docFile.FullName);
// Manipulate it-- warning, this could break the whole thing
rawXML = rawXML.Replace("winter", "spring");
// Save the manipulated xml back over the old file
docFile.Delete();
File.WriteAllText(docFile.FullName, rawXML);
// Zip our temporary directory back into a docx file
FileInfo tempFile = new FileInfo(Path.GetTempFileName());
ZipFile.CreateFromDirectory(myTempDir.FullName, tempFile.FullName);
// Read the raw bytes in from our new file
byte[] rawBytes = File.ReadAllBytes(tempFile.FullName);
return rawBytes;
}
You might want to delete all those temp files, too--but I'll leave that part to you.
I am using Zip Archive to create a zip folder with various files and subfolders and returning it as a memory stream like so.
public MemoryStream CreateAZipFolder(){
var stMarged = new System.IO.MemoryStream();
stMarged.Position = 0;
using (MemoryStream zipStream = new MemoryStream())
{
using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
{
string[] fileEntries = Directory.GetFiles(#"C:\Applications\folder");
foreach (var fileName in fileEntries)
{
zip.CreateEntryFromFile(fileName, "Applications/folder/" + Path.GetFileName(fileName),
CompressionLevel.Optimal);
}
ZipArchiveEntry batchEntry = zip.CreateEntry("mybatchFile.bat");
using (StreamWriter writer = new StreamWriter(batchEntry.Open()))
{
writer.Write(batchFile);
}
//Add the xml file to zip folder
ZipArchiveEntry entry = zip.CreateEntry("nCounterConfig.xml");
using (StreamWriter writer = new StreamWriter(entry.Open()))
{
writer.Write(xdoc.OuterXml);
}
}
zipStream.Position = 0;
return zipStream;
I would like to add a directory with sub directories and files to this memory stream. I found that ZipFile has a method "CreateFromDirectory" which would be ideal except it requires a paramater for an output folder the method also does not have a return type. How can i zip all the files and subfolders in a directory and add them to my memory stream using ZipFile?
something like this
zip.CreateEntry(ZipFile.CreateFromDirectory(
#"C:\morefilestozip\", "",
CompressionLevel.Fastest, true));
I have a function that requires a Filestream as input.
I want to hand several Files to that function which I get from uploaded zip-Files.
Is it possible to create the Filestream without extracting the file to a temporary folder?
I imagin something like this:
string path = #"C:\somepathtomyzip";
string filepath = "nameofimagefile"
using (ZipArchive archive = ZipFile.OpenRead(path))
{
ZipArchiveEntry entry = archive.GetEntry(file_path);
//generate Filestream from entry
myFunction(filestreamIneed);
}
You can use ZipArchiveEntry.Open() and copy the output from the returned Stream instance to a FileStream instance:
using (ZipArchive archive = ZipFile.OpenRead(path))
{
ZipArchiveEntry entry = archive.GetEntry(file_path);
var memoryStream = return entry.Open();
using (var fileStream = new FileStream(fileName, FileMode.CreateNew, FileAccess.ReadWrite))
{
memoryStream.CopyTo(fileStream); // fileStream is not populated
}
}