Delaying the use of code while a file is created? - vb.net

Okay, so my program is checking to see is a textfile exist (this works) then if it doesn't exist it's creating the directory and file as well as saving the data to the file. I receive the error when it drops into the second test statement to create the text file.
The program will create the directory and file, but fail to write to it. "unhandeled exception: file is being used by another process. If I click to ignore the error and run the program, I can click the save button again and it works properly.
So I guess my question is, can I somehow delay the code that writes to the file long enough for the other operation to finish, or is there a better way to structure it, so it's not an issue.
Relevant Code:
Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
'create necessary directory
'create text file
'if file exist write to file
If My.Computer.FileSystem.FileExists("C:\Documents and Settings\All Users\Documents\NailPolishSelector\polishColors.txt") = True Then
MsgBox("Data Saved")
Using sr As New IO.StreamWriter("C:\Documents and Settings\All Users\Documents\NailPolishSelector\polishColors.txt")
For Each line In lstColors.Items
sr.WriteLine(line)
Next
sr.Close()
End Using
ElseIf My.Computer.FileSystem.FileExists("C:\Documents and Settings\All Users\Documents\NailPolishSelector\polishColors.txt") = False Then
My.Computer.FileSystem.CreateDirectory("C:\Documents and Settings\All Users\Documents\NailPolishSelector")
Dim fs As FileStream = File.Create("C:\Documents and Settings\All Users\Documents\NailPolishSelector\polishColors.txt")
'error occurs here
Using srr As New IO.StreamWriter("C:\Documents and Settings\All Users\Documents\NailPolishSelector\polishColors.txt")
For Each line In lstColors.Items
srr.WriteLine(line)
Next
srr.Close()
End Using
MsgBox("File Created")
End If
End Sub

Your problem is that the file is locked by the fs FileStream object, and so the srr StreamWriter cannot write to it as it is trying to get a reference to the file by its name
So replacing
Using srr As New IO.StreamWriter("C:\Documents and Settings\All Users\Documents\NailPolishSelector\polishColors.txt")
with
Using srr As New IO.StreamWriter(fs)
should fix your problem.

Your code can be re-written somewhat to make it simpler and more robust. I'm guessing that if the file exists then you want to replace it, but if not then please remove the 'OPTIONAL piece of code:
Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
' Get the All Users documents folder
Dim docsFolder As String = Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments)
' Combine it with the desired directory and filename
Dim theFile As String = Path.Combine(docsFolder, "NailPolishSelector\polishColors.txt")
'OPTIONAL
' Remove the previous version of the file
If My.Computer.FileSystem.FileExists(theFile) Then
File.Delete(theFile)
End If
' REQUIRED: Create the directory if it doesn't exist
If Not Directory.Exists(Path.GetDirectoryName(theFile)) Then
Directory.CreateDirectory(Path.GetDirectoryName(theFile))
End If
' Create the data file
File.AppendAllLines(theFile, lstColors.items)
MsgBox("Data saved.")
End Sub
(Thanks go to Magnus for pointing out File.AppendAllLines(path, lstColors.Items).)
There are a couple of things there which you may which to look up in the documentation: the use of the SpecialFolders enumeration and Path.Combine.

Related

How to WriteAllText but restrict to overwrite the existing file?

Jan 8. 2023:
The AppendAllText can append into existing file and can create a file if no file exist.
the WriteAllText can Write into new created file and overwrite the existing file.
I'm trying to find another alltext for what I want to happen.
What I want to do is to save my textboxcontent.text into txt file.
I want to save 3 different content that will be displayed into my textboxcontent.text
And I only have one button.
That one button will open savefiledialog but with the code I have, I can only do 2 things, Write and Append.
Now, This is what suppose to happen.
*If I save the textcontent.text to an existing txt file, it will prompt message box "Do you want to overwrite this file?" And even if I click Yes, it will not allow to.
I must be able to create new txt file since I was not able to overwrite the file.
The reason is because I don't want to delete or overwrite the existing file with important information saved in it.
I hope somebody can help me.
This is the code I have.
```Imports System.io
Private lastSaveFileName As String = String.Empty
Private Function GetSaveFileName3(ByVal suggestedName As String) As String
Using sfd3 As New SaveFileDialog()
sfd3.Filter = "Text Files (*.txt) |*.txt"
sfd3.FileName = suggestedName
sfd3.OverwritePrompt = True
If DialogResult.OK Then
End If
If sfd3.ShowDialog() = DialogResult.OK Then
MessageBox.Show(
Me, "Your activity is not saved! This file have records from your last session, you cannot overwrite this file. Please create new file to save new records.",
"Save error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation
)
Else
End If
Return String.Empty
End Using
End Function
Private Sub Button6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button6.Click
lastSaveFileName = GetSaveFileName3(lastSaveFileName)
If Not String.IsNullOrEmpty(lastSaveFileName) Then
File.AppendAllText(lastSaveFileName, TextContent.Text)
End If
End Sub ' This code above includes IMPORTS.IO
Jan 9, 2023: Update
This is what I've done so far.
I tried to use the File.Exist but I don't know where to place it to make it run in the way I wanted.
Please see this code and help me fix it.
This code is running well in almost the way I want. I'm missing something.
Imports System.IO
Private lastSaveFileName As String = String.Empty
Private Sub SaveFile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SaveFile.Click
If Not File.Exists(lastSaveFileName) Then
lastSaveFileName = GetSaveFileName(lastSaveFileName)
If Not String.IsNullOrEmpty(lastSaveFileName) Then
File.WriteAllText(lastSaveFileName, txtdisplay1.Text)
End If
ElseIf File.Exists(lastSaveFileName) Then
lastSaveFileName = GetSaveFileName2(lastSaveFileName)
If Not String.IsNullOrEmpty(lastSaveFileName) Then
File.WriteAllText(lastSaveFileName, txtdisplay1.Text)
End If
End If
End Sub
Private Function GetSaveFileName2(ByVal suggestedName As String) As String
Using sfd As New SaveFileDialog()
sfd.Filter = "Text Files (*.txt) |*.txt"
sfd.FileName = suggestedName
sfd.OverwritePrompt = True
If sfd.ShowDialog() = DialogResult.OK Then
'If File.Exists(lastSaveFileName) Then
MessageBox.Show(
Me, "Your activity is not saved! This file have records from your last session, you cannot overwrite this file. Please create new file to save new records.",
"Save error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation
)
End If
Return String.Empty
End Using
End Function
Private Function GetSaveFileName(ByVal suggestedName As String) As String
Using sfd As New SaveFileDialog()
sfd.Filter = "Text Files (*.txt) |*.txt"
sfd.FileName = suggestedName
sfd.OverwritePrompt = True
If sfd.ShowDialog() = DialogResult.OK Then
Return sfd.FileName
End If
Return String.Empty
End Using
End Function
With this code, I was able to save the textdisplay to a txtfile but it's like, it's bypassing the Elseif function.
Sometimes, poeple forgot to avoid important files and accidentally deleted it. This is what I'm preventing to happen.
I let the overwriteprompt true to let it ask the user if they want to replace. It accidentally click the yes, this will show message "This file have records from your last session, Please create new file to save new records." means that even the user want to replace it, the program will not allow it. I don't want to remove that scenario.
(Scenario 1)
What happen in this code is this, when I click the button, savefiledialog pop up and giving me choice how I want to save the textdisplay.
I can create new file or replace existing file.
First, I choose to replace, and a messagebox shows and saying, I can't replace the file.
Then I create new file, it lets me save the txt display normally.
(scenario 2)
That's what I want. The code runs that way at first, but if you click the button again, and try to create new file first, the message box will show saying I can't replace the file. then when I choose to replace, no message box shows and the file was replace. I lost the file.
That's where I need help. I only want the Scenario 1.
Please try on your own I you don't get what I mean.
I tried this and this code works the way I want.
Private Sub SaveButton_Click(sender As Object, e As EventArgs) Handles SaveButton.Click
Dim saveFileDialog1 As New SaveFileDialog()
saveFileDialog1.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*"
saveFileDialog1.FilterIndex = 2
saveFileDialog1.RestoreDirectory = True
If saveFileDialog1.ShowDialog() = DialogResult.OK Then
If File.Exists(saveFileDialog1.FileName) Then
MessageBox.Show("A file with that name already exists. Please select a different file name or choose a different location to save the file.")
Else
File.WriteAllText(saveFileDialog1.FileName, Txtdisplay1.Text)
End If
End If
End Sub
Answered by: schoemr

visual studio 2019 how do I know what References to import and path settings

I created a Visual Studio 2019 project that uses FileSystem.FileExists and both StreamWriter and StreamReader
I also created a folder named Resource with the intention of creating a txt file in this folder
Knowing I need to tell the Writer and Reader where to find the file I used these lines of code
Dim path As String = "C:/Users/Me/source/repos/TestForms/TestForms/Resource/"
If Not My.Computer.FileSystem.FileExists(path & "Check.txt") Then
Because I do not full understand how to deal with a SQLite database yet lets say I put the database in the folder Resource. And if I make a EXE package that will run on another computer that string path is by my best guess is not going to work
In the process of leaning I keep seeing this line of code. I see no path to the database
m_dbConnection = New SQLiteConnection("Data Source=MyDatabase.sqlite; Version=3;")
Granted I am dealing with a txt file now but if it was a SQLite database file
My Question is how does the connection know where the database is ?
I also need to import this reference Imports System.IO
Coming from NetBeans I got spoiled with Auto Import
Second Question Does VS 2019 not have an Auto Import feature?
I am adding a screen shot of Solution Explore
Tried to add Resource folder to Resources that did not work real well
Stream Reader Code below without error
Private Sub btnRead_Click(sender As Object, e As EventArgs) Handles btnRead.Click
readDATA()
End Sub
Private Sub readDATA()
Dim line As String
Using reader As New StreamReader(path & "Check.txt", True)
line = reader.ReadToEnd.Trim
tbHaveOne.Text = line
End Using
End Sub
Code that creates Check.txt
Private Sub frmThree_Load(sender As Object, e As EventArgs) Handles MyBase.Load
haveFILE()
'tbHaveTwo.Text = frmOne.vR'KEEP see frmOne
'tbHaveOne.Select()
End Sub
Public Sub haveFILE()
'If My.Computer.FileSystem.FileExists(path & "Check.txt") Then
' MsgBox("File found.")
'Else
' MsgBox("File not found.")
'End If
If Not My.Computer.FileSystem.FileExists(path & "Check.txt") Then
' Create or overwrite the file.
Dim fs As FileStream = File.Create(path & "Check.txt")
fs.Close()
tbHaveTwo.Text = "File Created"
tbHaveOne.Select()
Else
tbHaveTwo.Text = "File Found"
tbHaveOne.Select()
End If
End Sub
You should pretty much never be hard-coding absolute paths. If you want to refer to a path under the program folder then you use Application.StartupPath as the root and a relative path, e.g.
Dim filePath = Path.Combine(Application.StartupPath, "Resource\Check.txt")
Then it doesn't matter where you run your program from. For other standard folder paths, you should use Environment.GetFolderPath or My.Computer.FileSystem.SpecialDirectories. For non-standard paths, you should let the user choose with a FolderBrowserDialog, OpenFileDialog or SaveFileDialog and then, if appropriate, save that path to a setting or the like.
When it comes to database connection strings, some ADO.NET providers support the use of "|DataDirectory|" in the path of a data file and that gets replaced at run time. What it gets replaced with depends on the type of app and how it was deployed. For Web Forms apps, it resolves to the App_Data folder. For ClickOnce Windows apps it resolves to a dedicated data folder. For other Windows apps, it resolves to the program folder, just like Application.StartupPath. I think the SQLite provider supports it but I'm not 100% sure. If it does, you could use something like this:
m_dbConnection = New SQLiteConnection("Data Source=|DataDirectory|\Resource\MyDatabase.sqlite; Version=3;")
EDIT:
If you add data files to your project in the Solution Explorer and you want those to be part of the deployed application then you need to configure them to make that happen. Select the file in the Solution Explorer and then set the Build Action to Content and the Copy to Output Directory property to Copy Always or, if you intend to make changes to the file when the app is running, Copy if Newer.
When you build, that file will then be copied from your project source folder to the output folder along with the EXE. You can then access it using Application.StartupPath at run time. That means while debugging as well as after deployment, because it will be copied to the "\bin\Release" output folder as well as the "\bin\Debug" output folder. If you add the file to a folder in the Solution Explorer, that file will be copied to, hence the reason I said earlier to use this:
Dim filePath = Path.Combine(Application.StartupPath, "Resource\Check.txt")
Here is the working code to Create a Text file if it does not exist and if it does exist the user is notified.
We also were able to Write & Read from the Text file
One of the disappointments is we were not able to use StreamReader
We did solve this error where the file name was created like this "Check.txtCheck.txt This line of code below created the File this way in the folder Bin > Debug
If Not My.Computer.FileSystem.FileExists(filePath & "Check.txt") Then See Code for correct format
One other BIG lesson Do NOT create a folder and place your Text file in that folder
I am not sure using the code "Using" was a good idea further research needed on that issue
Working Code Below
Private Sub frmThree_Load(sender As Object, e As EventArgs) Handles MyBase.Load
haveFILE()
End Sub
Public Sub haveFILE()
If Not System.IO.File.Exists(filePath) Then
System.IO.File.Create(filePath).Dispose()
tbHaveTwo.Text = "File Created"
tbHaveOne.Select()
Else
My.Computer.FileSystem.FileExists(filePath) ' Then
tbHaveTwo.Text = "File Found"
tbHaveOne.Select()
End If
'This line of code created the File this was in the Bin > Debug folder Check.txtCheck.txt
'If Not My.Computer.FileSystem.FileExists(filePath & "Check.txt") Then
End Sub
Sub PlaySystemSound()
My.Computer.Audio.PlaySystemSound(
System.Media.SystemSounds.Hand)
End Sub
Private Sub btnWrite_Click(sender As Object, e As EventArgs) Handles btnWrite.Click
If tbHaveOne.Text = "" Then
PlaySystemSound()
'MsgBox("Please enter a username.", vbOKOnly, "Required Data")
'If MsgBoxResult.Ok Then
' Return
'End If
Const Title As String = "To EXIT Click OK"
Const Style = vbQuestion
Const Msg As String = "Enter Data" + vbCrLf + vbNewLine + "Then Write Data"
Dim result = MsgBox(Msg, Style, Title)
If result = vbOK Then
'MsgBox("Enter Data")
tbHaveOne.Select()
Return
End If
End If
writeDATA()
End Sub
Private Sub writeDATA()
Dim file As System.IO.StreamWriter
file = My.Computer.FileSystem.OpenTextFileWriter(filePath, True)
file.WriteLine(tbHaveOne.Text)
file.Close()
tbHaveOne.Clear()
tbHaveTwo.Text = "Data Written"
End Sub
Private Sub btnRead_Click(sender As Object, e As EventArgs) Handles btnRead.Click
readDATA()
End Sub
Public Sub readDATA()
Dim fileReader As String
fileReader = My.Computer.FileSystem.ReadAllText(filePath)
tbHaveOne.Text = fileReader
End Sub

Can open and read from file but not then resave to same file

I am using vb.NET and windows forms.
I have a simple form with a list box and two buttons.
btnLoadData opens up an OpenFileDialog and allows me to choose the text file to open, this is then read into the list box.
I can then delete items from the list box.
btnSaveList opens up a SaveFileDialog and allows me to choose a file to save to.
The problem occurs when I try to save to the same file that I read in.
It tells me that the file cannot be accessed as it is in use. It works if I choose a new file name.
I have searched and tried a number of different suggestions. I have altered the code a number of times and have finally decided I need to ask for help!
The code for the two buttons is below.
Private Sub btnLoadData_Click(sender As Object, e As EventArgs) Handles btnLoadData.Click
Dim openFD As New OpenFileDialog()
openFD.Filter = "Text [*.txt*]|*.txt|CSV [*.csv]|*.csv|All Files [*.*]|*.*"
openFD.ShowDialog()
openFD.OpenFile()
Dim objReader As New StreamReader(openFD.SafeFileName)
While objReader.Peek <> -1
lstList.Items.Add(objReader.ReadLine)
End While
objReader.Close()
End Sub
Private Sub btnSaveList_Click(sender As Object, e As EventArgs) Handles btnSaveList.Click
Dim saveFD As New SaveFileDialog()
If saveFD.ShowDialog = Windows.Forms.DialogResult.OK Then
Using objWriter As New StreamWriter(saveFD.FileName) 'Throws the exception here
For Each line In lstList.Items
objWriter.WriteLine(line)
Next
End Using
End If
End Sub
Private Sub lstList_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lstList.SelectedIndexChanged
lstList.Items.Remove(lstList.SelectedItem)
End Sub
Thank you.
You create two streams but only closing one at the end of reading the file. The OpenFile() method of the OpenFileDialog is creating a stream you doesn't close at the end so it stays open and locks the file. In your case you are using your own stream so you don't need the method OpenFile().
code for button #1 (read the file):
openFD.Filter = "Text [*.txt*]|*.txt|CSV [*.csv]|*.csv|All Files [*.*]|*.*"
openFD.ShowDialog()
'openFD.OpenFile()
Using objReader As New StreamReader(openFD.FileName)
While objReader.Peek <> -1
lstList.Items.Add(objReader.ReadLine)
End While
End Using
code for button #2 (write the file):
Dim saveFD As New SaveFileDialog()
If saveFD.ShowDialog = Windows.Forms.DialogResult.OK Then
Using objWriter As New StreamWriter(saveFD.FileName)
For Each line In lstList.Items
objWriter.WriteLine(line)
Next
End Using
End If
Opening a file for read will lock the file against writes and deletes; opening a file for write will lock against reads, writes and deletes.
You can override those locks but trying to both read and write a file at the same time creates its own set of problems.
There are two approaches to avoid this:
Read the whole file in and close before processing and writing. Of course the whole content has to be in memory.
Write to a temporary file, after closing the input and finishing writing delete the original file and rename the temporary file. This will not preserve attributes (eg. ownership, ACL) without extra steps.
However in your case I suspect you need to use a using block to ensure the file is closed after the read rather than depending on the GC to close it at some point in the future.

Location to save custom settings text file?

I have a VB.Net program that has a few custom settings that are saved in a text file. Right now the file is saved in "settings.txt" which saves in the bin folder. The problem is that this program gets published to my network so my coworkers can use it, and every time I roll out a new update their settings they've saved get deleted; it overwrites the file with a blank version of it. Is there another location that would be better for me to save the file? or is there a way (maybe through code?) to prevent the contents for each of my coworkers from getting deleted every time I publish an update?
Public Class Program
'global variables
Dim fileName As String = "settings.txt"
Private Sub Program_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'code
Try
If File.Exists(fileName) = False Then
File.Create(fileName)
End If
' Open the file using a stream reader.
Using sr As New StreamReader(fileName)
Dim line As String
While (sr.EndOfStream = False)
line = sr.ReadLine()
End While
End Using
Catch ex As Exception
MsgBox(ex.ToString())
End Try
'rest of program
End Sub
End Class
If this is a ClickOnce app, try this:
Friend fileName As String = String.Empty
With My.Application.Info
fileName = IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), .CompanyName, .ProductName, .Version.ToString, "Settings.txt")
End With

VB.net program hangs when asked to read .txt

I am attempting to read a .txt file that I successfully wrote with a separate program, but I keep getting the program stalling (aka no input/output at all, like it had an infinite loop or something). I get the message "A", but no others.
I've seen a lot of threads on sites like this one that list all sorts of creative ways to read from a file, but every guide I have found wants me to change the code between Msgbox A and Msgbox D. None of them change the result, so I'm beginning to think that the issue is actually with how I'm pointing out the file's location. There was one code (had something to do with Dim objReader As New System.IO.TextReader(FileLoc)), but when I asked for a read of the file I got the file's address instead. That's why I suspect I'm pointing to the .txt wrong. There is one issue...
I have absolutely no idea how to do this, if what I've done is wrong.
I've attached at the end the snippet of code (with every single line of extraneous data ripped out of it).
If it matters, the location of the actual program is in the "G01-Cartography" folder.
Private Sub GameMain_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
LoadMap("Map_Cygnus.txt")
End Sub
Private Sub LoadMap(FileLoc As String)
FileLoc = "C:\Users\Adam\Documents\Visual Studio 2013\Projects\G01-Cartography\Maps\" + FileLoc
MsgBox("A")
Using File As New StreamReader(FileLoc)
MsgBox("B")
Dim WholeMap = File.ReadLine()
MsgBox("C")
End Using
MsgBox("D")
End Sub
What does running this show you in the debugger? Can you open the Map_Cygnus.txt file in Notepad? Set a breakpoint on the first line and run the program to see what is going on.
Private BaseDirectory As String = "C:\Users\Adam\Documents\Visual Studio 2013\Projects\G01-Cartography\Maps\"
Private Sub GameMain_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim WholeMap = File.ReadAllText(Path.Combine(BaseDirectory, "Map_Cygnus.txt"))
Debug.Print("Size Of Map: {0}", WholeMap.Length)
End Sub
It looks like you're using the correct methods/objects according to MSDN.
Your code runs for me in an new VB console app(.net 4.5)
A different approach then MSGBOXs would be to use Debug.WriteLine or Console.WriteLine.
If MSGBOX A shows but not B, then the problem is in constructing the stream reader.
Probably you are watching the application for output but the debugger(visual studio) has stopped the application on that line, with an exception. eg File not found, No Permission, using a http uri...
If MSGBOX C doesn't show then problem is probably that the file has problems being read.
Permissions?
Does it have a Line of Text?
Is the folder 'online'
If MSGBOX D shows, but nothing happens then you are doing nothing with WholeMap
See what is displayed if you rewite MsgBox("C") to Debug.WriteLine("Read " + WholeMap)
I have a few suggestions. Firstly, use Option Strict On, it will help you to avoid headaches down the road.
The code to open the file is correct. In addition to avoiding using MsgBox() to debug and instead setting breakpoints or using Debug.WriteLine(), wrap the subroutine in a Try...Catch exception.
Private Sub GameMain_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
LoadMap("Map_Cygnus.txt")
End Sub
Private Sub LoadMap(FileLoc As String)
Try
FileLoc = "C:\Users\Adam\Documents\Visual Studio 2013\Projects\G01-Cartography\Maps\" + FileLoc
MsgBox("A")
Using File As New StreamReader(FileLoc)
MsgBox("B")
Dim WholeMap = File.ReadLine() 'dimming a variable inside a block like this means the variable only has scope while inside the block
MsgBox("C")
End Using
MsgBox("D")
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Note that you normally should only catch whatever exceptions you expect, but I generally catch everything while debugging things like this.
I would also like to point out that you are only reading one line out of the file into the variable WholeMap. That variable loses scope as soon as the End Using line is hit, thereby losing the line you just read from the file. I'm assuming that you have the code in this way because it seems to be giving you trouble reading from it, but thought I would point it out anyway.
Public Class GameMain
Private WholeMap As String = ""
Private Sub GameMain_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
LoadMap("Map_Cygnus.txt")
End Sub
Private Sub LoadMap(FileLoc As String)
Try
FileLoc = "C:\Users\Adam\Documents\Visual Studio 2013\Projects\G01-Cartography\Maps\" + FileLoc
Using File As New StreamReader(FileLoc)
WholeMap = File.ReadLine() 'dimming the variable above will give all of your subs inside class Form1 access to the contents of it (note that I've removed the Dim command here)
End Using
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
End Class