Arquivo comprimido por GZIP cresce em vez de diminuir
Pergunta
Eu usei o código abaixo para arquivos comprimir e eles continuam a crescer em vez de diminuir. I comressed um arquivo de 4 kb e tornou-se 6. Isso é compreensível para um arquivo pequeno devido à sobrecarga de compressão. Eu tentei um arquivo de 400 MB e tornou-se 628 MB após a compressão. O que está errado? Veja o código. (.NET 2.0)
Public Sub Compress(ByVal infile As String, ByVal outfile As String)
Dim sourceFile As FileStream = File.OpenRead(inFile)
Dim destFile As FileStream = File.Create(outfile)
Dim compStream As New GZipStream(destFile, CompressionMode.Compress)
Dim myByte As Integer = sourceFile.ReadByte()
While myByte <> -1
compStream.WriteByte(CType(myByte, Byte))
myByte = sourceFile.ReadByte()
End While
sourceFile.Close()
destFile.Close()
End Sub
Solução
Você tem certeza que escrever byte por byte para o fluxo é realmente uma boa idéia? Ele certamente não tem características de desempenho ideais e talvez isso é o que confunde o algoritmo gzip comprimir também.
Além disso, pode acontecer que os dados que você está tentando compressa só não é muito bem-compressível. Se eu fosse você eu iria tentar o seu código com um documento de texto do mesmo tamanho como documentos de texto tendem a comprimir muito melhor do que binária aleatória.
Além disso, você pode tentar usar um DeflateStream pura em oposição a um GZipStream como eles usam o mesmo algoritmo de compressão (deflate), a única diferença é que gzip acrescenta alguns dados adicionais (como a verificação de erros), de modo a DeflateStream pode produzir menor resultados.
Meu VB.NET é um pouco enferrujado, então eu prefiro não vou tentar escrever um exemplo de código em VB.NET. Em vez disso, aqui está como você deve fazê-lo em C #, ele deve ser relativamente simples para traduzi-lo para VB.NET para alguém com um pouco de experiência: (ou talvez alguém que é bom em VB.NET poderia editar o meu post e traduzi-lo para VB.NET)
FileStream sourceFile;
GZipStream compStream;
byte[] buffer = new byte[65536];
int bytesRead = 0;
while (bytesRead = sourceFile.Read(buffer, 0, 65536) > 0)
{
compStream.Write(buffer, 0, bytesRead);
}
Outras dicas
Se o arquivo subjacente é em si altamente imprevisível (já comprimido ou em grande parte aleatório), em seguida, tentar comprimi-lo fará com que o arquivo para se tornar maior.
indo de 400 a 628Mb sons altamente improvável como um factor de expansão uma vez que o algoritmo deflate (utilizado para GZip) tende para um factor de expansão máxima de 0,03% a sobrecarga do cabeçalho GZip deve ser insignificante.
Edit: O 4.0 c # liberação indica que as bibliotecas de compressão foram melhorados para não causar a expansão significativa de dados uncompressable. Isto sugere que eles não estavam a implementar o "retorno à blocos de fluxo de matérias-" mode. Tente usar a biblioteca de SharpZipLib como um teste rápido. Isso deve lhe fornecer perto de desempenho idêntico quando o fluxo é incompressível por deflate. Se ele não considerar a mudança para isso ou aguardando a liberação 4.0 para uma implementação BCL de maior performance. Note-se que a falta de compressão que você está recebendo sugere fortemente que não há nenhum ponto você tentar comprimir ainda de qualquer maneira
Esta é uma conhecida anomalia com o built em GZipStream (E DeflateStream).
Eu posso pensar de duas soluções:
- usar um compressor alternativo.
- construir alguma lógica que examina o tamanho da saída "comprimido" e compara com o tamanho da entrada. Se for maior, Chuck a saída e apenas armazenar os dados.
DotNetZip inclui um GZipStream "fixa" com base em um porto gerenciado de zlib. (É preciso abordagem # 1 de cima). O Ionic.Zlib.GZipStream pode substituir o built-in GZipStream em seus aplicativos com uma simples troca de namespace.
Obrigado a todos por boas respostas. Mais cedo nesta Tentei compactar arquivos e um arquivo de texto .wmv. Mudei o código para DeflateStream e parece funcionar agora. Felicidades.