Copying locked files

M

Martin Ho

I am running into one really big problem.

I wrote a script in vb.net to make a copy of folders and subfolder to
another destination:

- in 'from.txt' I specify which folders to copy
- in 'to.txt' I specify where to copy it
- After I read content of 'to.txt' I create one more subfolder named
by current date and thats where everything gets to be copied


When I execute the program, it starts to copy my folders and
everything runs just fine.

Here is when the problem occurs:
I am trying to backup this way a folder, where some files are being
used by our network users.

Once my program gets to the point that it wants to copy file which is
being currently used, it crashes.

I can't figure out how to amend my program to make a copy even that
the file is locked or being used by someone.

Can you help me?

If you want to download the whole solution and look at it, I left it
on the the webserver for download, it's zipped (23kb):

http://www.doprocess.com/_users/joe/xcopy.zip

I am running out of ideas.

Here is the code, if you don't want to download it for any reasons:

Public Class Form1
Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

Public Sub New()
MyBase.New()

'This call is required by the Windows Form Designer.
InitializeComponent()

'Add any initialization after the InitializeComponent() call

End Sub

'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As
Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub

'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer

'NOTE: The following procedure is required by the Windows Form
Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(504, 266)
Me.Name = "Form1"
Me.Text = "Form1"

End Sub

#End Region

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim dest, findest As String

Dim SR1 As New System.IO.StreamReader("to.txt")
Dim strCurrentLine1 As String
strCurrentLine1 = SR1.ReadLine

dest = strCurrentLine1.ToString + Date.Now.Day.ToString + "."
+ Date.Now.Month.ToString + "." + Date.Now.Year.ToString + "-" +
Date.Now.Hour.ToString + "." + Date.Now.Minute.ToString + "." +
Date.Now.Second.ToString
System.IO.Directory.CreateDirectory(dest)



Dim SR As New System.IO.StreamReader("from.txt")
Dim strCurrentLine As String

Do While SR.Peek <> -1
strCurrentLine = SR.ReadLine

findest = dest + "\" +
strCurrentLine.ToString.Replace("\", "-").Replace(":", "")
System.IO.Directory.CreateDirectory(findest)

RecursiveCopyFiles((strCurrentLine.ToString), findest,
True)

Loop


SR1.Close()
SR.Close()
Close()
End Sub






Private Sub RecursiveCopyFiles(ByVal sourceDir As String, ByVal
destDir As String, ByVal fRecursive As Boolean)
Dim i As Integer
Dim posSep As Integer
Dim sDir As String
Dim aDirs() As String
Dim sFile As String
Dim aFiles() As String

' Add trailing separators to the supplied paths if they don't
exist.
If Not
sourceDir.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString())
Then
sourceDir &= System.IO.Path.DirectorySeparatorChar
End If

If Not
destDir.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString())
Then
destDir &= System.IO.Path.DirectorySeparatorChar
End If

' Recursive switch to continue drilling down into dir
structure.
If fRecursive Then

' Get a list of directories from the current parent.
aDirs = System.IO.Directory.GetDirectories(sourceDir)

For i = 0 To aDirs.GetUpperBound(0)

' Get the position of the last separator in the
current path.
posSep = aDirs(i).LastIndexOf("\")

' Get the path of the source directory.
sDir = aDirs(i).Substring((posSep + 1),
aDirs(i).Length - (posSep + 1))

' Create the new directory in the destination
directory.
System.IO.Directory.CreateDirectory(destDir + sDir)

' Since we are in recursive mode, copy the children
also
RecursiveCopyFiles(aDirs(i), (destDir + sDir),
fRecursive)
Next

End If

' Get the files from the current parent.
aFiles = System.IO.Directory.GetFiles(sourceDir)

' Copy all files.
For i = 0 To aFiles.GetUpperBound(0)

' Get the position of the trailing separator.
posSep = aFiles(i).LastIndexOf("\")

' Get the full path of the source file.
sFile = aFiles(i).Substring((posSep + 1), aFiles(i).Length
- (posSep + 1))

' Copy the file.
System.IO.File.Copy(aFiles(i), destDir + sFile)

Next i

End Sub

End Class

*-----------------------*
Posted at:
www.GroupSrv.com
*-----------------------*
 
G

Greg Burns

Here is my code that recursively moves a folder (and its subfolders). I not
sure how mine treats locked files, but I would assume the try/catch blocks
would allow it to continue.

HTH,
Greg


Option Strict On

Imports System.IO
Imports System.Configuration

Module Module1

Sub Main()

Dim Source As String = ConfigurationSettings.AppSettings("source")
Dim Dest As String =
ConfigurationSettings.AppSettings("destination") & "\" & Year(Today) &
Right("0" & Month(Today), 2) & Right("0" & Day(Today), 2)

Directory.CreateDirectory(Dest)

'get the log file name
Dim logFileName As String = Dest & "\trace.log"

'open the log file

Dim fileLog As StreamWriter = File.CreateText(logFileName)

'define the log file trace listener
Dim logListener As TextWriterTraceListener = New
TextWriterTraceListener(fileLog)

'add the new trace listener to the collection of listeners
Trace.Listeners.Add(logListener)

Dim consoleListener As MyTrace = New MyTrace
Trace.Listeners.Add(consoleListener)

'make sure that we actually write the data out
Trace.AutoFlush = True

RecursiveCopyFiles(Source, Dest, True)

Trace.WriteLine("Finished.")

' Flush and close the output stream.
fileLog.Flush()
fileLog.Close()

System.Environment.ExitCode = 0

End Sub



' Recursively copy all files and subdirectories from the
' specified source to the specified destination.
Private Function RecursiveCopyFiles( _
ByVal sourceDir As String, _
ByVal destDir As String, _
ByVal bTop As Boolean) As Boolean

Dim aDirs() As String
Dim aFiles() As String

Dim ok As Boolean = True

Trace.WriteLine("Inspecting folder " & sourceDir)

Try
' Get a list of directories from the current parent.
aDirs = System.IO.Directory.GetDirectories(sourceDir)

For Each folderpath As String In aDirs
Dim sDir As String

' Get the path of the source directory.
sDir = System.IO.Path.GetFileName(folderpath)

' Create the new directory in the destination directory.
System.IO.Directory.CreateDirectory(System.IO.Path.Combine(destDir,
sDir))

' Since we are in recursive mode, copy the children also
ok = RecursiveCopyFiles(folderpath,
System.IO.Path.Combine(destDir, sDir), False)

If ok Then
Try
Trace.WriteLine("Deleting " & destDir & sDir)
System.IO.Directory.Delete(destDir & sDir)
Catch ex As Exception
Trace.WriteLine("Error deleting " & destDir & sDir)
Trace.WriteLine(ex.Message)
ok = False
End Try
End If
Next
Catch ex As Exception
Trace.WriteLine("Error reading directory " & sourceDir)
End Try

' Get the files from the current parent.
aFiles = System.IO.Directory.GetFiles(sourceDir)

' Copy all files.
For Each filepath As String In aFiles
Dim sFile As String

' Get the full path of the source file.
sFile = System.IO.Path.GetFileName(filepath)

Try
' Copy the file.
Trace.WriteLine("Copying " & filepath)
System.IO.File.Copy(filepath,
System.IO.Path.Combine(destDir, sFile))

Try
' Delete the file.
Trace.WriteLine("Deleting " & filepath)
System.IO.File.Delete(filepath)
Catch ex As Exception
Trace.WriteLine("Error deleting " & filepath)
Trace.WriteLine(ex.Message)
ok = False
End Try

Catch ex As Exception
Trace.WriteLine("Error copying " & filepath)
Trace.WriteLine(ex.Message)
ok = False
End Try

Next

If Not bTop Then
Try
Trace.WriteLine("Deleting folder " & sourceDir)
System.IO.Directory.Delete(sourceDir)
Catch ex As Exception
Trace.WriteLine("Error deleting folder " & sourceDir)
Trace.WriteLine(ex.Message)
ok = False
End Try
End If

End Function

End Module

Public NotInheritable Class MyTrace
Inherits TraceListener

' disallow instantiation
Public Sub New()
MyBase.New()
End Sub

<Conditional("TRACE")> _
Public Overloads Overrides Sub Write(ByVal message As String)
Console.Write(message)
End Sub

<Conditional("TRACE")> _
Public Overloads Overrides Sub WriteLine(ByVal message As String)
Console.WriteLine(message)
End Sub
End Class
 
C

Chris, Master of All Things Insignificant

Do you really want to be reading a file that is in use, you will have no
idea what state the file is in. What I've done in these cases is to wrap in
a try... catch and log the fact the file could not be backed up. I don't
think there is a way for the Copy method to do this. You would have to open
up the file with a FileStream object and copy it byte by byte...

Hope it helps.
Chris
 
C

Cor Ligthert

Martin,

I looked at your program, however I thought that the question itself is
clear for me. In my opinion can you for that you at the moment only use a
try and catch block

something as in pseudo
\\\
If file.exist(path)
dim notfree as boolean
do while notfree = false
Try
readfile
notfree = true
catch
threading.thread.sleep(10000)
free = false
end catch
loop
end if
///

A little bit changed as I thought provided by Herfried, K. Wagner to this
newsgroup
(You have to create an escape of course when somebody never stops using it)

I hope this helps?

Cor
 
M

Martin Ho

Thanks for all your answers.
So apparently, if file is in use it cannot be copied.
I wonder how V2i backup or Norton's new Ghost 9 do the backup off
everything on the drive, even that files are locked.
Byte by byte could be a solution. But, wow, that is one complicated
way.
Is there really nothing I can do?
I don't want to skip any files when copying. Or wait till file is
ready to be open. Some network users never close the application, so
how can I make a copy then?
There must be some way.
m.

*-----------------------*
Posted at:
www.GroupSrv.com
*-----------------------*
 
C

Chris, Master of All Things Insignificant

Byte By Byte isn't that complicated, you just open up a file, and write it
back out. Same idea that the Copy command is doing, you just need to do it
in a "share" mode.

Chris
 
G

Greg Burns

I've haven't looked at Ghost 9 (I own Ghost 2003). Does it now to a copy
while Windows is running? Ghost 2003 makes you reboot to DOS.

Just curious?

Greg
 
H

Herfried K. Wagner [MVP]

Martin Ho said:
So apparently, if file is in use it cannot be copied.
I wonder how V2i backup or Norton's new Ghost 9 do the backup off
everything on the drive, even that files are locked.

Wow! The last time I worked with Norton's Ghost was when it was available
in version 5!

If a file is locked, there is AFAIK no chance to read it except with a
custom I/O driver.
 
M

Martin Ho

Yes new Norton Ghost and V2i as well, can do this while windows
running.
Tested it myself.
But they do the image of the whole drive. There is no way of backing
up just certain folders.
That is why I need to do this program.
Tell me, there is a way of doing this.
Thanks.
M.

*-----------------------*
Posted at:
www.GroupSrv.com
*-----------------------*
 
G

Greg Burns

Sounds to me like you need a professional backup program.

http://www.veritas.com/Products/www?c=product&refId=57

Q: Are open files protected by Backup Exec for Windows Servers ?

A: Yes. The Backup Exec Advanced Open File Option ensures that files
on local or remote servers are protected even while in use. This option
handles open files at the volume level and is seamlessly integrated into
Backup Exec. This advanced technology helps enable 100% application
availability and 100% complete backups.

Greg
 
M

Martin Ho

Greg,
I do not need another software, I want to write this in VB.NET.
Or I'd like to know from someone with great knowledge of VB.NET that
it's impossible task. Then eventually I will go and try to write this
in different language or as you mentioned, buy a software.
This shouldn't be too hard.
Come on guys.
M.

*-----------------------*
Posted at:
www.GroupSrv.com
*-----------------------*
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top