Copy a file in little chunks

.net, chunks, file-io, vb.net, visual-studio

Solution

You have to understand what you're doing and how it works.

First, you allocate a buffer.

Dim buffer = New Byte(1024) {}

Then you go and read some data from the input stream. The data is put in `buffer`, starting at `0`, at most `buffer.Length` bytes. The method returns how many bytes it has actually read and put in the buffer.

bytesRead = inputStream.Read(buffer, 0, buffer.Length)

If the number of bytes you've read is bigger than 0, then you haven't reached the end of the file yet.

While (bytesRead > 0)

Then you write exactly those bytes that were read (`bytesRead` bytes) to the output stream. Write the bytes from `buffer`, start at index `0` and write `bytesRead` number of bytes.

outputStream.Write(buffer, 0, bytesRead)

Since the stream will buffer what you wrote for efficiency reasons, you'll have to flush and close the output stream.

outputStream.Flush()
outputStream.Close()

Putting it together:

Dim buffer = New Byte(1024) {}
Dim bytesRead As Integer

' Read some bytes
While ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)
    ' Write them to the output
    outputStream.Write(buffer, 0, bytesRead)

    If cancelled Then
        MsgBox("operacion cancelada")
        Return
    End If

    ' Repeat
End

outputStream.Flush()
outputStream.Close()

The last time I wrote VB is more than a decade ago. You'll have to ensure the syntax is correct.

Notice how the original code contains this line:

While ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)

You see the `bytesRead =` part? You haven't copied that into your code. It is essential to store the number of bytes read.

Final code: this works on my computer:

Imports System
Imports System.IO

Namespace ConsoleApplication1
    Friend Class Program
        Private Shared Sub Main(args As String())
            Program.CopyMyFiles()
            Console.WriteLine("DONE!")
            Console.ReadLine()
        End Sub

        Private Shared Sub CopyMyFiles()
            Dim input_filepath As String = "Test.txt"
            Dim output_filepath As String = "Test_New.txt"
            Dim input As FileStream = New FileStream(input_filepath, FileMode.Open, FileAccess.ReadWrite)
            Dim output As FileStream = New FileStream(output_filepath, FileMode.Create, FileAccess.ReadWrite)
            Program.CopyStream(input, output)
        End Sub

        Public Shared Sub CopyStream(inputStream As Stream, outputStream As Stream)
            Dim buffer As Byte() = New Byte(1025)
            Dim bytesRead As Integer
            bytesRead = inputStream.Read(buffer, 0, buffer.Length)
            While bytesRead > 0
                outputStream.Write(buffer, 0, bytesRead)
                bytesRead = inputStream.Read(buffer, 0, buffer.Length)
            End While
            outputStream.Flush()
            inputStream.Close()
            outputStream.Close()
        End Sub
    End Class
End Namespace

Problem

I want to copy a file in little chunks (to cancel the copy operation if needed). I'm trying to follow the unmarked solution here: How to copy a file with the ability to cancel the copy? But I'm getting a 0 byte file What I'm doing wrong? ``` Public Class Form1 Dim cancelled As Boolean = Nothing Dim input = New System.IO.FileStream("C:\1.txt", System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read) Dim output = New System.IO.FileStream("C:\Nueva carpeta\1.txt", System.IO.FileMode.CreateNew, System.IO.FileAccess.Write, System.IO.FileShare.Write) Public Sub CopyStream(ByVal inputStream As System.IO.Stream, ByVal outputStream As System.IO.Stream) 'Dim buffer = System.IO.File.ReadAllBytes("C:\1.txt") Dim buffer = New Byte((1024) - 1) {} Dim bytesRead As Integer = 1 While (inputStream.Read(buffer, 0, buffer.Length) > 0) outputStream.Write(buffer, 0, bytesRead) 'bytesRead += 1 If cancelled Then MsgBox("operacion cancelada") Return End If End While inputStream.Close() outputStream.Close() MsgBox("operacion terminada") End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click CopyStream(input, output) End Sub End Class ``` ** UPDATE 1: ** I've tryed to follow the steps of Virtlink answer and putting the missing parts in my original code, but I still getting a zero byte file. ``` > Public Class Form1 Dim input = New System.IO.FileStream("C:\Test.txt", System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read) Dim output = New System.IO.FileStream("C:\Test_New.txt", System.IO.FileMode.CreateNew, System.IO.FileAccess.Write, System.IO.FileShare.Write) Public Sub CopyStream(ByVal inputStream As System.IO.Stream, ByVal outputStream As System.IO.Stream) Dim buffer = New Byte(1024) {} Dim bytesRead As Integer ' Read some bytes While (bytesRead = inputStream.Read(buffer, 0, buffer.Length) > 0) ' Write them to the output outputStream.Write(buffer, 0, bytesRead) End While End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click CopyStream(input, output) End Sub End Class ``` ** UPDATE 2: ** MY LATEST FAILED TRY: ``` Public Class Form1 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim input_filepath As String = "C:\Test.txt", output_filepath As String = "C:\Test_New.txt" Dim input = New System.IO.FileStream(input_filepath, System.IO.FileMode.Open, System.IO.FileAccess.ReadWrite) Dim output = New System.IO.FileStream(output_filepath, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite) CopyStream(input, output) ' For Testing: If New IO.FileInfo(output_filepath).Length = 0 Then IO.File.Delete(output_filepath) : Application.Exit() Else Process.Start("Notepad", output_filepath) End Sub Public Sub CopyStream(ByVal inputStream As System.IO.Stream, ByVal outputStream As System.IO.Stream) Dim buffer = New Byte(1024) {}, bytesRead As Integer While ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0) outputStream.Write(buffer, 0, bytesRead) End While inputStream.Flush() : outputStream.Flush() inputStream.Close() : outputStream.Close() End Sub End Class ``` ** UPDATE 3: ** SOLUTION The problem was in VB.NET I can't assign a value into a variable in the loop condition, so this is the working Sub: ``` Public Sub CopyStream(ByVal inputStream As Stream, ByVal outputStream As Stream) Dim buffer = New Byte(1025) {} Dim bytesRead As Integer = 0 Do bytesRead = inputStream.Read(buffer, 0, buffer.Length) If bytesRead > 0 Then outputStream.Write(buffer, 0, bytesRead) End If Loop While (bytesRead > 0) outputStream.Flush() inputStream.Close() : outputStream.Close() End Sub ```

Original source

Related problems