Deserializing in VB Without Failing When the File Does Not Exist - vb.net

I've nicked some code from msdn to write and read to an xml file to persist my data, but I need a little help with it. I have a dynamic array called darr. As I understand it, I use this code to store it in an xml file:
Dim objStreamWriter As New StreamWriter("C:\temp\test.xml")
Dim x As New XmlSerializer(darr.GetType)
x.Serialize(objStreamWriter, darr)
objStreamWriter.Close()
And this to read it:
Dim objStreamReader As New StreamReader("C:\temp\test.xml")
darr = x.Deserialize(objStreamReader)
objStreamReader.Close()
The thing is, I want the app to read from the file on startup, which means the second block gets called first and if the file doesn't exit yet, it throws an exception. (The first block automatically creates the file if not found.) So two questions:
Is there a way to have the app create the file automatically the first time it runs?
Since the file will be empty... will the code work? If not, is there a workaround? (Okay that's three questions!)

If Not File.Exists("C:\temp\test.xml") Then
' Create the file.
Dim file As System.IO.FileStream
file = System.IO.File.Create("C:\temp\test.xml")
Else
Dim objStreamWriter As New StreamWriter("C:\temp\test.xml")
Dim x As New XmlSerializer(darr.GetType)
x.Serialize(objStreamWriter, darr)
objStreamWriter.Close()
End If

Related

Remove double quotes in the content of text files

I am using a legacy application where all the source code is in vb.net. I am checking if the file exists and if the condition is true replace all the " in the contents of the file. For instance "text" to be replaced as text. I am using the below code.
vb.net
Dim FileFullPath As String
FileFullPath = "\\Fileshare\text\sample.txt"
If File.Exists(FileFullPath) Then
Dim stripquote As String = FileFullPath
stripquote = stripquote.Replace("""", "").Trim()
Else
'
End If
I get no errors and at the same time the " is not being replaced in the content of the file.
Data:
ID, Date, Phone, Comments
1,05/13/2021,"123-000-1234","text1"
2,05/13/2021,"123-000-2345","text2"
3,05/13/2021,"123-000-3456","text2"
Output:
1,05/13/2021,123-000-1234,text1
2,05/13/2021,123-000-2345,text2
3,05/13/2021,123-000-3456,text2
You can read each line of the file, remove the double-quotes, write that to a temporary file, then when all the lines are done delete the original and move/rename the temporary file as the filename:
Imports System.IO
'...
Sub RemoveDoubleQuotes(filename As String)
Dim tmpFilename = Path.GetTempFileName()
Using sr As New StreamReader(filename)
Using sw As New StreamWriter(tmpFilename)
While Not sr.EndOfStream
sw.WriteLine(sr.ReadLine().Replace("""", ""))
End While
End Using
End Using
File.Delete(filename)
File.Move(tmpFilename, filename)
End Sub
Add error handling as desired.
The best way to go about this depends on the potential size of the file. If the file is relatively small then there's no point processing it line by line and certainly not using a TextFieldParser. Just read the data in, process it and write it out:
File.WriteAllText(FileFullPath,
File.ReadAllText(FileFullPath).
Replace(ControlChars.Quote, String.Empty))
Only if the file is potentially large and reading it all in one go would require too much memory should you consider processing it line by line. In that case, I'd go this way:
'Let the system create a temp file.
Dim tempFilePath = Path.GetTempFileName()
'Open the temp file for writing text.
Using tempFile As New StreamWriter(tempFilePath)
'Open the source file and read it line by line.
For Each line In File.ReadLines(FileFullPath)
'Remove double-quotes from the current line and write the result to the temp file.
tempFile.WriteLine(line.Replace(ControlChars.Quote, String.Empty))
Next
End Using
'Overwrite the source file with the temp file.
File.Move(tempFilePath, FileFullPath, True)
Note the use of File.ReadLines rather than File.ReadAllLines. The former will only read one line at a time where the latter reads every line before you can process any of them.
EDIT:
Note that this:
File.Move(tempFilePath, FileFullPath, True)
only works in .NET Core 3.0 and later, including .NET 5.0. If you're targeting .NET Framework then you have three other options:
Delete the original file (File.Delete) and then move the temp file (File.Move).
Copy the temp file (File.Copy) and then delete the temp file (File.Delete).
Call My.Computer.FileSystem.MoveFile to move the temp file and overwrite the original file in one go.
TextFieldParser is probably the way to go.
Your code with a few changes.
Static doubleQ As String = New String(ControlChars.Quote, 2)
Dim FileFullPath As String
FileFullPath = "\\Fileshare\text\sample.txt"
If IO.File.Exists(FileFullPath) Then
Dim stripquote As String = IO.File.ReadAllText(FileFullPath)
stripquote = stripquote.Replace(doubleQ, "").Trim()
Else
'
End If
Note the static declaration. I adopted this approach because it confused the heck out of me.

VB.NET 2010 - Extracting an application resource to the Desktop

I am trying to extract an application resource from My.Resources.FILE
I have discovered how to do this with DLL & EXE files, but I still need help with the code for extracting PNG & ICO files.
Other file types also. (If possible)
Here is my current code that works with DLL & EXE files.
Dim File01 As System.IO.FileStream = New System.IO.FileStream("C:\Users\" + Environment.UserName + "\Desktop\" + "SAMPLE.EXE", IO.FileMode.Create)
File01.Write(My.Resources.SAMPLE, 0, My.Resources.SAMPLE.Length)
File01.Close()
First things first, the code you have is bad. When using My.Resources, every time you use a property, you extract a new copy of the data. That means that your second line is getting the data to write twice, with the second time being only to get its length. At the very least, you should be getting the data only once and assigning it to a variable, then using that variable twice. You should also be using a Using statement to create and destroy the FileStream. Even better though, just call File.WriteAllBytes, which means that you don't have to create your own FileStream or know the length of the data to write. You should also not be constructing the file path that way.
Dim filePath = Path.Combine(My.Computer.FileSystem.SpecialDirectories.Desktop, "SAMPLE.EXE")
File.WriteAllBytes(filePath, My.Resources.SAMPLE)
As for your question, the important thing to understand here is that it really has nothing to do with resources. The question is really how to save data of any particular type and that is something that you can look up for yourself. When you get the value of a property from My.Resources, the type of the data you get will depend on the type of the file you embedded in first place. In the case of a binary file, e.g. DLL or EXE, you will get back a Byte array and so you save that data to a file in the same way as you would any other Byte array. In the case of an image file, e.g. PNG, you will get back an Image object, so you save that like you would any other Image object, e.g.
Dim filePath = Path.Combine(My.Computer.FileSystem.SpecialDirectories.Desktop, "PICTURE.PNG")
Using picture = My.Resources.PICTURE
picture.Save(filePath, picture.RawFormat)
End Using
For an ICO file you will get back an Icon object. I'll leave it to you to research how to save an Icon object to a file.
EDIT:
It's important to identify what the actual problem is that you're trying to solve. You can obviously get an object from My.Resources so that is not the problem. You need to determine what type that object is and determine how to save an object of that type. How to do that will be the same no matter where that object comes from, so the resources part is irrelevant. Think about what it is that you have to do and write a method to do it, then call that method.
In your original case, you could start like this:
Dim data = My.Resources.SAMPLE
Once you have written that - even as you write it - Intellisense will tell you that the data is a Byte array. Your actual problem is now how to save a Byte array to a file, so write a method that does that:
Private Sub SaveToFile(data As Byte(), filePath As String)
'...
End Sub
You can now which you want to do first: write code to call that method as appropriate for your current scenario or write the implementation of the method. There are various specific ways to save binary data, i.e. a Byte array, to a file but, as I said, the simplest is File.WriteAllBytes:
Private Sub SaveToFile(data As Byte(), filePath As String)
File.WriteAllBytes(filePath, data)
End Sub
As for calling the method, you need to data, which you already have, and the file path:
Dim data = My.Resources.SAMPLE
Dim folderPath = My.Computer.FileSystem.SpecialDirectories.Desktop
Dim fileName = "SAMPLE.EXE"
Dim filePath = Path.Combine(folderPath, fileName)
SaveToFile(data, filePath)
Simple enough. You need to follow the same steps for any other resource. If you embedded a PNG file then you would find that the data is an Image object or, more specifically, a Bitmap. Your task is then to learn how to save such an object to a file. It shouldn't take you long to find out that the Image class has its own Save method, so you would use that in your method:
Private Sub SaveToFile(data As Image, filePath As String)
data.Save(filePath, data.RawFormat)
End Sub
The code to call the method is basically as before, with the exception that an image object needs to be disposed when you're done with it:
Dim data = My.Resources.PICTURE
Dim folderPath = My.Computer.FileSystem.SpecialDirectories.Desktop
Dim fileName = "SAMPLE.EXE"
Dim filePath = Path.Combine(folderPath, fileName)
SaveToFile(data, filePath)
data.Dispose()
The proper way to create and dispose an object in a narrow scope like this is with a Using block:
Dim folderPath = My.Computer.FileSystem.SpecialDirectories.Desktop
Dim fileName = "SAMPLE.EXE"
Dim filePath = Path.Combine(folderPath, fileName)
Using data = My.Resources.PICTURE
SaveToFile(data, filePath)
End Using
Now it is up to you to carry out the same steps for an ICO file. If you are a hands on learner then get your hands on.

how to read a CSV file as resource using TextFieldParser

I have a CSV file in my project resources which I want to read using FileIO.TextFieldParser
I tried Dim parser = new TextFieldParser(My.Resources.ArticlesCSV), but since TextFieldParser expects either a path (as string) or a stream, this is not working.
I guess one possibility is to convert the resource to a stream, but I cannot find how to do that...
What is the best way to get this working?
You can create a new instance of IO.StringReader which is of type TextReader that TextFieldParser will accept. Just pass your CSV file (Thanks to AndrewMorton)
Using strReader As New IO.StringReader(My.Resources.ArticlesCSV)
Using textparser As New TextFieldParser(strReader)
textparser.Delimiters = {","}
While Not textparser.EndOfData
Dim curRow = textparser.ReadFields()
' Do stuff
End While
End Using
End Using

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.

Stream Reader and Writer Conflict

I am making a class that is to help with saving some strings to a local text file (I want to append them to that file and not overwrite so that it is a log file). When I write with the streamwriter to find the end of the previous text, I get an error "the file is not available as it is being used by another process". I looked into this problem on MSDN and I got very little help. I tried to eliminate some variables so I removed the streamreader to check was that the problem and it was. When I tried to write to the file then it worked and I got no error so this made me come to the conclusion that the problem arose in the streamreader. But I could not figure out why?
Here is the code:
Public Sub SaveFile(ByVal Task As String, ByVal Difficulty As Integer, ByVal Time_Taken As String)
Dim SW As String = "C:/Program Files/Business Elements/Dashboard System Files/UserWorkEthic.txt"
Dim i As Integer
Dim aryText(3) As String
aryText(0) = Task
aryText(1) = Difficulty
aryText(2) = Time_Taken
Dim objWriter As System.IO.StreamWriter = New System.IO.StreamWriter(SW, True)
Dim reader As System.IO.StreamReader = New System.IO.StreamReader(SW, True)
reader.ReadToEnd()
reader.EndOfStream.ToString()
For i = 0 To 3
objWriter.WriteLine(aryText(reader.EndOfStream + i))
Next
reader.Close()
objWriter.Close()
End Sub
As Joel has commented on the previous answer it is possible to change the type of locking.
Otherwise building on what Neil has suggested, if to try to write to a file with a new reader it is difficult not to lose the information already within the file.
I would suggest you rename the original file to a temporary name, "UserWorkEthicTEMP.txt" for example. Create a new text file with the original name. Now; read a line, write a line, between the two files, before adding your new data onto the end. Finally Delete the temporary file and you will have the new file with the new details. If you have an error the temporary file will serve as a backup of the original. Some sample code below:
Change file names
Dim Line as string
line=Reader.readline
Do until Line=nothing
objwriter.writeline(line)
line=reader.readline
loop
add new values on the end and remove old file
You are trying to read and write to the same file and this is causing a lock contention. Either store the contents of the file into a variable and then write it back out including your new data to the file.
Psuedo
Reader.Open file
String content = Reader.ReadToEnd()
Reader.Close
Writer.Open file
Loop
Writer.Write newContent
Writer.Close