I am implementing a Save File button in my VB.NET Windows Forms application.
I am attempting to encapsulate the normally expected behaviour of Save buttons in Windows applications. I.E: If a file was already selected then open the current file it, write to it and save it; else if there is no current file, or Save As was used, then show a SaveFileDialog, then open, write and save just the same.
I currently have coded the function below but I keep getting an exception:
Cannot access a closed file
The file is created just fine, but is empty (It should contain "Test string"). I can't understand how the file is closed unless some kind of garbage collection is doing away with it somehow??
The current code:
Function SaveFile(ByVal Type As ProfileType, ByVal suggestedFileName As String, ByVal saveAs As Boolean, ByVal writeData As String) As Boolean
Dim FileStream As Stream = Nothing
Dim FolderPath As String = Nothing
Dim CancelSave As Boolean = False
Dim SaveFileDialog As SaveFileDialog = New SaveFileDialog()
Try
If Type = ProfileType.Product Then 'Select the initial directory path
FolderPath = ProductPath
Else
FolderPath = ProfilePath
End If
If (FileName = String.Empty Or saveAs = True) Then 'If a file is not already selected launch a dialog to allow the user to select one
With SaveFileDialog
.Title = "Save"
.AddExtension = True
.CheckPathExists = True
.CreatePrompt = False
.DefaultExt = "xml"
.Filter = "Xml Files (*.xml)|*.xml"
.FilterIndex = 0
.FileName = suggestedFileName
.InitialDirectory = FolderPath
If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
FullyQualfiedPathName = New String(SaveFileDialog.FileName) 'Save the path and name of the file
FileName = Path.GetFileName(FullyQualfiedPathName)
Else
CancelSave = True
End If
.Dispose()
End With
End If
If (FileName <> String.Empty) Then 'Write the string to the file if the filewas correctly selected
FileStream = File.Open(FullyQualfiedPathName, FileMode.OpenOrCreate, FileAccess.ReadWrite) 'Open the file
Using FileStreamWriter As New StreamWriter(FileStream) 'Create the stream writer
FileStreamWriter.Write(writeData) 'Write the data
FileStream.Close() 'Clse the file
End Using
ElseIf (CancelSave <> True) Then 'Only throw an exception if the user *didn't* cancel the SavefileDialog
Throw New Exception("File stream was nothing", New IOException())
End If
Catch ex As Exception
MessageBox.Show(ex.Message & Environment.NewLine & FullyQualfiedPathName)
End Try
Return True
End Function
One problem I see is that you should be putting your File.Open in a Using block:
Using fs = File.Open(fullyQualfiedPathName, FileMode.OpenOrCreate, FileAccess.ReadWrite)
Using writer As New StreamWriter(fs) 'Create the stream writer
writer.Write(writeData) 'Write the data
'fs.Close() <--- you do not need this line becuase the "Using" block will take care of this for you.
End Using
End Using
I'm not sure if this will resolve your issue because I can't run your code, but the Using block will automatically take care of closing and cleaning up disposable instances like FileStream and StreamWriter, even if an exception is thrown.
By the way, you should use proper naming conventions (lower camel case) for local variables.
Related
I have a vb.net windows app that creates a PDF. After creation, I want to prompt the user where they want to save the file. The default save folder is different than the folder of the created PDF. I get the SaveDialog box to come up with the default folder and file name that I want. If I choose "Save", I get a message saying that the file does not exist and none of the code below the ShowDialog is executed (I'm sure that I'm doing that part wrong as well).
Dim saveFileDialog1 As New SaveFileDialog
saveFileDialog1.InitialDirectory = MyDocsFolder
saveFileDialog1.FileName = "Report.pdf"
saveFileDialog1.Title = "Save Report"
saveFileDialog1.CheckFileExists = True
saveFileDialog1.CheckPathExists = True
saveFileDialog1.DefaultExt = "pdf"
saveFileDialog1.Filter = "All files (*.*)|*.*|All files (*.*)|*.*"
saveFileDialog1.FilterIndex = 2
saveFileDialog1.RestoreDirectory = True
saveFileDialog1.ShowDialog()
If saveFileDialog1.ShowDialog = DialogResult.OK Then
If saveFileDialog1.FileName() <> "" Then
Dim newStream As FileStream = File.Open(newFile, FileMode.Open)
Dim pdfStream As New FileStream(saveFileDialog1.FileName, FileMode.Create)
newStream.CopyTo(fs, FileMode.Append)
newStream.Close()
fs.Close()
End If
End If
you can do it like this:
Imports Microsoft.WindowsAPICodePack.Dialogs
Public NotInheritable Class Form1
Private Sub ButtonSave_Click(sender As Object, e As EventArgs) Handles ButtonSave.Click
Dim Path As String
Using SFD1 As New CommonSaveFileDialog
SFD1.Title = "Where should the file be saved?"
SFD1.Filters.Add(New CommonFileDialogFilter("PDF", ".pdf"))
SFD1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
If SFD1.ShowDialog() = CommonFileDialogResult.Ok Then
Path = SFD1.FileName
Else
Return
End If
End Using
Dim dest As IO.FileInfo
Using fs As IO.FileStream = IO.File.Create(Path & ".pdf")
dest = My.Computer.FileSystem.GetFileInfo(fs.Name)
End Using
End Sub
End Class
Please note that I am using a FileDialog that I downloaded from Visual Studios' own Nuget Package Manager. See image. You don't have to do that, but I prefer this FileDialog because it offers more options than the one that is already included.
So the user enters the file name; thus the path results. In my code example, this creates a blank PDF. It cannot be opened like this yet.
So that something is written in the PDF, you can download itext7 (also via NuGet).
Then, you write Imports iText.Kernel.Pdf,
Imports iText.Kernel.Utils and in your sub Dim pdfwriter As New PdfWriter(dest) with ‘dest’ from above.
I am so blind and stupid...
saveFileDialog1.CheckFileExists = True
Sorry for wasting anyone's time.
I create a plugin for MS Word by VSTO VB.NET
I Wrote the function to copy two files to the AppData folder from Resources.
The code works fine and copy files, but create the Additional files (file size is 0) in MyDocumnet and my doc file location.
How can I fix it?
Public Function openFile(fName As String) As String
Dim path, fileName As String
Dim bytes, p
' Dim FileLocked As Boolean
p = Environment.GetEnvironmentVariable("APPDATA") & "\"
Select Case fName
Case "q"
bytes = My.Resources.qText
fileName = "qText.docx"
path = p & fileName
Case "t"
bytes = My.Resources.tText
fileName = "tText.docx"
path = p & fileName
End Select
Dim Locked As Boolean = False
Try
Dim fs As FileStream = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)
fs.Close()
Catch
Locked = True
End Try
Try
If Locked Then
Return fileName
Else
File.WriteAllBytes(path, bytes)
If fileName = "QText.docx" Then
SourceApp.Documents.Open(FileName:=path, ReadOnly:=True, Visible:=False)
Else
SourceApp.Documents.Open(FileName:=path, Visible:=False)
SourceApp.Documents("tText.docx").Content.Delete()
End If
SourceApp.ScreenUpdating = False
SourceApp.DisplayStatusBar = False
Call ComMode()
Return fileName
End If
Catch ex As Exception
End Try
End Function
When you check whether a particular file exists/locked on the disk a relative path is used. Only the filename is passed which means the relative path:
Dim fs As FileStream = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)
fs.Close()
But when you write the content the absolute path is specified in the code:
File.WriteAllBytes(path, bytes)
The path can point to another place. I'd suggest using the Directory.GetCurrentDirectory method which gets the current working directory of the application. If required you may set the current directory using the Environment.CurrentDirectory property sets the fully qualified path of the current working directory.
Shouldn't this:
Dim fs As FileStream = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)
actually be this:
Dim fs As FileStream = File.Open(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)
As it stands, you're specifying only a file name rather than a file path, so the folder path has to be assumed to be some default, which is presumably where you're seeing those files created.
This is an example of why descriptive variable names are important. Personally, I would have used folderPath, fileName and filePath rather than p, fileName and path. It's far more obvious what each one is then.
What's the point of creating a file anyway? Why not check whether one exists first and then only try to open it if it does? You appear to be checking whether the file is locked but it obviously can't be locked if it doesn't exist.
in my VB.net Application id like to overwrite and add new content of a text file
What Code do I need to use?
Thanks
Read (ie: load) everything in the TXT file into your program.
Dim sFullPathToFile As String = Application.StartupPath & "\Sample.txt"
Dim sAllText As String = ""
Using xStreamReader As StreamReader = New StreamReader(sFullPathToFile)
sAllText = xStreamReader.ReadToEnd
End Using
Dim arNames As String() = Split(sAllText, vbCrLf)
'Just for fun, display the found entries in a ListBox
For iNum As Integer = 0 To UBound(arNames)
If arNames(iNum) > "" Then lstPeople.Items.Add(arNames(iNum))
Next iNum
Because you wanted to overwrite everything in the file, we now use StreamWriter (not a StreamReader like before).
'Use the True to indicate it is to be appended to existing file
'Or use False to open the file in Overwrite mode
Dim xStreamWRITER As StreamWriter = New StreamWriter(sFullPathToFile, False)
'Use the carriage return character or else each entry is on the same line
xStreamWRITER.Write("I have overwritten everything!" & vbCrLf)
xStreamWRITER.Close()
I've been searching around for a solution to this problem to no avail. I've got a small VB.net program that allows the user to change the autocomplete source file for the textboxes on the form. If there's no autocomplete file selected on load, the program makes you select one.
If a new file is selected when there's already an autocomplete file, then the textboxes will use suggestions from both until the program is restarted, where it'll start only using the newly selected file. Is there any way to prevent this behaviour?
Here's the code for selecting the file:
Dim fd As OpenFileDialog = New OpenFileDialog()
fd.Title = "Select a file..."
fd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
fd.Filter = "Text files (*.txt)|*.txt"
fd.RestoreDirectory = True
If fd.ShowDialog() = DialogResult.OK Then
My.Settings.streamerFileLocation = fd.FileName
Call Form1_Load(Me, e)
stream1Textbox.Text = ""
stream2Textbox.Text = ""
stream3Textbox.Text = ""
stream4Textbox.Text = ""
End If
And the releveannt part of the Form1_Load sub that it calls:
Using reader As New System.IO.StreamReader(My.Settings.streamerFileLocation)
While Not reader.EndOfStream
autocompleteList.Add(reader.ReadLine())
End While
End Using
stream1Textbox.AutoCompleteCustomSource = autocompleteList
stream2Textbox.AutoCompleteCustomSource = autocompleteList
stream3Textbox.AutoCompleteCustomSource = autocompleteList
stream4Textbox.AutoCompleteCustomSource = autocompleteList
A friend helped me figure it out - the program was still hanging on to the old entries between file changes for whatever reason. Added in autocompleteList.Clear() before the While loop:
Using reader As New System.IO.StreamReader(My.Settings.streamerFileLocation)
autocompleteList.Clear() // THIS LINE
While Not reader.EndOfStream
autocompleteList.Add(reader.ReadLine())
End While
End Using
And hey presto, no more old auto-complete suggestions.
I started making a file manager which scans a folder selected by user through folderbrowserdialog in vb.net, extract the extentions of every file in every directory or subdirectory using GetFiles() Method with SearchOption.AllDirectories. I am having an UnauthorizedAccessException when it scans the Recycle Bin Folder in logical drive whereas i have seen Softwares like WinRar or R-Studio Scanning and showing every directory without having an exception or error. Following is my code:
Public Sub WriteExtentionsToFile()
Try
Title_Window.FolderBrowserDialog.ShowDialog()
Dim Path As String = Title_Window.FolderBrowserDialog.SelectedPath
'Getting FilesNames
Dim FileNames As String() = GetFilesNames(Path)
Title_Window.LblStatusBar.Text = "File Names Saved"
Dim MaximumForProgressBar As Integer = FileNames.Length
Title_Window.ToolStripProgressBar1.Maximum = MaximumForProgressBar
Title_Window.ToolStripProgressBar1.Step = 1
'Getting Extentions
Dim ExtentionsList As New List(Of String)
For Each item In FileNames
ExtentionsList.Add(System.IO.Path.GetExtension(item))
Next
'Deleting Duplicate Extentions
Dim NoDuplicateExtentionList As New List(Of String)
Dim ExtentionReadFromFile As String() = ReadExtentionsFromFile()'Another Function in my Class Which Reads previously saved extentions in a file and store them in an array
For Each item In ExtentionReadFromFile
NoDuplicateExtentionList.Add(item)
Next
For Each E In ExtentionsList
Dim LastIndexOfDot As Integer = E.LastIndexOf(".")
E = E.Remove(0, LastIndexOfDot + 1)
If NoDuplicateExtentionList.Contains(E.ToLower) = False Then
NoDuplicateExtentionList.Add(E.ToLower)
My.Computer.FileSystem.WriteAllText("d:\ExtentionsList.txt", E.ToString & vbCrLf, True)
End If
Next
MessageBox.Show("Writing Process Completed", "Success")
Catch ex As UnauthorizedAccessException
Dim Buttons As MessageBoxButtons = MessageBoxButtons.AbortRetryIgnore
Dim result As DialogResult
MessageBox.Show(ex.ToString, "Access Denied", Buttons)
If result = Windows.Forms.DialogResult.Ignore Then
'What should be Done Here????
ElseIf result = Windows.Forms.DialogResult.Abort Then
'What should be Done Here????
Else
'What should be Done Here????
End If
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
End Sub
What should be the solution for thsi problem? Is this about getting the permissions through FileIoPermission Class or something else??