I'm new to C# and using C#.Net 2.0 with Visual Studio 2005.
How can I create a zip file from a string using GZipStream. (I don't want to use any third party libraries and doing this purely using C#.)
FYI: Scenario is this. Already there is a zip file in a folder. I need to encode this zip file stream in Base64 and again zip the Base 64 encoded string. (Creating a new zip file from Base64 encoded original zip file).
Appreciate your help.
Thanks,
Chatura
Thanks Bueller for the reply. But without using any external libraries I could do it. Here is the code snippet. This is not the final code with all try/ catch etc. May be useful for others.
private static void CreateZipFromText(string text)
{
byte[] byteArray = ASCIIEncoding.ASCII.GetBytes(text);
string encodedText = Convert.ToBase64String(byteArray);
FileStream destFile = File.Create("C:\\temp\\testCreated.zip");
byte[] buffer = Encoding.UTF8.GetBytes(encodedText);
MemoryStream memoryStream = new MemoryStream();
using (System.IO.Compression.GZipStream gZipStream = new System.IO.Compression.GZipStream(destFile, System.IO.Compression.CompressionMode.Compress, true))
{
gZipStream.Write(buffer, 0, buffer.Length);
}
}
I am assuming you actually mean using the .zip archive format versus another format such as .gz. The .Net 2.0 compression libraries do not out of the box support zip format archives. The GZipStream and such compress to and from gzip format. There is an article here that shows how to support zip in C# without external libraries but I have not tried or tested it. You can find similar articles around but you have to dig to find the pure C# .NET no external library articles.
http://www.codeproject.com/KB/recipes/ZipStorer.aspx
Related
I'm using SharpZipLib to extract archives. I managed to extract .zip archives:
FastZip fastZip = new FastZip();
fastZip.ExtractZip(file, directory, null);
and to extract .tar.gz:
// Use a 4K buffer. Any larger is a waste.
byte[] dataBuffer = new byte[4096];
using (Stream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read))
{
using (GZipInputStream gzipStream = new GZipInputStream(fileStream))
{
// Change this to your needs
string fnOut = Path.Combine(directory, Path.GetFileNameWithoutExtension(file));
using (FileStream fsOut = File.Create(fnOut))
{
StreamUtils.Copy(gzipStream, fsOut, dataBuffer);
}
}
}
Is there also a way to extract any kind of archive where I don't need to know the type of archive upfront? (e.g. SharpZipLib.ExtractAnyArchive(file, directory))
SharpZipLib unfortunately is currently not able to auto-detect the format of an archive file/stream.
You either have to implement the functionality by yourself in some form, or seek an alternative library that is able to auto-detect the format of an archive. An example of such a library would be SharpCompress, however, as you already noted in the comments, different libraries can come with different kind of limitations and bugs that might affect the functionality of your software.
If you decide to roll your own auto-detection functionality for SharpZipLib, you can choose different approaches, like
Try opening an (unknown) archive using the archive (reader/stream) classes for every archive format supported by SharpZipLib, until you find one which can open and process the archive file successfully.
Implement some format detection routine that scans an archive file/stream for 'magic' signature bytes identifying a particular archive format. If the format of an archive file/stream has been thus identified, select and use the appropriate SharpZipLib classes for handling the detected archive format.
I am using ASP.NET and I prefer VB as the language, but I should be able to translate C# for my needs.
I have an array of strings which I would like to send to the browser as individual files for the user to save. In searching the internet, the most common solution to send multiple files to a browser is to zip them up, and send a single zip file.
Towards that end, I need to learn a few things I do not know;
1) What tool/methods (preferably built in to ASP.NET running on IIS7) can I use to create a zip filestream to send to a browser?
2) How do I fool the zip tool into thinking it is getting multiple files from strings in memory? I assume I need to create filestreams, but how do I tell the methods what the file name is, etc.?
If there is an example of doing something substantially similar to what I need available, that would be great. Just point me at it.
Thanks for the help.
The approach could be:
Convert the string into stream
Add data from that stream into the zip file
Write the zip file into response stream
Code example below:
ZipFile zipFile = new ZipFile();
int fileNumber = 1;
foreach(string str in strArray)
{
// convert string to stream
byte[] byteArray = Encoding.UTF8.GetBytes(contents);
MemoryStream stream = new MemoryStream(byteArray);
stream.Seek(0, SeekOrigin.Begin);
//add the string into zip file with a name
zipFile.AddEntry("String" + fileNumber.ToString() + ".txt", "", stream);
}
Response.ClearContent();
Response.ClearHeaders();
Response.AppendHeader("content-disposition", "attachment; filename=strings.zip");
zipFile.Save(Response.OutputStream);
zipFile.Dispose();
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).
I will like to compress a file before sending it through the network. I think the best approach is 7zip because it is free and open source.
How I use 7zip with .net?
I know that 7zip is free and that they have the source code in c# but for some reason it is very slow on c# so I rather call the dll 7z.dll that comes when installing 7zip for performance reasons. So the way I am able to eassily marshal and call the methods in 7z.dll is with the help of the library called sevenzipsharp . For example adding that dll to my project will enable me to do:
// if you installed 7zip 64bit version then make sure you change plataform target
// like on the picture I showed above!
SevenZip.SevenZipCompressor.SetLibraryPath(#"C:\Program Files\7-Zip\7z.dll");
var stream = System.IO.File.OpenRead(#"SomeFileToCompress.txt");
var outputStream = System.IO.File.Create("Output.7z");
SevenZip.SevenZipCompressor compressor = new SevenZip.SevenZipCompressor();
compressor.CompressionMethod = SevenZip.CompressionMethod.Lzma2;
compressor.CompressionLevel = SevenZip.CompressionLevel.Ultra;
compressor.CompressStream(stream, outputStream);
that's how I use 7zip within c#.
Now my question is:
I will like to send a compressed file over the network. I know I could compress it first then send it. The file is 4GB so I will have to wait a long time for it to compress. I will be wasting a lot of space on hard drive. then I will finally be able to send it. I think that is to complicated. I was wondering how it will be possible to send the file meanwhile it is being compressed.
It seems to be a problem with SevenZipSharp:
Have you considered an alternate library - one that doesn't even require 7-Zip to be installed / available?
From the description posted at http://dotnetzip.codeplex.com/ :
creating zip files from stream content, saving to a stream, extracting
to a stream, reading from a stream
Unlike 7-Zip, DotNetZip is designed to work with C# / .Net.
Plenty of examples - including streaming, are available at http://dotnetzip.codeplex.com/wikipage?title=CS-Examples&referringTitle=Examples .
Another option is to use the 7-Zip Command Line Version (7z.exe), and write to/read from standard in/out. This would allow you to use the 7-Zip file format, while also keeping all of the core work in native code (though there likely won't be much of a significant difference).
Looking back at SevenZipSharp:
Since the 0.29 release, streaming is supported.
Looking at http://sevenzipsharp.codeplex.com/SourceControl/changeset/view/59007#364711 :
it seems you'd want this method:
public void CompressStream(Stream inStream, Stream outStream)
Thank you for considering performance here! I think way too many people would do exactly what you're trying to avoid: compress to a temp file, then do something with the temp file.
CompressStream threw an exception. My code is as follows:
public void TestCompress()
{
string fileToCompress = #"C:\Users\gary\Downloads\BD01.DAT";
byte[] inputBytes = File.ReadAllBytes(fileToCompress);
var inputStream = new MemoryStream(inputBytes);
byte[] zipBytes = new byte[38000000]; // this memory size is large enough.
MemoryStream outStream = new MemoryStream(zipBytes);
string compressorEnginePath = #"C:\Engine\7z.dll";
SevenZipCompressor.SetLibraryPath(compressorEnginePath);
compressor = new SevenZip.SevenZipCompressor();
compressor.CompressionLevel = CompressionLevel.Fast;
compressor.CompressionMethod = CompressionMethod.Lzma2;
compressor.CompressStream(inputStream, outputStream);
inputStream.Close();
outputStream.Close();
The exception messages:
Message: Test method Test7zip.UnitTest1.TestCompress threw exception:
SevenZip.SevenZipException: The execution has failed due to the bug in the SevenZipSharp.
Please report about it to http://sevenzipsharp.codeplex.com/WorkItem/List.aspx, post the release number and attach the archive
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/