Can open and read from file but not then resave to same file - vb.net

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.

Related

text file im trying to overwrite is being used by another process, but it is not in use?

im trying to overwrite a text file saved on an external drive using an openfile dialog in vb.net winforms, and i keep getting the error:
System.IO.IOException: 'The process cannot access the file 'F:\SETTINGS.TXT' because it is being used by another process.' after clicking the save button, i get the error.
here is my code:
` Public Sub SaveButton_Click(sender As Object, e As EventArgs) Handles SaveButton.Click
Dim myStream As Stream
Dim FileSaveLocation As String
Dim openFileDialog1 As New OpenFileDialog()
openFileDialog1.Filter = "txt files (*.txt)|*.txt"
openFileDialog1.FilterIndex = 2
If openFileDialog1.ShowDialog() = DialogResult.OK Then
myStream = openFileDialog1.OpenFile()
FileSaveLocation = openFileDialog1.FileName
MessageBox.Show(FileSaveLocation)
If (myStream IsNot Nothing) Then
Dim file As System.IO.StreamWriter
IO.File.WriteAllText(FileSaveLocation, "SETTINGS.txt")
file.WriteLine("list of variables and text go here, hidden for privacy" ,True)
File.Close()
End If
End If
End Sub`
ive been switching around the code and slowly making my way through different issues and errors, i thought maybe it has a strange error with the messagebox but removing that makes no difference, but im really stumped on this one, can anyone help? thanks a tonne in advance, its hurting my brain XD
You're opening the file...
myStream = openFileDialog1.OpenFile()
... and then calling WriteAllText which tries to open the file as well...
IO.File.WriteAllText(FileSaveLocation, "SETTINGS.txt")
If you truly do need to open the file to evaluate some condition before you write then you'll need to be sure to close myStream before the call to WriteAllText

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

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

How to open a specific file without user selection?

I currently have the following code which allows a user to select a file:
Private Sub FileToolStripMenuItem1_Click(sender As Object, e As EventArgs) Handles FileToolStripMenuItem1.Click
Dim result As DialogResult
Using filechooser As New OpenFileDialog()
result = filechooser.ShowDialog()
playFile = filechooser.FileName
End Using
End Sub
What I am trying to do is have the program open a file on its own without user selection. Basically, i have a generic file that needs to be used for the application regardless of who is using it, and I want it to be uploaded automatically upon the application being started.
You could just simply point your PlayFile directly by specifying the file
playFile = "C:\yourfile.txt" 'point to your file here

Delaying the use of code while a file is created?

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.