如何保存数组?
How do I save an array?
我有一个包含用户名的数组。这是它的样子:
dim numberofaccounts as integer
dim username(numberofaccounts) as string
我想将这些数据存储在某个地方,这样当我重新打开它时,所有信息都已经存在了。我已经厌倦了使用 "My.Settings.usernames" 但它不能容纳数组。
我在想也许可以用word文档来保存这些信息。我知道如何编写它以及如何阅读 doc 一词上的信息,但它作为一条信息出现,例如大卫、丹、弗雷德。不是 3 位信息。
将有大约 100 个帐户
正如 Plutonix 提到的,有一种特殊类型的字符串数组可以与 My.Settings 一起使用。它被称为 StringCollection
.
参见here。
转到项目属性并添加 StringCollection 类型的新设置后(将值留空)。
在您的代码中,您可以按如下方式创建和访问值:
My.Settings.UserNames = New Specialized.StringCollection()
My.Settings.UserNames.Add("User 1")
My.Settings.Save()
正如其他人所提到的,这可能不是存储用户名的好方法,尤其是在用户数量很大的情况下。
在这种情况下使用 My.Settings
不是最佳解决方案。是的,.NET 会负责保存数据并为您加载数据,My.Settings
中的数据是易变的。如果您的应用程序编译为 ManagedCode(大多数 .NET 代码都这样做),则 My.Settings
项与应用程序的程序集版本相关联。如果您更改程序集的版本,您将丢失存储在 My.Settings
中的数据,因为 .NET 代码会将您的程序集视为一个全新的应用程序。此外,如果 .exe
文件从不同的路径移动和执行,设置也将丢失,因为 .NET 将查看应用程序和一个完全不同的实例。
更好的选择是自己保存数据。您可以通过序列化对象并将其保存到文件中来实现。当您反序列化文件时,return 将与保存的对象完全相同。我建议创建一个 class 作为数组的包装器,甚至更好的是 List(Of String)
。这是一个示例控制台应用程序,可用作参考:
' 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:\Whosebug\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://whosebug.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://whosebug.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
我有一个包含用户名的数组。这是它的样子:
dim numberofaccounts as integer
dim username(numberofaccounts) as string
我想将这些数据存储在某个地方,这样当我重新打开它时,所有信息都已经存在了。我已经厌倦了使用 "My.Settings.usernames" 但它不能容纳数组。
我在想也许可以用word文档来保存这些信息。我知道如何编写它以及如何阅读 doc 一词上的信息,但它作为一条信息出现,例如大卫、丹、弗雷德。不是 3 位信息。
将有大约 100 个帐户
正如 Plutonix 提到的,有一种特殊类型的字符串数组可以与 My.Settings 一起使用。它被称为 StringCollection
.
参见here。
转到项目属性并添加 StringCollection 类型的新设置后(将值留空)。
在您的代码中,您可以按如下方式创建和访问值:
My.Settings.UserNames = New Specialized.StringCollection()
My.Settings.UserNames.Add("User 1")
My.Settings.Save()
正如其他人所提到的,这可能不是存储用户名的好方法,尤其是在用户数量很大的情况下。
在这种情况下使用 My.Settings
不是最佳解决方案。是的,.NET 会负责保存数据并为您加载数据,My.Settings
中的数据是易变的。如果您的应用程序编译为 ManagedCode(大多数 .NET 代码都这样做),则 My.Settings
项与应用程序的程序集版本相关联。如果您更改程序集的版本,您将丢失存储在 My.Settings
中的数据,因为 .NET 代码会将您的程序集视为一个全新的应用程序。此外,如果 .exe
文件从不同的路径移动和执行,设置也将丢失,因为 .NET 将查看应用程序和一个完全不同的实例。
更好的选择是自己保存数据。您可以通过序列化对象并将其保存到文件中来实现。当您反序列化文件时,return 将与保存的对象完全相同。我建议创建一个 class 作为数组的包装器,甚至更好的是 List(Of String)
。这是一个示例控制台应用程序,可用作参考:
' 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:\Whosebug\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://whosebug.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://whosebug.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