System.IO: Convert zip file to byte[] without saving file - c#

I'm having trouble using the System.IO.Compression library to create a zip file and then return the byte[] for that zip file. So I want the method to take an input string--the path for the file to be zipped--and return the corresponding byte array for the file once it's been zipped. Currently, I can save the zip file to some known path and then use System.IO.File.ReadAllBytes(path) to get the byte[].
But how can I do this if I don't know beforehand where that zip file should end up (if anywhere at all)? My attempt at the solution is below. It doesn't seem to be working because when I try to reconstruct the zip file from the byte array it says that the archive is in an unknown format or damaged. Note: I've been able to do this using the Ionic DotNetZip library; however, I'm trying to do the same with only the use of System.IO libraries.
Any ideas on how to go about this?
private static byte[] CreateZipAndFindBytes(string importfile)
{
byte[] retVal = null;
using (System.IO.MemoryStream memStream = new System.IO.MemoryStream())
{
//ZipArchive(Stream, ZipArchiveMode, Boolean) //true means leave stream open
using (System.IO.Compression.ZipArchive archive = new System.IO.Compression.ZipArchive(memStream, System.IO.Compression.ZipArchiveMode.Create, true))
{
archive.CreateEntryFromFile(importfile, "test.zip"); //adds the file to the zip
}
retVal = memStream.ToArray();
}
return retVal;
}

entryName, the second parameter of CreateEntryFromFile is supposed to be "The name of the entry to create in the zip archive." It's not the name of your zip file.
you're zipping the import file, but also renaming it with a .zip extension, and I'm assuming that the import file is not actually a zip.
do this instead
archive.CreateEntryFromFile(importfile, importfile); //adds the file to the zip

Related

C# api octet-stream response body to zip file

I have a service which executes a request to a client api that returns a octet-stream response body with the Content-Disposition header in it (This api is meant to return a zip file.). I am using RestSharp and the DownloadData function to get the response as a byte array, but I want to then save the zip file to my local server.
I have tried using DotNetZip and a MemoryStream to create the zip file by using the following example:
using (MemoryStream stream = new MemoryStream(fileBytes))
{
using (ZipFile zip = new ZipFile())
{
zip.AddEntry("test", stream);
zip.Save(filePath);
}
}
The code above creates a zip file and an entry called test but I cannot open it.
Just to clarify, the zip file I am trying to create contains the following files and folders:
296927a0-5ac7-4ccd-9928-bd74ef7ae68a_20200227074457 (Root folder)
images (folder)
jpg image
jpg image
jpg image
details.json (file)
achievements.json (file)
evaluation.json (file)
Is there any way to achieve this?
As I understood the fileBytes is already a zip file byte stream, what means you don't need to zip it again. Just save as file.
File.WriteAllBytes(filePath, fileBytes);
For anyone else who encounters this problem, as in saving the byte array to disk and getting a corrupted zip file, I have figured out the answer with the help of Dennis Tretyakov.
Basically, when downloading a octet-stream, the first section of is dedicated to the structure of the zip file. In my case the first section of the zip file was:
--c7c2ad44-881c-47c4-89e5-323f91b75269
Content-Disposition: form-data; name="deb08d79-372d-4de2-a684-1298f25fecd9_20200310142909.zip"
Content-Type: application/octet-stream
And thereafter the actual data for the zip file appears after a linebreak.
What I ended up doing was calculating the byte count of the "header" section by converting the byte array to a string:
string stringEncodedBytes = Encoding.ASCII.GetString(response.RawBytes);
Then with knowing the starting point of the zip file data, finding the index of the starting point:
int headerSectionIndex = stringEncodedBytes.IndexOf("PK");
Once I found the index, which in my case always seems to be 178, I simple removed that part of the byte array and then copy the trimmed byte array to a new byte array and write it to disk:
byte[] trimmedFileBytes = new byte[response.RawBytes.Length - headerSectionIndex];
Array.Copy(response.RawBytes, headerSectionIndex, trimmedFileBytes, 0, trimmedFileBytes.Length);
File.WriteAllBytes(filePath, trimmedFileBytes);
I would suggest that anyone struggling with the same issue, open the "corrupted" zip file in notepad++ and take a look at the first section and then determine where the data section of the zip file starts.
The initial zip file data looks like this:
And the trimmed zip file data looks like this:
So i had the same issue Dev_101 had, in which a RestResponse was corrupting the .zip file, however in my case, it was just appending an extra " on the beginning and end, so I just needed to remove the " and Base64Decode it and saved perfectly.

Extract zip MemoryStream to string

I am using DotNetZip Library to save MemoryStream to .xml data and read its text form saved loacation:
using (ZipFile zip = ZipFile.Read(myMs))
{
zip[0].Extract(#"C:\XmlFilePath\MyXml.xml", ExtractExistingFileAction.OverwriteSilently);
}
Is there any way to read Xml string on extracting without saving it in file or temp file using this library? Please Help. Thanks.
You should be able to get a stream from zip[0].OpenReader() and read your string from that.

DeflateStream CopyTo writes nothing and throws no exceptions

I've basically copied this code sample directly from msdn with some minimal changes. The CopyTo method is silently failing and I have no idea why. What would cause this behavior? It is being passed a 78 KB zipped folder with a single text file inside of it. The returned FileInfo object points to a 0 KB file. No exceptions are thrown.
public static FileInfo DecompressFile(FileInfo fi)
{
// Get the stream of the source file.
using (FileStream inFile = fi.OpenRead())
{
// Get original file extension,
// for example "doc" from report.doc.cmp.
string curFile = fi.FullName;
string origName = curFile.Remove(curFile.Length
- fi.Extension.Length);
//Create the decompressed file.
using (FileStream outFile = File.Create(origName))
{
// work around for incompatible compression formats found
// here http://george.chiramattel.com/blog/2007/09/deflatestream-block-length-does-not-match.html
inFile.ReadByte();
inFile.ReadByte();
using (DeflateStream Decompress = new DeflateStream(inFile,
CompressionMode.Decompress))
{
// Copy the decompression stream
// into the output file.
Decompress.CopyTo(outFile);
return new FileInfo(origName);
}
}
}
}
In a comment you say that you are trying to decompress a zip file. The DeflateStream class can not be used like this on a zip file. The MSDN example you mentioned uses DeflateStream to create individual compressed files and then uncompresses them.
Although zip files might use the same algorithm (not sure about that) they are not just compressed versions of a single file. A zip file is a container that can hold many files and/or folders.
If you can use .NET Framework 4.5 I would suggest to use the new ZipFile or ZipArchive class. If you must use an earlier framework version there are free libraries you can use (like DotNetZip or SharpZipLib).

Creating a zipped Document that containing files from memory stream / byte array in C#

I'm needing to create a zipped document containing files that exist on the server. I am using the Ionic.Zip to do so, and to create a new Package (which is the zip file) I have to have either a path to a physical file or a stream. I am trying to not create an actual file that would be the zip file, instead just create a stream that would exist in memory or something. how can i do this?
Create the package using a MemoryStream then.
You can try the save method in the ZipFile Class. It can save to a stream
try this.
using (MemoryStream ms = new MemoryStream())
{
using (Ionic.Zip.ZipFile zipFile = new Ionic.Zip.ZipFile())
{
zipFile.AddFiles(filesToBeZipped, false, "NewFolder");//filesTobeZipped is a List<string>
zipFile.Save(ms);
}
}
You'll want to use the .AddEntry method on the ZipFile you've created specifying a name and the byte[] containing the actual file data.
ex.
ZipFile zipFile = new ZipFile();
zipFile.AddEntry(file.FileName, file.FileData);
where file.FileName will be the entry name (in the zip file) and file.FileData is the byte array.

GZipStream not working

I am using the following C# code to compress a file:
// Open the stream we want to compress
FileStream fs = File.Create(#"C:\Projects\Samples\test\compressed.zip", 0);
// Creates the GZipStream
GZipStream gzip = new GZipStream(fs, CompressionMode.Compress);
// Reading the content to compress
byte[] bytes = File.ReadAllBytes(#"C:\Projects\Samples\samplefile.xml");
// Writing compressed content
gzip.Write(bytes, 0, bytes.Length);
gzip.Close(); // This also closes the FileStream (the underlying stream)
However, when I extract the file from windows explorer the file loses it's extension so instead of samplefile.xml it just becomes samplefile. Same thing happened with .txt file not just .xml file.
Can you help me see what I'm doing wrong?
ok found the problem:
Line 2 has to be as follows:
FileStream fs = File.Create(#"C:\Projects\Samples\test\compressed.xml.zip", 0);
GZipStream doesn't create zip archives. It creates a gzip file, which contains only one file, and doesn't necessarily store a filename at all. Normally you should use the .gz extension to identify a gzip file, and it's conventional to use the entire name of the original file with .gz appended on the end. See also here for more information about gzip format: http://en.wikipedia.org/wiki/Gzip#File_format
If you actually want to create zip archives, you might want to use a library like SharpZipLib: http://www.icsharpcode.net/opensource/sharpziplib/

Categories

Resources