1

I have an array which holds usernames. This is what it looks like:

dim numberofaccounts as integer
dim username(numberofaccounts) as string

I want to store this data somewhere so when I reopen it it will have all the information already there. I have tired using "My.Settings.usernames" but it can't hold arrays.

I was thinking that it might be possible to use a word document to save this information. I know how to write it and how to read the information on the word doc but it comes out as one piece of information e.g. David, Dan, Fred,. not as 3 bits of information.

There will be about 100 accounts

Nathan
  • 41
  • 5

2 Answers2

3

As Plutonix mentioned there is a special type of string array that can be used with My.Settings. It's called a StringCollection.

See here.

After going to project properties and adding a new setting of type StringCollection (leave the value blank).

In your code you can create and access the values as follows:

My.Settings.UserNames = New Specialized.StringCollection()
My.Settings.UserNames.Add("User 1")
My.Settings.Save()

As others have mentioned, this may not be a great way to store usernames especially if the number of users is large.

Drarig29
  • 1,902
  • 1
  • 19
  • 42
Alexander Van Atta
  • 870
  • 11
  • 34
1

Using My.Settings in this instance is not the best solution. While yes, .NET will take care of saving the data and loading it for you, the data in My.Settings is volatile. If your application compiles as ManagedCode (which most all .NET code does), the My.Settings items are tied to the Assembly version of the application. If you change the version of your assembly, you will lose the data stored in My.Settings as the .NET code will look at your assembly as a completely new application. Further more, if the .exe file is moved and executed from a different path, the settings will also be lost as .NET will look at the application and a completely different instance.

The better option would be to save the data yourself. You can do this by serializing an object and saving it to a file. When you deserialize the file, the return will be the exact same object that was saved. I would suggest creating a class that is a wrapper for the array or even better a List(Of String). Here is a sample Console application to use as a reference:

' Always, always, always use these (unless you have a few edge cases, usually reflection)
Option Strict On
Option Explicit On

' Makes for shorter code
Imports System.Runtime

Module Module1
    Sub Main()
        ' File path to save the file, hardcoded here just for an example
        Dim filePath As String = "C:\StackOverflow\usernames.dat"
        ' Set it to Nothing to prove that the below methods work, if they don't you'll get an NRE
        Dim userNames As UsernameWrapper = Nothing

        Console.Write("do you want to read from the file or write to a file? [r / w] ")
        If Console.ReadKey.Key = ConsoleKey.W Then
            Console.WriteLine() : Console.WriteLine("Enter three usernames:")
            ' Create the object that we want to save
            userNames = New UsernameWrapper({Console.ReadLine, Console.ReadLine, Console.ReadLine})
            'Save the object to a file
            userNames.SaveToFile(filePath)
        Else
            ' Get the object from the file
            userNames = UsernameWrapper.ReadFromFile(filePath)
            Console.WriteLine() : Console.WriteLine("Saved usernames loaded from file:")
            ' Output the contents
            userNames.UserNames.ForEach(Sub(x) Console.Write(x & " ")) : Console.WriteLine()
        End If


        Console.WriteLine()
        Console.Write("Run Again? [y / n] ")
        If Console.ReadKey.Key = ConsoleKey.Y Then
            Console.WriteLine() : Console.WriteLine()
            ' Set it to nothing to prove that the above methods are working,
            ' if they didn't work you'd get a NRE on next run
            userNames = Nothing
            ' Call Main() again for a new run
            Main()
        End If

    End Sub

End Module


' This is the key to the whole thing, this attribute is what allows the object to be serialized
<Serializable()>
Public Class UsernameWrapper
    Public Property UserNames As List(Of String)

    ' Just a few ways of instantiating the object
    Public Sub New()
        Me.UserNames = New List(Of String)
    End Sub
    Public Sub New(ByVal usernameArray() As String)
        Me.UserNames = usernameArray.ToList()
    End Sub

    Public Sub New(ByVal userNameList As List(Of String))
        Me.UserNames = userNameList
    End Sub

    ''' <summary>
    ''' Save the current object to a file
    ''' </summary>
    ''' <param name="filePath">Path to save the file to</param>
    ''' <remarks>http://stackoverflow.com/users/2659234</remarks>
    Public Sub SaveToFile(ByVal filePath As String)
        ' Create the formatter that will do the serialization
        Dim formatter As Serialization.IFormatter = New Serialization.Formatters.Binary.BinaryFormatter()
        Using fs As New IO.FileStream(filePath, IO.FileMode.Create, IO.FileAccess.Write)
            ' Serialize the data
            formatter.Serialize(fs, Me)
        End Using
    End Sub

    ''' <summary>
    ''' Load object from file
    ''' </summary>
    ''' <param name="filePath">Path of the file to read from</param>
    ''' <returns>The deseerailized object</returns>
    ''' <remarks>http://stackoverflow.com/users/2659234</remarks>
    Public Shared Function ReadFromFile(ByVal filePath As String) As UsernameWrapper
        ' Create the formatter that will do the serialization
        Dim formatter As Serialization.IFormatter = New Serialization.Formatters.Binary.BinaryFormatter()
        ' The deserialized object will be saved to this
        Dim _usernameWrapper As UsernameWrapper = Nothing

        Using fs As New IO.FileStream(filePath, IO.FileMode.Open, IO.FileAccess.Read)
            ' Deserialize the object and cast it to the correct type
            _usernameWrapper = TryCast(formatter.Deserialize(fs), UsernameWrapper)
        End Using

        ' If the deserializing failed, throw an error
        If IsNothing(_usernameWrapper) Then Throw New Runtime.Serialization.SerializationException(String.Format("Could not deserialize {0}.", filePath))

        Return _usernameWrapper
    End Function
End Class
  • `If you change the version of your assembly, you will lose the data stored` That is not true. Use the Upgrade and/or GetPreviousVersion() methods. They do get lost if the user does something like move the app or installs the new version to a different folder. [I've never liked MySettings](http://stackoverflow.com/a/25014480/1070452) and avoid it for a number of reasons. – Ňɏssa Pøngjǣrdenlarp Oct 29 '15 at 16:33