Check the file whether is it by another process - vb.net

I have some ask to you to check and advice if my code is enough and correct. My application works on files sometimes its downloading multiple files by windows service and then by other windows service parser process those files are parsing. Unfortunately before process file has to be finished downloading before process parser should open the file and play with it therefore i prepared some code to check firstly whether the file is free - means not open by another process or some person, whatever. I use most cases streamreader to open the file and play with it but as i said i would like firstly check file if its ready.
This is my code, what do you think:
Public Shared Function FileInUse(ByVal sFile As String, ByVal log As String) As Boolean
Dim thisFileInUse As Boolean = True
Dim counter As Integer = 0
For i = 0 To 30
counter += 1
If System.IO.File.Exists(sFile) Then
Try
Using f As New IO.FileStream(sFile, FileMode.Open, FileAccess.ReadWrite, FileShare.None)
thisFileInUse = False
Exit For
End Using
Catch
System.Threading.Thread.Sleep(10000) '10 sec
End Try
End If
Next
Return thisFileInUse
End Function

Related

Unable to move the file because it is being used in another process

In my project I launch a batch file (not mine) that opens a pdf file, I wait 7000 milliseconds, then I close the Adobe processes and repeat the sequence again, at the end of everything I move the file to a new folder, but every now and then the program goes in exception
the function I use is this (vb.net):
Function Close(name as String)
{
dim processList as Process() = Process.GetProcessByName(name)
If processList.Count < 0 then
processList = Process.GetProcessByName(“AcroRd32”)
End If
For i as Integer = 0 to processList.Count - 1
processList(i).CloseMainWindow()
Next
}
I state that this exception when testing my program had never happened, in the client's desk it happened

VB.NET: The process cannot access the file 'filename' because it is being used by another process

I should add a list of files into a ZIP. Procedure code is like this
Sub CreateZip
Dim FileList As New ArrayList 'List of File Paths to be added to the ZIP
For Each path in FileList
Try
AddFileToZip(ZipFilePath, path.ToString)
Catch (ex as New Exception)
....
End Try
Next
End Sub
And this is AddFileToZip
Public Sub AddFileToZip(ByVal zipFilename As String, ByVal fileToAdd As String)
Using zip As Package = System.IO.Packaging.Package.Open(zipFilename, FileMode.OpenOrCreate)
Dim destFilename As String = ".\" & Path.GetFileName(fileToAdd)
Dim uri As Uri = PackUriHelper.CreatePartUri(New Uri(destFilename, UriKind.Relative))
If zip.PartExists(uri) Then
zip.DeletePart(uri)
End If
Dim part As PackagePart = zip.CreatePart(uri, "", CompressionOption.Normal)
Using fileStream As New FileStream(fileToAdd, FileMode.Open, FileAccess.Read)
Using dest As Stream = part.GetStream()
CopyStream(fileStream, dest)
End Using
End Using
End Using
End Sub
At runtime, I get this error message
The process cannot access the file [ZipFilePath] because it is being used by another process
this error is raised randomly, maybe on adding small files into the Zip. If I place breakpoints and run procedure in debug mode, it works.
It seems clear that procedure thread is not synchronized with IO, so that my procedure loop continues even if IO is still adding processed file into Zip (ie VB.NET is faster than IO).
I also tried to place a Thread.Sleep(1000) before AddFileToZip, but this may be not enough to synchronize the two processes. Placing Thread.Sleep(2000) seems to make procedure work, but it may slow down dramaticly performances (I should pack more than 50 files into my Zip).
So, how can I force my loop to "wait" until IO Process has released ZIP file?

ftp download stopping before end of list

I'm using the following code to download files from an FTP server. Before entering this code, I have created a list of filenames from files that are in the directory on the FTP server. There are over 2000 files in the list.
As I iterate through the list, the files download properly until I reach exactly 121 files downloaded. Then it starts giving me an error of "file not found, access denied." for every file after that. However the files are there. If I start the process over again it will pick up from where it left off and download another 121 files and continue until it errors again after the next 121 files.
Here is the code:
For Each file As String In dirlist
DownloadFile(local_path + "\" + filename, new_path + "/" + Trim(filename), client)
Next
Private Sub DownloadFile(ByVal localpath As String, ByVal ftpuri As String, client As String)
Dim request As New WebClient()
request.Credentials = New NetworkCredential(user_name, password)
Dim bytes() As Byte = request.DownloadData(ftpuri)
Try
Dim DownloadStream As FileStream = IO.File.Create(localpath)
DownloadStream.Write(bytes, 0, bytes.Length)
DownloadStream.Close()
Catch ex As Exception
add_to_log(log_window, ex.Message)
End Try
End Sub
I do not understand why it is stopping before completing the list.

How do know the csv created from SQLite is closed so I can read from it?

In vb.net, I have my program run sqlite3.exe. Sqlite3 runs the following commands, which are stored in a text file:
.open prod.db
.mode csv
.output output.csv
SELECT STATEMENT
.output stdout
.exit
Once output.csv has been created, I then run a Streamreader to see what the results were and I get the following error:
The process cannot access the file 'output.csv' because it is being used by another process.
However, I know it is not locked up for long because I can go to the csv and open it manually after it is created.
I would write code to check to see when the process finishes, but I'm not sure what process is running to check this (I already check for SQLite3.exe to close). In other words, how do I know my csv is free for Streamreader to open?
Using droque's link"
VB.Net 3.5 Check if file is in use
I was able to combine this with some of my own code to fix the problem:
While FileInUse("output.csv") And j < 100
System.Threading.Thread.Sleep(100)
j += 1
End While
'Timeout after ~10 seconds
If j = 100 Then
MessageBox.Show("CSV timeout. Exiting now.")
Exit Sub
End If
where FileInUse is defined here:
Public Function FileInUse(ByVal sFile As String) As Boolean
Dim thisFileInUse As Boolean = False
If System.IO.File.Exists(sFile) Then
Try
Using f As New IO.FileStream(sFile, FileMode.Open, FileAccess.ReadWrite, FileShare.None)
' thisFileInUse = False
End Using
Catch
thisFileInUse = True
End Try
End If
Return thisFileInUse
End Function

Deleting file if not just created (or being used)

I am creating a console app that will delete pictures from a directory every 30 minutes. Problem is that its being populated by files every minute or so. So if I go and delete files in that directory then it may cause an error trying to delete a file thats being created just then or opened.
I currently have this code to copy the files to another directory and then delete them from the source directory.
Dim f() As String = Directory.GetFiles(sourceDir)
For i As Integer = 0 To UBound(f)
'Check file date here in IF statement FIRST...
File.Copy(f(i), destDir & f(i).Replace(sourceDir, ""))
If File.Exists(f(i)) = True Then
File.Delete(f(i))
End If
Debug.Print(f(i) & " to >>> " & destDir & f(i).Replace(sourceDir, ""))
Next
How can I use:
File.GetCreationTime(f(i))
in an IF statement checking IF the currently file its on is newer than 30 seconds ago?
OR
Is there a way of only populating:
Dim f() As String = Directory.GetFiles(sourceDir)
with only those files that are more than 30 seconds old?
There isn't a reliable way to detect if a file is locked or not. Even if you did find out (it is technically possible), it could be locked before you tried to delete it. There are other reasons a delete may fail. In your case, I don't think it matters what the reason was.
The only way is to put the call to delete in a try/catch and trap IOException, and then retry if you want.
You need to use a FileInfo object to get the CreatedTime and compare to Now. You can also use LastAccessTime or LastWriteTime, but since these are all new files being written then, you don't need to.
Private Sub DeleteFiles()
Dim files = From f In Directory.GetFiles("c:\temp")
Let fi = New FileInfo(f)
Where fi.Exists AndAlso fi.CreationTime <= DateTime.Now.AddSeconds(-30)
For Each f In files
Try
f.Delete()
Catch ex As Exception
If TypeOf ex Is IOException AndAlso IsFileLocked(ex) Then
' do something?
End If
'otherwise we just ignore it. we will pick it up on the next pass
End Try
Next
End Sub
Private Shared Function IsFileLocked(exception As Exception) As Boolean
Dim errorCode As Integer = Marshal.GetHRForException(exception) And ((1 << 16) - 1)
Return errorCode = 32 OrElse errorCode = 33
End Function
IsFileLocked function lifted from this other thread on SO
Dim NewFileDate As DateTime = DateTime.Now.AddSeconds(-30)
' get the list of all files in FileDir
Dim PicFiles As List(Of String) = System.IO.Directory.GetFiles("C:\", "*.txt").ToList()
' filter the list to only include files older than NewFileDate
Dim OutputList As List(Of String) = PicFiles.Where(Function(x) System.IO.File.GetCreationTime(x) < NewFileDate).ToList()
' delete files in the list
For Each PicFile As String In OutputList
'wrap this next line in a Try-Catch if you find there is file locking.
System.IO.File.Delete(PicFile)
Next
Obviously targeting .Net 3.5 or 4.0