This is a follow-on question from here: Decompress Stream to String using SevenZipSharp.
The following code works in the sense that it takes a string and successfully compresses and decompresses it.
using System;
using System.IO;
using SevenZip;
namespace _7ZipWrapper
{
public class ProgramOriginal
{
public static void Main()
// This should be broken into separate methods
{
// Setup Input String
var strToCompress = "This String"; // will pass as parameter
var memStreamToCompress = new MemoryStream();
var StringToStream = new StreamWriter(memStreamToCompress);
StringToStream.Write(strToCompress);
StringToStream.Flush();
// Confirm the Input Stream is As-Expected
memStreamToCompress.Position = 0;
var MemoryAsString = new StreamReader(memStreamToCompress);
Console.WriteLine("Stream in memory: " + MemoryAsString.ReadToEnd());
Console.ReadKey();
// Setup the SevenZip Dll
SevenZipCompressor.SetLibraryPath(@"C:\Temp\7za64.dll");
// Set up a compressor...
SevenZipCompressor SevenZipC = new SevenZipCompressor();
SevenZipC.CompressionMethod = CompressionMethod.Ppmd;
SevenZipC.CompressionLevel = global::SevenZip.CompressionLevel.Ultra;
SevenZipC.ScanOnlyWritable = true;
// Compress PassedStream -> CompressedStream
var compressedMemoryStream = new MemoryStream();
SevenZipC.CompressStream(memStreamToCompress, compressedMemoryStream, "Optional Password Field");
compressedMemoryStream.Position = 0;
StreamReader compressedMemoryAsString = new StreamReader(compressedMemoryStream);
// Show that we have a compressed String
compressedMemoryStream.Position = 0;
Console.WriteLine(compressedMemoryAsString.ReadToEnd());
Console.ReadKey();
// Set up a decompressor... (only needs to know what to decompress)
compressedMemoryStream.Position = 0;
var SevenZipE = new SevenZip.SevenZipExtractor(compressedMemoryStream, "Optional Password Field");
// Decompress CompressedStream
var DecompressedMemoryStream = new MemoryStream();
SevenZipE.ExtractFile(0, DecompressedMemoryStream);
// Show that DecompressedMemoryStream is valid
DecompressedMemoryStream.Position = 0;
StreamReader decompressedStreamAsText = new StreamReader(DecompressedMemoryStream);
Console.WriteLine("Decompressed String: " + decompressedStreamAsText.ReadToEnd());
Console.ReadKey();
}
}
}
However, the above code obviously does little good in its current form (this is destined to become a COM DLL).
I thought I was home-and-hosed and that refactoring would be a cinch, However, my attempts to rearranging the code into something useful have left me at a loss as to why the following code throws a System.ArgumentException ('The stream is invalid or no corresponding signature was found.') but the code above runs without issue.
Fundamentally there must be some sort of difference but I'm at a loss as to what causes it, and how to resolve. A solution accompanied with a brief explanation will be much appreciated.
using System;
using System.IO;
using SevenZip;
namespace _7ZipWrapper
{
public class Program
{
public static void Main()
{
// Setup Input String
var strToCompress = "This String"; // will eventually pass as parameter
// Convert input string to memory stream
var memStreamToCompress = StringToStream(strToCompress);
// Confirm the Input Stream is As-Expected
memStreamToCompress.Position = 0;
var MemoryAsString = new StreamReader(memStreamToCompress);
Console.WriteLine("Stream in memory: " + MemoryAsString.ReadToEnd());
Console.ReadKey();
// Compress the Stream
memStreamToCompress.Position = 0;
var compressedString = StreamCompress(memStreamToCompress, "password");
// Decompress the String
var memStreamToRestore = StringToStream(compressedString);
memStreamToRestore.Position = 0;
var decompressedString = StreamDecompress(memStreamToRestore, "password");
Console.WriteLine(decompressedString);
Console.ReadKey();
}
private static MemoryStream StringToStream(string strToMemoryStream)
{
var memoryStream = new MemoryStream();
var writer = new StreamWriter(memoryStream);
writer.Write(strToMemoryStream);
writer.Flush();
return memoryStream;
}
private static MemoryStream StringToStream1(string strToMemoryStream)
{
var memoryStream = new MemoryStream();
var writer = new StreamWriter(memoryStream);
writer.Write(strToMemoryStream);
writer.Flush();
return memoryStream;
}
private static string StreamCompress(MemoryStream memStreamToCompress, string optionalPassword)
{
// Setup the SevenZip Dll
SevenZipCompressor.SetLibraryPath(@"C:\Temp\7za64.dll");
// Set up a compressor...
SevenZipCompressor SevenZip = new SevenZipCompressor();
SevenZip.CompressionMethod = CompressionMethod.Ppmd;
SevenZip.CompressionLevel = global::SevenZip.CompressionLevel.Ultra;
SevenZip.ScanOnlyWritable = true;
// Compress PassedStream -> CompressedStream
var compressedMemoryStream = new MemoryStream();
SevenZip.CompressStream(memStreamToCompress, compressedMemoryStream, optionalPassword); // "Optional Password Field"
compressedMemoryStream.Position = 0;
StreamReader compressedMemoryAsString = new StreamReader(compressedMemoryStream);
return compressedMemoryAsString.ReadToEnd();
}
private static string StreamDecompress(MemoryStream compressedMemoryStream, string optionalPassword)
{
// Setup the SevenZip Dll
SevenZipExtractor.SetLibraryPath(@"C:\Temp\7za64.dll");
// Set up a decompressor... (only needs to know what to decompress)
compressedMemoryStream.Position = 0;
// CRASHES Next Line: System.ArgumentException: 'The stream is invalid or no corresponding signature was found.'
var SevenZip = new SevenZip.SevenZipExtractor(compressedMemoryStream, optionalPassword);
// Decompress CompressedStream
var DecompressedMemoryStream = new MemoryStream();
SevenZip.ExtractFile(0, DecompressedMemoryStream);
// Show that DecompressedMemoryStream is valid
DecompressedMemoryStream.Position = 0;
StreamReader decompressedStreamAsText = new StreamReader(DecompressedMemoryStream);
return decompressedStreamAsText.ReadToEnd();
}
}
}
Note: While I appreciate there may be multiple issues with this code I'm learning and intend to put the next iteration up on CodeReview. That said, feel free to offer suggestions but right now this is a learning exercise for me. TIA
Your working code decompressed
compressedMemoryStream
. Your broken code decompressed a string created fromcompressedMemoryStream
.As I said in your previous question, the result of compression is not text. If you must represent it as text, you should use Base64 or hex. But just reading from it as if it's UTF-8-encoded text (which is what you're doing now) simply will not work.
The result of your
StreamCompress
method should probably be abyte[]
. That's easy to achieve:When you want to decompress, you can just create a
MemoryStream
to wrap that byte array, as one of many options.If you really need the result as a string, you can then call
Convert.ToBase64String
, then later callConvert.FromBase64String
to get back the original bytes. This will not lose information, unlike your current approach.I should also point out that unless you want 7zip-specific compression, there are plenty of purely-managed compression libraries available too.
C# compress and decompress string using SevenZipSharp
Basic problem was that I was not using strings properly, converting memory stream to string does not work. Solution uses base64 encoding to make the compressed string portable; this enables it to be stored in an XML / JSON file which suits my needs. Thank you @Daisy Shipton (see: this answer).
Coming from VBA the use of constructors (passing an argument while newing) was not immediately obvious, but this helps. This was the key:
In the hopes that this helps someone else: