VB 2008调试基于.DAT文件存储的多用户登录密码校验异常
问题根因拆解
你当前遇到的登录校验失效,是文件格式错误和原有代码逻辑缺陷两类问题叠加导致的,具体原因如下:
- 关于.DAT文件解析异常:你使用VB传统的
Input函数读取顺序文本文件,该函数的默认解析规则对字符串字段的格式有严格要求——所有字符串字段必须被成对双引号包裹,遇到首个双引号后开始读取字符串内容,直到匹配到下一个闭合双引号才认为当前字段读取完成。你存储Admin账号的行里,密码字段缺失闭合引号时,Input函数会一直向后寻找闭合双引号,最终把下一行Guest账号的开头引号当成Admin密码的结束标记,直接吞入下一行的用户名内容,导致读到的Admin密码完全失真,自然无法通过校验。而Guest账号的字段引号是完整闭合的,所以读取过程不受影响,能正常通过校验。 - 关于代码逻辑硬伤:你当前用两个全局变量
user_name、pass_word存储读取到的账号信息,循环读取文件时每读一条记录就会覆盖之前的值,循环结束后这两个变量里永远只保留文件最后一条(也就是Guest)的账号信息。哪怕文件格式完全正确,当你选择Admin账号登录时,代码里也没有存储Admin对应的密码,根本无法完成对应校验。
修正方案
第一步:规范.DAT文件存储格式
如果坚持使用原生的FileOpen+Input读取方式,必须保证文件内每个账号的两个字段都带有成对双引号,字段间用逗号分隔,单条账号占一行,正确格式示例:
"Admin","passwordA" "Guest","passwordG"
严禁遗漏任何闭合引号,否则会触发解析错位问题。
第二步:重构代码逻辑,建立账号-密码映射
摒弃用两个全局变量临时存账号的方式,用字典结构存储所有读取到的账号和对应密码,实现按选中账号精准取密码校验:
- 全局替换零散变量的声明:
' 类内全局声明区 ' 存储账号-密码映射 Dim accountDict As New Dictionary(Of String, String)() ' 记录登录尝试次数 Dim attempts As Integer = 0 ' 最大允许尝试次数 Const MAX_ALLOW_ATTEMPTS As Integer = 3 - 修正窗体加载时的文件读取逻辑:
Private Sub login_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load ' 填充账号下拉列表,禁止手动输入非预设账号 cmbUsername.Items.AddRange(New String() {"Admin", "Guest"}) cmbUsername.DropDownStyle = ComboBoxStyle.DropDownList Dim accountFilePath As String = IO.Path.Combine(My.Application.Info.DirectoryPath, "users.DAT") ' 提前判断文件是否存在,避免抛出异常 If Not IO.File.Exists(accountFilePath) Then MsgBox("账号存储文件缺失,请检查配置!") Me.Close() Return End If FileOpen(1, accountFilePath, OpenMode.Input) Do Until EOF(1) Dim tempUserName As String = String.Empty Dim tempUserPass As String = String.Empty ' 逐行读取单条账号记录 Input(1, tempUserName) Input(1, tempUserPass) ' 写入字典,避免重复键覆盖 If Not accountDict.ContainsKey(tempUserName) Then accountDict.Add(tempUserName, tempUserPass) End If Loop FileClose(1) End Sub - 补全登录按钮的校验逻辑:
Private Sub btnLogin_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLogin.Click ' 校验是否选中账号 If cmbUsername.SelectedIndex = -1 Then MsgBox("请选择需要登录的账号!") Return End If Dim selectedAccount As String = cmbUsername.SelectedItem.ToString() Dim inputPassword As String = txtPassword.Text.Trim() ' 判断选中账号是否存在映射 If Not accountDict.ContainsKey(selectedAccount) Then MsgBox("选中的账号无有效存储记录!") Return End If Dim storedPassword As String = accountDict(selectedAccount) ' 执行密码匹配 If inputPassword.Equals(storedPassword) Then MsgBox("登录验证通过!") ' 此处添加跳转主窗体、关闭登录窗的业务逻辑 Else attempts += 1 MsgBox($"密码错误,当前为第{attempts}次尝试,最多允许{MAX_ALLOW_ATTEMPTS}次输入") ' 达到尝试上限则关闭窗体 If attempts >= MAX_ALLOW_ATTEMPTS Then MsgBox("登录尝试次数过多,即将退出程序") Me.Close() End If End If End Sub
可选优化:提升文件读取容错性
如果不想强制要求.DAT文件必须带双引号,可以把文件读取的部分替换为逐行拆分解析的方式,就算存储时漏打引号、混有多余空行也能正常读取,彻底规避解析错位问题:
' 替换原来的FileOpen读取逻辑 Using reader As New IO.StreamReader(accountFilePath) Do While Not reader.EndOfStream Dim rawLine As String = reader.ReadLine().Trim() ' 跳过空行 If rawLine = String.Empty Then Continue Do ' 按第一个逗号拆分用户名和密码 Dim splitPos As Integer = rawLine.IndexOf(","c) If splitPos <= 0 Then Continue Do ' 拆分内容并去除前后包裹的双引号、多余空格 Dim tempUserName As String = rawLine.Substring(0, splitPos).Trim().Trim(""""c) Dim tempUserPass As String = rawLine.Substring(splitPos + 1).Trim().Trim(""""c) If Not accountDict.ContainsKey(tempUserName) Then accountDict.Add(tempUserName, tempUserPass) End If Loop End Using
内容的提问来源于stack exchange,提问作者apprentice01
相关产品推荐
相关产品推荐

