本文介绍了为什么?重构后的 C# 错误:“流无效或未找到相应的签名."的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是来自此处的后续问题:使用 SevenZipSharp 将流解压缩为字符串.

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:Temp7za64.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).

However, the above code obviously does little good in its current form (this is destined to become a COM DLL).

我以为我是家常便饭,重构很容易,但是,我尝试将代码重新排列成有用的东西,这让我不知为何下面的代码会抛出 System.ArgumentException ('流无效或未找到相应的签名.')但上面的代码运行没有问题.

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:Temp7za64.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:Temp7za64.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

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

推荐答案

您的工作代码已解压缩 compressedMemoryStream.您损坏的代码解压了从 compressedMemoryStream 创建的 string.

Your working code decompressed compressedMemoryStream. Your broken code decompressed a string created from compressedMemoryStream.

正如我在您之前的问题中所说,压缩的结果不是文本.如果您必须将其表示为文本,则应使用 Base64 或十六进制.但只是从它读取它就好像它是 UTF-8 编码的文本(这就是你现在正在做的)根本行不通.

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.

你的 StreamCompress 方法的结果应该是一个 byte[].这很容易实现:

The result of your StreamCompress method should probably be a byte[]. That's easy to achieve:

// Note: changed input type to just Stream to make it more general
private static byte[] StreamCompress(Stream input, string optionalPassword)
{
    SevenZipCompressor.SetLibraryPath(@"C:Temp7za64.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 来包装该字节数组,作为众多选项之一.

When you want to decompress, you can just create a MemoryStream to wrap that byte array, as one of many options.

如果您确实需要将结果作为字符串,则可以调用 Convert.ToBase64String,然后调用 Convert.FromBase64String 以取回原始字节.与您目前的方法不同,这不会丢失信息.

If you really need the result as a string, you can then call Convert.ToBase64String, then later call Convert.FromBase64String to get back the original bytes. This will not lose information, unlike your current approach.

我还应该指出,除非您想要特定于 7zip 的压缩,否则还有很多纯托管压缩库可用.

I should also point out that unless you want 7zip-specific compression, there are plenty of purely-managed compression libraries available too.

这篇关于为什么?重构后的 C# 错误:“流无效或未找到相应的签名."的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 13:54