I am currently working on a console application to play a freshly created WAV RIFF file, and then delete it. Like I said, it is freshly created, so I need to make sure the file isn't being edited before I start playing it or it will be corrupted. After it plays, I delete it.
Currently, my code looks like this (using System.IO):
Sub Main()
Dim fileName As String
fileName = "C:\temp\Burst\Burst.wav"
While CheckFile(fileName)
End While
Try
My.Computer.Audio.Play(fileName, AudioPlayMode.WaitToComplete)
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
My.Computer.FileSystem.DeleteFile(fileName)
End Sub
Private Function CheckFile(ByVal filename As String) As Boolean
Try
System.IO.File.Open(filename, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.None)
FileClose(1)
Return False
Catch ex As Exception
Return True
End Try
End Function
The function I am using to check if the file is opened was created by sealz. I found it here. Unfortunately, however, this function is causing an exception in that after it runs, the program cannot access the file because it is being used by another process. If I remove this function, the file can be opened, played and deleted.
The exception reads as follows:
An unhandled exception of type'System.IO.IOException' occurred in mscorlib.dll Additionalinformation: The process cannot access the file 'C:\temp\Burst\burst.wav' because it is being used by another process.
So the function that is supposed to help determine if the file is being used, is actually causing the file to be opened. It seems like it isn't closing. Is there anyway I can modify this current function to work properly for my application or are there any other ideas on how to tackle this. Thanks for your time.
-Josh
Here is your problem:
System.IO.File.Open(filename, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.None)
FileClose(1)
Return False
A Using will help:
Using _fs as System.Io.FileStream = System.IO.File.Open(filename, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.None)
End Using
Return False
File.Open Returns a Filestream, not an Integer needed for FileClose
As far as I get you are trying to check if file exists before playback using System.IO.File.Open however you may do it with File.Exists.
Method File.Exists from System.IO returns true if file exists on path and returns false the otherwise.
Also you are doing it wrong here,
While CheckFile(fileName)
End While
If file is found it will enter into an infinite loop without doing anything other than calling CheckFile repeatedly. If file is not found, it will get out of loop and attempt Audio.Play and FileSystem.DeleteFile and you end up getting a file not found exception.
Here is your code modified and working.
Imports System.IO
Module Module1
Sub Main()
Dim fileName As String
fileName = "C:\temp\Burst\Burst.wav"
While CheckFile(fileName)
Try
My.Computer.Audio.Play(fileName, AudioPlayMode.WaitToComplete)
'Delete statement here if you want file to be deleted after playback
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
End While
My.Computer.FileSystem.DeleteFile(fileName)
Console.ReadLine()
End Sub
Private Function CheckFile(ByVal filename As String) As Boolean
If (File.Exists(filename)) Then
Return True
Else
Return False
End If
End Function
End Module
Related
I get the feeling this is something really simple, but I've tried I don't know how many permutations of vbNewLine, Environment.NewLine, sMessage & vbNewLine (or Environment.Newline) I've tried, or how many pages on this site, or through Google I've looked at but nothing has worked.
I even tried getting help from a VB.Net discord channel I'm a part of and they suggested to do the same things that I've done and the procedure is still writing each new log entry at the end of the previous one in a continuous string. My writer is below. Am I missing something simple?
Edit: The code that worked is below in case anyone else comes along with the same issue. If you want to see the original code it's in the edit log.
Option Explicit On
Imports System.IO
Public Class WriteroLog
Public Shared Sub LogPrint(sMessage As String)
Dim AppPath As String = My.Application.Info.DirectoryPath
If File.Exists($"{AppPath}\Log.txt") = True Then
Try
Using objWriter As StreamWriter = File.AppendText($"{AppPath}\Log.Txt")
objWriter.WriteLine($"{Format(Now, "dd-MMM-yyyy HH:mm:ss")} – {sMessage}")
objWriter.Close()
End Using
Catch ex As Exception
MsgBox(ex)
Return
End Try
Else
Try
Using objWriter As StreamWriter = File.CreateText($"{AppPath}\Log.Txt")
objWriter.WriteLine($"{Format(Now, "dd-MMM-yyyy HH:mm:ss")} – {sMessage}")
objWriter.Close()
End Using
Catch ex As Exception
MsgBox(ex)
Return
End Try
End If
End Sub
End Class
The File.AppendText() method creates a new StreamWriter that is then used to append Text to the specified File.
Note, reading the Docs about this method, that you don't need to verify whether the File already exists: if it doesn't, the File is automatically created.
As a side note, when creating a Path, it's a good thing to use the Path.Combine method: it can prevent errors in the path definition and handles platform-specific formats.
Your code could be simplified as follows:
Public Shared Sub LogPrint(sMessage As String)
Dim filePath As String = Path.Combine(Application.StartupPath, "Log.Txt")
Try
Using writer As StreamWriter = File.AppendText(filePath)
writer.WriteLine($"{Date.Now.ToString("dd-MMM-yyyy HH:mm:ss")} – {sMessage}")
End Using
Catch ex As IOException
MsgBox(ex)
End Try
End Sub
The File.CreateText does not assign result to "objWrite", should be:
objWriter = File.CreateText($"{AppPath}\Log.Txt")
Not really sure if this is the root of your problem, but it is an issue.
In essences, your logic is re-opening or creating the stream "objWriter" for every call to this method. I would recommend you initialize "objWriter" to Nothing and only define if it is Nothing.
Set to Nothing as below.
Shared objWriter As IO.StreamWriter = Nothing
Then add check for Nothing in logic.
i am creating a hangman game that is to be used on a few computers, i have created the hangman game itself but i am using the "load form" function to create the list when the program first starts, but i am having this issue.
An unhandled exception of type 'System.IO.IOException' occurred in mscorlib.dll
Additional information: The process cannot access the file 'h:\Bryson\words.txt' because it is being used by another process.
Using sw As StreamWriter = File.CreateText("h:\Bryson\words.txt")
^^that line is where the error pops up^^
I have inserted some in code Comments to make life easier. If anyone can help thanks in advance :)
'USED TO CREATE HANGMAN FILE IF NOT FOUND
Private Sub main_Load(sender As Object, e As EventArgs) Handles MyBase.Load
fofound = False
fifound = False
MsgBox("remove this and change file path and fix qu2 quiz")
'DESIGNER USE
Dim path As String = "h:\Bryson\words.txt"
'CREATE VAR FOR PATH
If System.IO.Directory.Exists("h:\Bryson") Then
'CHECKS IF FOLDER EXISTS
fofound = True
Else
'IF IT DOES THEN IT MOVES ON
System.IO.Directory.CreateDirectory("h:\Bryson")
'IF NOT IT CREATES THE FOLDER
fofound = True
If File.Exists("h:\Bryson\test\words.txt") Then
'CHECKS IF FILE EXISTS
fifound = True
Else
'IF IT DOES IT MOVES ON
IO.File.Create("h:\Bryson\words.txt")
'IF NOT IT CREATES IT
FileClose()
End If
End If
If fofound And fifound = True Then
Else
Using sw As StreamWriter = File.CreateText("h:\Bryson\words.txt")
'CRASH POINT The process cannot access the file 'C:\Bryson\words.txt'
'because it Is being used by another process.
sw.WriteLine("Hangman")
sw.WriteLine("computer")
sw.WriteLine("electrode")
sw.WriteLine("independent")
sw.WriteLine("stream")
sw.WriteLine("enforcing")
End Using
'WRITES TO FILE
MsgBox("file created")
'DESIGNER USE
FileClose()
'CLOSES FILE
End If
End Sub
FileClose() is a legacy function from VB6 and will not affect anything in the System.IO namespace. To close a file you need to call .Close() or .Dispose() on the stream that has opened the file (wrapping the stream in a Using block does this automatically).
Your problem is this line:
IO.File.Create("h:\Bryson\words.txt")
The method creates a new file and opens a FileStream to it which locks the file. Since you never close the returned FileStream your file will remain locked until you close your application.
The File.Create() call is completely unnecessary though because File.CreateText() will create the file if it doesn't exist. So you should just remove the above line.
I have an application that generates documents.
However if a document is already open, then the generated new document cannot override the opened document, so no changes occur.
How can I properly check whether the document is already open or not? (And if open, then close it)
This code is working for me
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
You may try like this:
If File.Exists(Application.StartupPath & "\~$MyWordDocument.doc") Then
MsgBox("File is open")
Exit Sub
End If
Also check FAQ: How do I check whether a file is in use?
I have a program (simple file updater) which downloads a file. Before that, an old version of this file is queued for deletion. But if I edit this file e.g. in text editor (save and close it), then my program refuses to delete it.
I have sub like this
Private Sub delete_file(ByVal dir As String)
Try
If My.Computer.FileSystem.FileExists(dir) Then My.Computer.FileSystem.DeleteFile(dir)
Catch ex As Exception
Debug.WriteLine(ex.ToString())
Sleep(1000)
delete_file(dir)
End Try
End Sub
It never goes out of the recursion. Exception says that file is being used by other process, and waiting doesn't change anything.
Any clues?
[EDIT]
Changed Sub a bit, so it doesn't contain recursion in Exception handler
Private Sub delete_file(ByVal dir As String)
Dim ok As Boolean = True
Try
If My.Computer.FileSystem.FileExists(dir) Then My.Computer.FileSystem.DeleteFile(dir)
Catch ex As Exception
Debug.WriteLine(ex.ToString())
ok = False
End Try
If ok = False Then
Sleep(1000)
delete_file(dir)
End If
End Sub
Words "another process" are VERY ambiguous.
It turned out that other function from my program was opening the same file twice, and closing it only once. Fixing that removed problem with deleting it.
So when u're having the same error, try searching your program for other places when this file may be modified.
Thanks for comments, they surely gave me some hints about good programming.
Is there a method to verify that a file is open? The only thing I can think of is the Try/Catch to see if i can catch the file-open exception but I figured that a method be available to return true/false if file is open.
Currently using System.IO and the following code under class named Wallet.
Private holdPath As String = "defaultLog.txt"
Private _file As New FileStream(holdPath, FileMode.OpenOrCreate, FileAccess.ReadWrite)
Private file As New StreamWriter(_file)
Public Function Check(ByVal CheckNumber As Integer, ByVal CheckAmount As Decimal) As Decimal
Try
file.WriteLine("testing")
file.Close()
Catch e As IOException
'Note sure if this is the proper way.
End Try
Return 0D
End Function
Any pointers will be appreciated! Thank you!!
Private Sub IsFileOpen(ByVal file As FileInfo)
Dim stream As FileStream = Nothing
Try
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None)
stream.Close()
Catch ex As Exception
If TypeOf ex Is IOException AndAlso IsFileLocked(ex) Then
' do something here, either close the file if you have a handle, show a msgbox, retry or as a last resort terminate the process - which could cause corruption and lose data
End If
End Try
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
Call it like this:
Call IsFileOpen(new FileInfo(filePath))
There is really no point using a 'is file in use check' function since you will still need to have try catch to handle the case that the file fails to open. The file open can fail for many more reasons than it just being already open.
Also using a function to do a check is no guarantee of success. The 'is file in use check' might return false only for the file open to fail with a file already open error, because in time between the check and trying to open the file it was opened by someone else.
It looks like the two suggestions from this MSDN forum posting both involve trying to open the file.
The first one is similar to what you are doing now, and the second involves using a Windows API function (CreateFile) and checking for a invalid handle signifying the file is in use. In both cases they are relying on an error condition to determine if the file is open or not. In short, in my opinion the method you are using is correct since there is not a System.IO.File.IsOpen property.