Can DeflateStream or GZipStream be used to deflate an uncompressed file?

I am trying to implement file compression in an application. The application exists for some time, so it should be able to read uncompressed documents written by previous versions. I expected DeflateStream to be able to process an uncompressed file, but for GZipStream I get the error "The magic number in the GZip header is incorrect." For DeflateStream, I get "Found invalid data during decoding." I think he does not find the header that marks the file as the type that it is.

If it is not possible to simply process an uncompressed file, then it would be best to be able to determine if the file is compressed and choose how to read the file. I found this link: http://blog.somecreativity.com/2008/04/08/how-to-check-if-a-file-is-compressed-in-c/ , but it is very implementation specific and not seems like the right approach. It can also provide false positives (I'm sure this would be rare, but this indicates that this is not the right approach).

The third option I examined is to try to use DeflateStream and return to the standard IO stream if an exception occurs. It also seems messy and causes VS to throw an exception (unless I rejected that exception, which I really don't want to make).

Of course, I can just make a mistake. This is the code I tried in .Net 3.5:

Stream reader = new FileStream(fileName, FileMode.Open, readOnly ? FileAccess.Read : FileAccess.ReadWrite, readOnly ? FileShare.ReadWrite : FileShare.Read);

using (DeflateStream decompressedStream = new DeflateStream(reader, CompressionMode.Decompress))
{
    workspace = (Workspace)new XmlSerializer(typeof(Workspace)).Deserialize(decompressedStream);

    if (readOnly)
    {
        reader.Close();
        workspace.FilePath = fileName;
    }
    else
        workspace.SetOpen(reader, fileName);
}

Any ideas?

Thank! Luke.

+3
source share
2 answers

Does your file format have a header? If not, now is the time to add it (in any case, you change the file format while supporting compression). Choose a good magic value , make sure the title is extensible (add a version field or use certain magic values โ€‹โ€‹for certain versions), and you are ready to go.

After loading, check the magic value. If not, use the current boot routines. If present, the header will tell you whether the content is compressed or not.

Update

, XML-, , , , , . , :)

() -; , .net "", SubRangeStream, , (DeflateStream, , , , , ).

Int64 oldPosition = reader.Position;
reader.Read(magic, 0, magic.length);
if(IsRightMagicValue(magic))
{
    Header header = ReadHeader(reader);
    Stream furtherReader = new SubRangeStream(reader, reader.Position, header.ContentLength); 
    if(header.IsCompressed)
    {
        furtherReader = new DeflateStream(furtherReader, CompressionMode.Decompress);
    }

    XmlSerializer xml = new XmlSerializer(typeof(Workspace));
    workspace = (Workspace) xml.Deserialize(furtherReader); 
} else
{
    reader.Position = oldPosition;
    LegacyLoad(reader);
}

- - , . , IsRightMagicValue, ( ), " " , . Factory Method, IWorkspaceReader .

+1

/- ? -

try
{
    // Try return decompressed stream 
}
catch(InvalidDataException e)
{
    // Assume it is already decompressed and return it as it is
}
+1

Source: https://habr.com/ru/post/1763966/


All Articles