Unable to delete all files from temporary folders in vb.net - vb.net

I am using the following code to delete all files from a particular folder:
Sub DeleteFiles(Folder As String)
If Directory.Exists(Folder) Then
For Each _file As String In Directory.GetFiles(Folder)
File.Delete(_file)
Next
For Each _folder As String In Directory.GetDirectories(Folder)
DeleteFiles(_folder)
Next
End If
End Sub
Whenever I use the above code to delete all files from "C:\Temp" by calling it using DeleteFiles("C:\Temp"), It deletes all the files successfully, but whenever I try to use the same code for deleting files in "C:\Windows\TEMP\", it breaks the operation saying that the file is in use. I want that the code should not raise an exception and stop deleting the files right-away. If the file cannot be deleted, the code should move on to the next file and try deleting it. This way, it should be able to delete maximum possible files from that directory.

You need to handle exceptions raised by File.Delete() using a Try....Catch... statement. I'm not a VB coder (I'm surprised to find myself answering this question), but something like this should work:
Sub DeleteFiles(Folder As String)
If Directory.Exists(Folder) Then
For Each _file As String In Directory.GetFiles(Folder)
Try
File.Delete(_file)
Catch e As System.IO.IOException
Console.WriteLine(e.Message)
End Try
Next
For Each _folder As String In Directory.GetDirectories(Folder)
DeleteFiles(_folder)
Next
End If
End Sub
This will catch an System.IO.IOException exception, log that it was received, and then ignore it. Note that this will catch a number of other File.Delete() related exceptions such as System.IO.DirectoryNotFoundException, System.IO.PathTooLongException, etc. If you want to catch these, you must add a Catch clause for each before the more general System.IO.IOException. The possible exceptions are listed here, along with an example of using File.Delete() - you just need to read the docs.
You might like to also look at Directory.Delete to recursively delete a directory, its files, and its subdirectories.

You can't stop an exception being thrown. What you need to do is catch the exception, process it as appropriate (which may mean just ignoring it) and move on. That means putting a Try...Catch block inside your first loop. That way, when File.Delete throws an exception, you can catch it, ignore it and the loop will continue.
Be sure to catch only the type of exception that you expect to be thrown though. Otherwise, something completely unexpected may be causing an issue and you're just ignoring it, which is bad. Only ignore exceptions that you reasonably expect and know can be safely ignored.

Dim temp As String = Environment.GetEnvironmentVariable("TEMP")
Dim k As String() = System.IO.Directory.GetFiles(temp)
Dim i As Integer
For i = 0 To k.Length
On Error Resume Next
Kill(k(i))
System.IO.File.Delete(k(i))
Next

Related

How to iterate through files and skip the ones to which I don't have access

I want to get all files in a directory, so I have used For Each loop.
but I got this error and stopped the loop.
System.UnauthorizedAccessException: 'Access to the path
'G:\$RECYCLE.BIN\S-1-5-18' is denied.'
The loop cannot access some of the files because of file permissions. I want to by-pass those files and move to the next file.
how can I do this,
Try
For Each filename As String In Directory.GetFiles(dir_path, pattern, sub_directory)
Console.WriteLine(filename.ToString)
Next filename
Catch ex As Exception
End Try
The loop is irrelevant. It's the call to GetFiles that is the problem. There is no way to call GetFiles with the recursive option and simply ignore inaccessible folders. You can only use that method when you know you can access every subfolder. Otherwise, you need to write your own recursive file search and explicitly catch those exceptions and ignore them. There are lots of examples of that on the web.
It should be noted that GetFiles does the entire search first, creates an array containing all the file paths and returns it, so your loop can't even begin until that's done. Even if this could work, it would still generally be preferable to call EnumerateFiles if you want to loop through the file paths on the spot. That's because EnumerateFiles is an iterator, basically returning the file paths one by one. That means that, for instance, you can break out of the loop if a particular condition is met without completing the entire search. EnumerateFiles will still throw an exception if it finds an inaccessible folder though, so it won't help here. If you do write your own method though, it would be nice to write an iterator if you plan to search big folders or you might not need to use all results.
EDIT:
Here's my home-spun versions. The first one does all the work first while the second is an iterator. Note that you may be able to make the first one more efficient by using a single external list to store all the file paths in rather than creating a new one in every recursive call.
Public Function GetFilesRecursively(path As String, searchPattern As String) As String()
Dim filePaths As New List(Of String)(Directory.GetFiles(path, searchPattern))
For Each folderPath In Directory.GetDirectories(path)
Try
filePaths.AddRange(GetFilesRecursively(folderPath, searchPattern))
Catch ex As UnauthorizedAccessException
'Ignore inaccessible folders
End Try
Next
Return filePaths.ToArray()
End Function
Public Iterator Function EnumerateFilesRecursively(path As String, searchPattern As String) As IEnumerable(Of String)
For Each filePath In Directory.EnumerateFiles(path, searchPattern)
Yield filePath
Next
For Each folderPath In Directory.EnumerateDirectories(path)
Try
For Each filePath In EnumerateFilesRecursively(folderPath, searchPattern)
Yield filePath
Next
Catch ex As UnauthorizedAccessException
'Ignore inaccessible folders
End Try
Next
End Function

VB How do I add items to a class list using iteration?

This is a very simple question.
I am trying to add items to the Inventory class list from a .txt file. However i can't use the word 'New' in this line otherwise it give a syntax error:
New Inventory("Rod", 1)
Function GetInventory() As IEnumerable(Of Inventory)
If System.IO.File.Exists(loc) = True Then
If System.IO.File.ReadAllText(loc).Count > 0 Then
Dim file As System.IO.StreamReader
file = My.Computer.FileSystem.OpenTextFileReader(loc)
Do While file.Peek() >= 0
New Inventory("Rod", 1)
Loop
Return New Inventory
file.Close()
End If
End If
End Function
How do I go about this???
Thank you.
With what you have, you're reading the entire file into memory twice. That's crazy wasteful.
Also, you don't need the .Exists() check here. The file system is volatile, meaning it's possible for the file to cease to be available between when you check .Exists() and when you try to access the file. A good program will still have a good exception handler for when the file does not exist, and now that you have an exception handler, the .Exists() check is just redundant. It's not saving you the performance hit you likely think it is. Also, this method is probably the wrong place to handle the exception. That's usually better to do in the calling code somewhere, meaning you can skip error checking here completely.
You can get this whole method down to a single statement that will cut your execution time in half:
Function GetInventory(ByVal loc As String) As IEnumerable(Of Inventory)
Return IO.File.ReadLines(loc).Select(Function(i) New Inventory(i, 1))
End Function

Understanding the Open method and the Try block in VB.NET

I'm using VB.NET for the first time, to check if a file is in use, but there are some lines of code that I don't fully understand.
Can someone explain the two lines of code highlighted below in the comments?
Public Sub Main()
IsFileInUse("C:\someFolder\file.pdf")
End Sub
Function IsFileInUse(filePath As String) As Boolean
IsFileInUse = False
If System.IO.File.Exists(filePath) Then
Dim fileInfo As System.IO.FileInfo
Dim stream As System.IO.FileStream
fileInfo = New System.IO.FileInfo(filePath)
Try
' Can someone explain this line of code?
' how does this determines where to go from here, Catch or Finally?
stream = fileInfo.Open(System.IO.FileMode.Open, System.IO.FileAccess.ReadWrite, System.IO.FileShare.None)
Catch
IsFileInUse = True
MessageBox.Show("It looks like the file is opened")
Finally
If stream IsNot Nothing Then
' What is this closing?
stream.Close()
End If
End Try
Else
MessageBox.Show("File does NOT Exist")
End If
End Function
how does this determines where to go from here, Catch or Finally?
Look at the documentation for FileInfo.Open. The Exceptions section shows all of the possible exceptions that can happen.
If an exception is thrown, the Catch block will be executed.
The Finally block always gets executed, whether or not an exception was thrown.
What is this closing?
It will release the stream's resources, in this case it will close the file.
The Try block runs the code. In the Try block, a stream is used to open the file and access its contents. If that code errors for any reason, it will throw an Exception, which will then cause to the Catch block to be run. The Finally block of the code will run whether an Exception is thrown or not. In the Finally block, the stream to the File is being closed.
The code is determining whether or not the file is currently "in use" by any other processes by attempting to open the file with read/write access. Whether the opening of the file fails or not, it always closes the file stream. It assumes that if opening the file in that mode fails for any reason, then it must be because it is "in use". That's a bad assumption to make, and likely not the best way to accomplish it anyway, but for what it's worth, that's what it's doing.
The Try/Catch block is VB.NET's preferred syntax for exception handling (it replaces the older On Error syntax which predated .NET). When anything inside of the Try section throws an exception, execution will jump to the Catch section. Once execution of the Catch section completes, it then jumps to the Finally section. If nothing in the Try section throws an exception, then once it's done, it also jumps to the Finally section. Essentially, everything in the Finally section is "guaranteed" to execute, whether or not an exception occurred, whereas the code in the Catch section only executes when there is an exception.
In other words, consider this example:
' Outputs "ABCE" (does not output "D")
Console.Write("A")
Try
Console.Write("B")
Console.Write("C")
Catch
Console.Write("D")
Finally
Console.Write("E")
And compare it to this example:
' Outputs "ABDE" (does not output "C")
Console.Write("A")
Try
Console.Write("B")
Throw New Exception()
Console.Write("C")
Catch
Console.Write("D")
Finally
Console.Write("E")
See the MSDN article for much more information on the topic.

Using a IO variable before it has been assigned a value in a Try...Catch...Finally

I'm trying to use an IO object in VB.net which I'm not initialising from the declaration point. I use the object in several places in a Try..Catch block and then I use it again in the Finally block. For the purpose of my question you can ignore the method calls of my code. VS is showing this warning: Variable 'objSourceDirectory' is used before it has been assigned a value. A null reference exception could result at runtime.
I believe having safe checks in some places in my code the null reference shouldn't happen, but how could I get rid of this warning? I would initialise the variable as empty at declaration point but this can't be possible with IO.DirectoryInfo, as it doesn't have a construction without parameters. How can I fix this?
Dim object1 As IO.DirectoryInfo
Try
mlstProcessedFiles = New Global.System.Collections.Generic.List(Of String)
' Gather Data from import source
object1 = New IO.DirectoryInfo(object2.Location)
MethodD(object2.Location)
MethodA(object1)
MethodC(object2.Location)
' Work through files found in the source. Detect if the file was moved and add it to the manual processing
For Each objFile In object1.GetFiles()
Try
MethodB(objFile, object2)
objFile = Nothing
Catch objFileEx As FileNotFoundException
Catch objDirEx As DirectoryNotFoundException
MethodX(mstrERROR_11_MOVED, objDirEx.Message)
Continue For
End Try
Next
Catch objectException As Exception
Throw
Finally
'Make sure processed files have been moved to their folders
Method1()
Method2()
Method3(object1)
End Try
You haven't shown objSourceDirectory in your code. I assume it is object1 which is used in the Finally.
Yes, you cannot use a variable when it is possible that this variable was not assigned a value. You are using it in the Finally which is executed always, even on error.
Since you haven't assigned a default value it is possible that you get an exception which causes it to remain unassigned. This compiler error prevents you from careless mistakes.
To fix it you could assign Nothing:
Dim object1 As IO.DirectoryInfo = Nothing
but you should check if it's Nothing in the Finally or in Method3.
In this case you could also move the initilization to the declaration which makes it definitely assigned:
Dim object1 As IO.DirectoryInfo = New IO.DirectoryInfo(object2.Location)
Note that the compiler is not smart enough to check if it is possible that an errors is raised before the variable is initialized. It just looks at the Try and "thinks": it's possible that here comes an error.

Repeated error handling

So in my vb.net application, i've got alot of try and catch blocks for error handling, especially whenever my app talks to the db.
i'm running through a series of if/elseif statements to see if
ex.tostring.contains("Unable to connect to any of the specified MySQL hosts")
and various bits like that.
At the minute, I wrote this out and copy and pasted it into each catch, but I know there will be a much more efficient way to do this whereby the code is just in one place and called as and when required.
I tried to implement it as a function, but I had trouble passing info to the function.
So i thought I'd ask and see how you guys go about doing this?
You don't need multipe try...catch statements for a program. One is enough.
If i understood you correctly, you want to print or show the error that occured inside the Try block.
Public Sub main()
Try
'Do something
Catch ex As Exception
End Try
Try
'Do something else
Catch ex As Exception
End Try
If ex.tostring.contains("something") than
End Sub
Instead you can do something like this:
Public Sub main()
Try
'Do all your code here.
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
In this part, the compiler will automaticlly print the error occured in the program.
You can perform some action based on the type of exception thrown. Checking the text if not recommended as this could change with a new version of .net or mysqldata
Try something like this:
Try
'
' Programming lines of code
'
Catch exError As MySqlException
' an error occurred with MySql
Catch e As Exception
' a General error occurred
Finally
' Cleanup custom and unmanaged resources if necessary
End Try
Have a look at the MySQL Documentation for their recommendations