How do I output to a text file without getting an IO exception? - vb.net

I have this code.
Dim txtVern As String = String.Empty
Try
Using verSR As New StreamReader(appDataVersionLoc)
txtVern = verSR.ReadToEnd()
End Using
Catch ex As Exception
Dim verFile As System.IO.FileStream
verFile = System.IO.File.Create(appDataVersionLoc)
Dim wWFERes As DialogResult = MessageBox.Show("Version file missing/corrupt, created a new one.")
If My.Computer.FileSystem.FileExists(appDataVersionLoc) Then
My.Computer.FileSystem.WriteAllText(appDataVersionLoc, "0.0.0.0", True)
End If
End Try
But when it tries to execute My.Computer.FileSystem.WriteAllText(appDataVersionLoc, "0.0.0.0", True), I get this error:
The process cannot access the file 'C:\Users\Dubstaphone\AppData\Roaming\TheArena\version.txt' because it is being used by another process.
How to I avoid this? What I did was I made it create a text file called "version.txt" if it doesn't already exist. Now I'm trying to write "0.0.0.0" to it, but it's giving me that error. By the way, "appDataVersionLoc" equals GetFolderPath(SpecialFolder.ApplicationData) & "\TheArena\version.txt"
This variable works fine for everything else.
Thanks!
P.S.
I'm a complete noob.

System.IO.File.Create or My.Computer.FileSystem.WriteAllText may still hold a lock on the file. Use the System.IO.File WriteAllText and a Using statement.
If you use a Stream you should close/dispose of it. Better yet when dealing with files always use a Using statement.
Edit:
Example of creating a file
Using File.Create(path)
End Using
If File.Exists(appDataVersionLoc) Then
File.WriteAllText(appDataVersionLoc, "0.0.0.0")
End If
or
Dim appDataFile = File.Create(path)
appDataFile.Close

Related

Log Writer not creating new line for each entry

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.

Saving embedded resource contents to string

I am trying to copy the contents of an embedded file to a string in Visual Basic using Visual Studio 2013. I already have the resource (Settings.xml) imported and set as an embedded resource. Here is what I have:
Function GetFileContents(ByVal FileName As String) As String
Dim this As [Assembly]
Dim fileStream As IO.Stream
Dim streamReader As IO.StreamReader
Dim strContents As String
this = System.Reflection.Assembly.GetExecutingAssembly
fileStream = this.GetManifestResourceStream(FileName)
streamReader = New IO.StreamReader(fileStream)
strContents = streamReader.ReadToEnd
streamReader.Close()
Return strContents
End Function
When I try to save the contents to a string by using:
Dim contents As String = GetFileContents("Settings.xml")
I get the following error:
An unhandled exception of type 'System.ArgumentNullException' occurred in mscorlib.dll
Additional information: Value cannot be null.
Which occurs at line:
streamReader = New IO.StreamReader(fileStream)
Nothing else I've read has been very helpful, hoping someone here can tell me why I'm getting this. I'm not very good with embedded resources in vb.net.
First check fileStream that its not empty as it seems its contains nothing that's why you are getting a Null exception.
Instead of writing to file test it by using a msgBox to see it its not null.
fileStream is Nothing because no resources were specified during compilation, or because the resource is not visible to GetFileContents.
After fighting the thing for hours, I discovered I wasn't importing the resource correctly. I had to go to Project -> Properties -> Resources and add the resource from existing file there, rather than importing the file from the Solution Explorer. After adding the file correctly, I was able to write the contents to a string by simply using:
Dim myString As String = (My.Resources.Settings)
Ugh, it's always such a simple solution, not sure why I didn't try that first. Hopefully this helps someone else because I saw nothing about this anywhere else I looked.

Null Reference Exception when reading file vb.NET

So I am creating a program that needs to be able to read line by line from a .cfg (config) file, it can open it happily; here is the code:
OpenConfig.ShowDialog()
file = OpenConfig.FileName()
fileReader()
However when it tries to read the file, using this code:
Function fileReader()
Dim reader As New StreamReader(file)
Dim vLb As ListBox = shopTabs.SelectedTab.Controls.Item(10) 'Listbox Variable
For i = 0 To reader.Peek
textline(i) = reader.ReadLine()
vLb.Items.Add(i)
Next
Return True
End Function
It throws an exception at the line:
textline(i) = reader.ReadLine()
Any help would be greatly appreciated as I can't work out why it does so.
Your code could be simplified into the following code:
Using openConfig As New OpenFileDialog()
If openConfig.ShowDialog(Me) = DialogResult.OK Then
For Each s As String In File.ReadAllLines(openConfig.FileName)
ListBox1.Items.Add(s)
Next
End If
End Using
As I commented, your code does some things that are highly questionable and undoubtedly difficult to maintain, such as referencing a control by the index property.
I suspect that your project would benefit from using UserControls too, since I'm guessing you have the same controls placed in every tab (a ListBox is always control index #10?).

Streamwriter not adding text to file?

I have the following code:
If line = Nothing Then
MsgBox("Login failed.")
Using sw As New StreamWriter(File.Open(Index.strLogPath, FileMode.OpenOrCreate)) ' open or create a new file at our path
sw.BaseStream.Seek(0, SeekOrigin.End) ' append new users to the end
sw.AutoFlush = True
sw.WriteLine("line is nothing")
sw.Flush()
sw.Close()
End Using
End If
My line = nothing condition is met, the msgbox pops up letting me know, but the file is not created. If the file is there, nothing is added to it.
I have checked the path validity, and ensured that applications have permission there, everything I can think of isn't working, and to make it more frustrating there are no errors! Any help would be greatly appreciated.
Did you know that the File class already has a utility method to do exactly that?
File.AppendAllText(Index.strLogPath, "line is nothing")
Should be as simple as that. :)
EDIT
If you insist on managing the file stream yourself, try this:
Using sw As New StreamWriter(File.Open(Index.strLogPath, FileMode.Append)) ' open or create a new file at our path
sw.WriteLine("line is nothing")
End Using
Points of interest:
Use FileMode.Append instead of OpenOrCreate
No need to flush or close. This is done automatically when you leave the "using" block.

Why am I getting object reference not set error on script task connector?

I have an SSIS package (SQL Server 2005) that loops through a bunch of flat files in a folder. I need to wait until the source application has finished writing the file before I can open it in my flat file import task.
I have a For Each loop container and within it a script task to execute before the Data Flow Task.
When I try to create the success connector between the Script Task and the Data Flow Task I get this error:
Could not create connector. Object reference not set to an instance of
an object.
I get that something is being set to nothing, but I can't see it. I have DelayValidation set to true on both the Script Task and the Data Flow Task. What else am I missing?
I'm a C# guy so maybe I'm missing something obvious in the VB. Here's the script I poached from the interwebs:
Public Sub Main()
Dim strFileName As String = CType(Dts.Variables("FileName").Value, String)
Dim objFS As System.IO.FileStream
Dim bolFinished As Boolean = False
Do
Try
objFS = System.IO.File.Open(strFileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None)
bolFinished = True
objFS.Close()
Catch ex As Exception
System.Threading.Thread.Sleep(1000)
End Try
Loop
If bolFinished Then
Dts.TaskResult = Dts.Results.Success
Else
Dts.TaskResult = Dts.Results.Failure
End If
End Sub
Milen k is more than right. It looks like you have an infinite loop which is opening a file several times until it breaks down.
You could change your code with the below suggested code. This will help you to get out of the infinite loop.
Your current code:
Do
Try
objFS = System.IO.File.Open(strFileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None)
bolFinished = True
objFS.Close()
Catch ex As Exception
System.Threading.Thread.Sleep(1000)
End Try
Loop
Suggested code:
Do While(true)
Try
objFS = System.IO.File.Open(strFileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None)
bolFinished = True
objFS.Close()
Exit Do
Catch ex As Exception
System.Threading.Thread.Sleep(1000)
End Try
Loop
Make sure that you have created a Flat File Source for your Data Flow task. If you do not have an existing one, create a temporary one which act as a place-holder for the file paths you feed it through the For Each loop.
From what I understand, you should be passing the path to each file that you will be importing to your Flat File Connection. This can easily be done by adding the variable generated in your For Each loop as an expression in the Expression property of your Flat File Connection.
UPDATE:
You need to set a condition in your Do ... Loop. For example: Loop While Not bolFinished. Look at this document for more information.