3

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
Community
  • 1
  • 1
ElektroStudios
  • 19,105
  • 33
  • 200
  • 417
  • 1
    you try to read buffer length bytes, then write just one out. That's obviously not correct code. – Mitch Wheat Mar 21 '13 at 00:16
  • That's the reason why I asked a question cause I don't know the correct way to do it, but at least I've searched and I've tryed it before ask, if you really think I deserve a downvote and a Closure too... well thankyou anyway for comment. – ElektroStudios Mar 21 '13 at 00:22
  • 1
    You haven't translated the lines of code you linked to, correctly. I suggest looking at that code again. – Mitch Wheat Mar 21 '13 at 00:24
  • I've used 2 online translators and I can't translate it better cause I don't know C# syntax. But I will take a look again on the code. PS: Sorry for my english – ElektroStudios Mar 21 '13 at 00:28
  • 1
    I can't believe the reason of the closure "Not a real question", thanks for being comprehensive all you guys... – ElektroStudios Mar 21 '13 at 15:51
  • 1
    Just a quick comment: Looks like you have to add: `bytesRead =` before `inputStream.Read(buffer, 0, buffer.Length) > 0`. – ispiro Mar 21 '13 at 18:13

1 Answers1

7

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
Daniel A.A. Pelsmaeker
  • 47,471
  • 20
  • 111
  • 157
  • Thankyou so much for your help and your explanation, but I've followed your steps and I still getting a zero file, I've updated my question, thankyou again – ElektroStudios Mar 22 '13 at 09:45
  • Yes it compiles without any error/exception, and creates a zero byte file, I've tryed now by adding the parentheses that you've said in the while but nothing changed, my code is the same above just with that parentheses. – ElektroStudios Mar 22 '13 at 18:31
  • @ElektroHacker You previously had code that closed the output stream, but in your latest code that is no longer present. You should close the output stream, this will write the buffered data to the stream. – Daniel A.A. Pelsmaeker Mar 22 '13 at 21:01
  • I've updated again my question, your patience and your help is appreciated but unfortunately I made the changes that you have shown me and I keep getting a file of 0 bytes (PS: The input file weighs 34 bytes, has 15 lines of text), the same code runs in C#? – ElektroStudios Mar 22 '13 at 21:47
  • @ElektroHacker I used some tool to convert your code to C#. I tested it, and it works properly on my computer. I converted the code back to VB.Net, so have a look at the above code. Compare it to your code and maybe you can find some subtle difference that causes all this. For example, in my code there is `As Byte()` and `As FileStream` at some places where there isn't in your code. I don't know if it makes a difference. – Daniel A.A. Pelsmaeker Mar 22 '13 at 23:31
  • No way, I tested that converted code but I'm still getting a 0 byte file, please can you post the C# working version? – ElektroStudios Mar 23 '13 at 01:37
  • @ElektroHacker I added the C# code and some things you should take a look at. – Daniel A.A. Pelsmaeker Mar 23 '13 at 01:49
  • I can't believe it, all the things appear to be the same in your C# version and in my VB version but only works the C# vrs, only difference I can found is C# vrs is a CLI APP and VB vrs is a WinForm, well i accept your answer cause you gived me the working code that I'll need, now I need to find the translated error from C# to VB.NET. thankyou for all again! – ElektroStudios Mar 23 '13 at 13:20
  • Someone says me the problem is in VB.NET I can't assign a value into a variable in the while condition like in C#, that's it! resolved. – ElektroStudios Mar 23 '13 at 20:56
  • @ElektroHacker If you want, you could update your post with the final working code. Other users with this problem will be grateful. – Daniel A.A. Pelsmaeker Mar 23 '13 at 21:31