2

I'm attempting to compress a file to stream which is sent over wcf and decompressed. However with the following code the I'm get not a valid exe when attempting to execute the decompressed exe. Any decompressed exe is around 211-212 bytes lower that the original.

Sub Main()

    Dim strm As Stream = CompressToStream("c:\rje\Launcher.exe")

    DecompressToFile(strm)

End Sub

Compression Routine

Private Function CompressToStream(ByVal strFullFilename As String) As Stream

    If File.Exists(strFullFilename) Then

        Dim uncompressedfile As New MemoryStream(File.ReadAllBytes(strFullFilename))

        Dim compressedStream As New MemoryStream
        Dim compressionStream As New GZipStream(compressedStream, CompressionMode.Compress)

        uncompressedfile.CopyToStream(compressionStream)
        compressionStream.Flush()
        compressedStream.Position = 0
        Return compressedStream

    End If

    Return Nothing
End Function

Extension method to copy streams as using .net3.5

<System.Runtime.CompilerServices.Extension()> _
Private Sub CopyToStream(ByVal input As Stream, ByRef output As Stream)

    Dim Buffer(4096) As Byte
    Dim numRead As Integer = input.Read(Buffer, 0, Buffer.Length)
    Do While numRead <> 0
        output.Write(Buffer, 0, numRead)
        numRead = input.Read(Buffer, 0, Buffer.Length)
    Loop
End Sub

Finally Decompression

Private Sub DecompressToFile(ByVal strmDownload As Stream)

    Dim spath As String = "c:\rje\text.exe"

    Using outFile As FileStream = File.Create(spath)
        Using Decompress As GZipStream = New GZipStream(strmDownload, CompressionMode.Decompress)
            ' Copy the compressed file into the decompression stream. 

            Dim buffer(4096) As Byte
            Dim numRead As Integer = Decompress.Read(buffer, 0, buffer.Length)
            Do While numRead <> 0
                outFile.Write(buffer, 0, numRead)
                numRead = Decompress.Read(buffer, 0, buffer.Length)
            Loop
        End Using
        outFile.Close()
    End Using
End Sub

If someone could point out where I'm going wrong that would be great.

robpws
  • 79
  • 8
  • 1
    Never use File.Exists() like that (2nd code snippet). Just try to open the file, and handle the exception if it fails. – Joel Coehoorn Mar 19 '14 at 14:10
  • What version of .Net? – Joel Coehoorn Mar 19 '14 at 14:12
  • @JoelCoehoorn 3.5 vs2008, why shouldn't I use File.Exists()? – robpws Mar 19 '14 at 14:16
  • Okay, you can't use the new ZipArchive in .Net 4.5 then :( – Joel Coehoorn Mar 19 '14 at 14:20
  • Have you seen this sample code? http://msdn.microsoft.com/en-us/library/ms404280(v=vs.90).aspx?cs-lang=vb I ask just 'cause I want to know what to use as a starting point. – Joel Coehoorn Mar 19 '14 at 14:22
  • @JoelCoehoorn I have, but I am trying to avoid creating the zipped version of the file, then re-opening that so that I can return the stream – robpws Mar 19 '14 at 14:24
  • That sample code does extra work to convert filenames or fileInfo structs to streams. You should be able to get it to do what you need simply _removing_ the code this conversion code: what you want to do is actually _less_ complicated, and all of the code you need is contained in the sample. Just about all you have to do is cut a few lines and change function signatures – Joel Coehoorn Mar 19 '14 at 14:30

2 Answers2

2

The error was with CompressToStream, amending as follows functions correctly

Private Function CompressToStream(ByVal strFullFilename As String) As Stream

    If File.Exists(strFullFilename) Then
        Dim compressedStream As New MemoryStream()
        Using uncompressedfile As New MemoryStream(File.ReadAllBytes(strFullFilename))
            Using compressionStream As New GZipStream(compressedStream, CompressionMode.Compress, True)
                uncompressedfile.CopyToStream(compressionStream)
            End Using
        End Using
        compressedStream.Seek(0, SeekOrigin.Begin)
        Return compressedStream 
    End If

    Return Nothing
End Function

I still don't have an answer as to why I shouldn't use File.Exists()?

robpws
  • 79
  • 8
  • 2
    File.Exists() only checks existence. It does not check permissions, whether a file is locked by another process, or whether the state of a file changed in the brief space between when you check and when you use the file. (The file system is volatile. Using File.Exists() in this way creates a race condition, even if it's a small one). The result of all this is that you have to handle the exception anyway, making the .Exists() check redundant in terms of code maintenance, and wasteful, in terms of making an extra trip out to the hard disk (about the slowest possible thing a computer can do). – Joel Coehoorn Mar 19 '14 at 14:47
0

Here are adapted Compress()/Decompress() methods from the sample in the link I posted in my comment:

Private Function Compress(ByVal strFullFilename As FileInfo) As Stream
    ' Get the stream of the source file. 
    Dim fi as New FileInfo(strFullFilename)
    Dim result As New MemoryStream() 
    Using inFile As FileStream = fi.OpenRead()
        ' Compressing: 
        ' Prevent compressing hidden and already compressed files. 

        If (File.GetAttributes(fi.FullName) And FileAttributes.Hidden) _
            <> FileAttributes.Hidden And fi.Extension <> ".gz" Then 
            ' Create the compressed file.
            Using Compress As GZipStream = New GZipStream(result, CompressionMode.Compress)
                ' Copy the source file into the compression stream. 
                Dim buffer As Byte() = New Byte(4096) {}
                Dim numRead As Integer = inFile.Read(buffer, 0, buffer.Length)
                Do While numRead <> 0
                    Compress.Write(buffer, 0, numRead)
                    numRead = inFile.Read(buffer, 0, buffer.Length)
                Loop

                'Console.WriteLine("Compressed {0} from {1} to {2} bytes.", fi.Name, fi.Length.ToString(), result.Length.ToString())

            End Using 
        End If 
    End Using 
    Return result
End Sub 

' Method to decompress. 
Private Sub Decompress(ByVal strmDownload As Stream, ByVal resultFileName As String)        

        ' Create the decompressed file. 
        Using outFile As FileStream = File.Create(resultFileName)
            Using Decomp As GZipStream = New GZipStream(strmDownload, CompressionMode.Decompress)
                ' Copy the compressed file into the decompression stream. 
                Dim buffer As Byte() = New Byte(4096) {}
                Dim numRead As Integer = Decompress.Read(buffer, 0, buffer.Length)

                Do While numRead <> 0
                    outFile.Write(buffer, 0, numRead)
                    numRead = Decomp.Read(buffer, 0, buffer.Length)
                Loop
                'Console.WriteLine("Decompressed: {0}", fi.Name)

            End Using 
        End Using 
    End Using 
End Sub 
Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • I'm pretty sure that will return a closed stream as the 'end using' of Compress will close the stream rendering it unuseable – robpws Mar 19 '14 at 14:50