为什么?重构后的 C# 错误:'The stream is invalid or no corresponding signature was found.'
Why? C# Error after Refactor: 'The stream is invalid or no corresponding signature was found.'
这是来自此处的后续问题:。
以下代码的工作原理是它接受一个字符串并成功地压缩和解压缩它。
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:\Tempza64.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();
}
}
}
但是,上面的代码在目前的形式下显然没有什么好处(这注定要成为一个 COM DLL)。
我以为我是在家和水管,重构将是小菜一碟,但是,我尝试将代码重新排列成有用的东西让我不知所措,为什么下面的代码会抛出 System.ArgumentException ('The stream is invalid or no corresponding signature was found.') 但上面的代码运行没有问题。
从根本上说肯定存在某种差异,但我不知道是什么原因造成的,也不知道如何解决。将不胜感激附有简短解释的解决方案。
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:\Tempza64.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:\Tempza64.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();
}
}
}
注意:虽然我知道这段代码可能存在多个问题,但我正在学习并打算将下一次迭代放在 CodeReview 上。也就是说,请随时提出建议,但现在这对我来说是一个学习练习。 TIA
您的工作代码已解压缩 compressedMemoryStream
。您损坏的代码解压缩了从 compressedMemoryStream
.
创建的 string
正如我在你之前的问题中所说,压缩的结果不是文本。如果您必须将其表示为文本,则应使用 Base64 或十六进制。但是,就好像它是 UTF-8 编码的文本(这就是您现在正在做的)一样读取它根本行不通。
您的 StreamCompress
方法的结果可能应该是 byte[]
。这很容易实现:
// Note: changed input type to just Stream to make it more general
private static byte[] StreamCompress(Stream input, string optionalPassword)
{
SevenZipCompressor.SetLibraryPath(@"C:\Tempza64.dll");
SevenZipCompressor SevenZip = new SevenZipCompressor();
SevenZip.CompressionMethod = CompressionMethod.Ppmd;
SevenZip.CompressionLevel = global::SevenZip.CompressionLevel.Ultra;
SevenZip.ScanOnlyWritable = true;
var output = new MemoryStream();
SevenZip.CompressStream(input, output, optionalPassword);
// You don't even need to rewind when you call ToArray
return output.ToArray();
}
当你想解压缩时,你可以创建一个 MemoryStream
来包装那个字节数组,作为许多选项之一。
如果您确实需要字符串形式的结果,则可以调用 Convert.ToBase64String
,然后调用 Convert.FromBase64String
以取回原始字节。与您当前的方法不同,这不会丢失信息。
我还应该指出,除非您想要特定于 7zip 的压缩,否则还有大量 纯托管 压缩库可用。
C# 使用 SevenZipSharp 压缩和解压缩字符串
基本问题是我没有正确使用字符串,无法将内存流转换为字符串。解决方案使用base64编码使压缩字符串可移植;这使它能够存储在适合我需要的 XML / JSON 文件中。谢谢@Daisy Shipton(参见:)。
来自 VBA 构造函数的使用(在 newing 时传递参数)不是很明显,but this helps。这是关键:
// Create a memory stream from the input: base64 --> bytes --> memStream
Byte[] compBytes = Convert.FromBase64String(input);
MemoryStream compStreamIn = new MemoryStream(compBytes);
希望这对其他人有帮助:
using System;
using System.IO;
using System.Text;
using SevenZip;
namespace _7ZipWrapper
{
public class ProgramToModify
{
public static void Main()
{
var input = "Some string"; // Input String will pass as parameter
var compressed = MyEncode(input);
Console.WriteLine("Compressed String: " + compressed);
var decodedString = myDecode(compressed);
Console.WriteLine("Decompressed String: " + decodedString);
Console.ReadKey();
}
// Returns compressed and encoded base64 string from input
private static String MyEncode(string input)
{
// Setup the SevenZip Dll
SevenZipCompressor.SetLibraryPath(@"C:\Tempza64.dll");
SevenZipCompressor SevenZipC = new SevenZipCompressor();
SevenZipC.CompressionMethod = CompressionMethod.Ppmd;
SevenZipC.CompressionLevel = global::SevenZip.CompressionLevel.Ultra;
SevenZipC.ScanOnlyWritable = true;
var memoryStream = new MemoryStream(); // Create Memory Stream
var streamWriter = new StreamWriter(memoryStream);
streamWriter.Write(input); // streamWriter writes input to memoryStream
streamWriter.Flush();
// Compress: memoryStream -> cmpdMemoryStream
var cmpdMemoryStream = new MemoryStream();
SevenZipC.CompressStream(memoryStream, cmpdMemoryStream, "Optional Password Field");
Byte[] bytes = cmpdMemoryStream.ToArray();
return Convert.ToBase64String(bytes);
}
// Returns plain string from compressed and encoded input
private static String myDecode(string input)
{
// Create a memory stream from the input: base64 --> bytes --> memStream
Byte[] compBytes = Convert.FromBase64String(input);
MemoryStream compStreamIn = new MemoryStream(compBytes);
SevenZipExtractor.SetLibraryPath(@"C:\Tempza64.dll");
var SevenZipE = new SevenZip.SevenZipExtractor(compStreamIn, "Optional Password Field");
var OutputStream = new MemoryStream();
SevenZipE.ExtractFile(0, OutputStream);
var OutputBase64 = Convert.ToBase64String(OutputStream.ToArray());
Byte[] OutputBytes = Convert.FromBase64String(OutputBase64);
string output = Encoding.UTF8.GetString(OutputBytes);
return output;
}
}
}
这是来自此处的后续问题:
以下代码的工作原理是它接受一个字符串并成功地压缩和解压缩它。
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:\Tempza64.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();
}
}
}
但是,上面的代码在目前的形式下显然没有什么好处(这注定要成为一个 COM DLL)。
我以为我是在家和水管,重构将是小菜一碟,但是,我尝试将代码重新排列成有用的东西让我不知所措,为什么下面的代码会抛出 System.ArgumentException ('The stream is invalid or no corresponding signature was found.') 但上面的代码运行没有问题。
从根本上说肯定存在某种差异,但我不知道是什么原因造成的,也不知道如何解决。将不胜感激附有简短解释的解决方案。
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:\Tempza64.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:\Tempza64.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();
}
}
}
注意:虽然我知道这段代码可能存在多个问题,但我正在学习并打算将下一次迭代放在 CodeReview 上。也就是说,请随时提出建议,但现在这对我来说是一个学习练习。 TIA
您的工作代码已解压缩 compressedMemoryStream
。您损坏的代码解压缩了从 compressedMemoryStream
.
正如我在你之前的问题中所说,压缩的结果不是文本。如果您必须将其表示为文本,则应使用 Base64 或十六进制。但是,就好像它是 UTF-8 编码的文本(这就是您现在正在做的)一样读取它根本行不通。
您的 StreamCompress
方法的结果可能应该是 byte[]
。这很容易实现:
// Note: changed input type to just Stream to make it more general
private static byte[] StreamCompress(Stream input, string optionalPassword)
{
SevenZipCompressor.SetLibraryPath(@"C:\Tempza64.dll");
SevenZipCompressor SevenZip = new SevenZipCompressor();
SevenZip.CompressionMethod = CompressionMethod.Ppmd;
SevenZip.CompressionLevel = global::SevenZip.CompressionLevel.Ultra;
SevenZip.ScanOnlyWritable = true;
var output = new MemoryStream();
SevenZip.CompressStream(input, output, optionalPassword);
// You don't even need to rewind when you call ToArray
return output.ToArray();
}
当你想解压缩时,你可以创建一个 MemoryStream
来包装那个字节数组,作为许多选项之一。
如果您确实需要字符串形式的结果,则可以调用 Convert.ToBase64String
,然后调用 Convert.FromBase64String
以取回原始字节。与您当前的方法不同,这不会丢失信息。
我还应该指出,除非您想要特定于 7zip 的压缩,否则还有大量 纯托管 压缩库可用。
C# 使用 SevenZipSharp 压缩和解压缩字符串
基本问题是我没有正确使用字符串,无法将内存流转换为字符串。解决方案使用base64编码使压缩字符串可移植;这使它能够存储在适合我需要的 XML / JSON 文件中。谢谢@Daisy Shipton(参见:
来自 VBA 构造函数的使用(在 newing 时传递参数)不是很明显,but this helps。这是关键:
// Create a memory stream from the input: base64 --> bytes --> memStream
Byte[] compBytes = Convert.FromBase64String(input);
MemoryStream compStreamIn = new MemoryStream(compBytes);
希望这对其他人有帮助:
using System;
using System.IO;
using System.Text;
using SevenZip;
namespace _7ZipWrapper
{
public class ProgramToModify
{
public static void Main()
{
var input = "Some string"; // Input String will pass as parameter
var compressed = MyEncode(input);
Console.WriteLine("Compressed String: " + compressed);
var decodedString = myDecode(compressed);
Console.WriteLine("Decompressed String: " + decodedString);
Console.ReadKey();
}
// Returns compressed and encoded base64 string from input
private static String MyEncode(string input)
{
// Setup the SevenZip Dll
SevenZipCompressor.SetLibraryPath(@"C:\Tempza64.dll");
SevenZipCompressor SevenZipC = new SevenZipCompressor();
SevenZipC.CompressionMethod = CompressionMethod.Ppmd;
SevenZipC.CompressionLevel = global::SevenZip.CompressionLevel.Ultra;
SevenZipC.ScanOnlyWritable = true;
var memoryStream = new MemoryStream(); // Create Memory Stream
var streamWriter = new StreamWriter(memoryStream);
streamWriter.Write(input); // streamWriter writes input to memoryStream
streamWriter.Flush();
// Compress: memoryStream -> cmpdMemoryStream
var cmpdMemoryStream = new MemoryStream();
SevenZipC.CompressStream(memoryStream, cmpdMemoryStream, "Optional Password Field");
Byte[] bytes = cmpdMemoryStream.ToArray();
return Convert.ToBase64String(bytes);
}
// Returns plain string from compressed and encoded input
private static String myDecode(string input)
{
// Create a memory stream from the input: base64 --> bytes --> memStream
Byte[] compBytes = Convert.FromBase64String(input);
MemoryStream compStreamIn = new MemoryStream(compBytes);
SevenZipExtractor.SetLibraryPath(@"C:\Tempza64.dll");
var SevenZipE = new SevenZip.SevenZipExtractor(compStreamIn, "Optional Password Field");
var OutputStream = new MemoryStream();
SevenZipE.ExtractFile(0, OutputStream);
var OutputBase64 = Convert.ToBase64String(OutputStream.ToArray());
Byte[] OutputBytes = Convert.FromBase64String(OutputBase64);
string output = Encoding.UTF8.GetString(OutputBytes);
return output;
}
}
}