Steven Liekens
Steven Liekens

Reputation: 14113

Confused about stream buffers

I'm trying to familiarize myself with network programming, and what better place to start than designing an FTP client code library?

So far I'm not doing very good. I'm trying to create a method which downloads a file from a remote server to a local file path. To do so, all the examples that I could find declare a byte array that serves as a data buffer. I completely understand the point of doing that, rather than reading and writing byte per byte, but I just can't get it to work. Whenever I set a buffer greater than 1 byte, the output is somehow corrupted (different checksums, media files won't play etc).

Can someone please point out what I'm doing wrong here:

Public Function DownloadFile(source As Uri, output As Uri) As FtpStatusCode
    Dim request = FtpWebRequest.Create(source)
    request.Method = WebRequestMethods.Ftp.DownloadFile

    Using response As FtpWebResponse = CType(request.GetResponse, FtpWebResponse)
        Using outputStream = New FileStream(output.AbsolutePath, FileMode.Create)
            Do
                Dim buffer(8192) As Byte
                response.GetResponseStream.Read(buffer, 0, buffer.Length)
                outputStream.Write(buffer, 0, buffer.Length)
            Loop While outputStream.Position < response.ContentLength
        End Using
        Return response.StatusCode
    End Using
End Function

Because this code does work when I set the buffer size to 1, I feel like there's something going wrong with the byte order. But all of this code is synchronous, so how is that even possible...

EDIT

I got it to work now, so here's the code solution for future reference (thanks again @tcarvin):

Public Function DownloadFile(source As Uri, output As Uri) As FtpStatusCode
    Dim request = FtpWebRequest.Create(source)
    request.Method = WebRequestMethods.Ftp.DownloadFile

    Using response As FtpWebResponse = CType(request.GetResponse, FtpWebResponse)
        Using inputStream = response.GetResponseStream
            Using outputStream = New FileStream(output.AbsolutePath, FileMode.Create)
                Do
                    Dim buffer(8192) As Byte
                    Dim buffered = inputStream.Read(buffer, 0, buffer.Length).Read(buffer, 0, buffer.Length)
                    outputStream.Write(buffer, 0, buffered)
                Loop While outputStream.Position < response.ContentLength
            End Using
        End Using
        Return response.StatusCode
    End Using
End Function

Upvotes: 0

Views: 1588

Answers (1)

tcarvin
tcarvin

Reputation: 10855

When reading from a stream, you need to capture the return value of the method. Read returns how many bytes were just read. That is the number of bytes you need to then write to your output stream.

Upvotes: 1

Related Questions