繁体   English   中英

如何使用 StreamReader 并读取文本文件的某些部分?

[英]How to use StreamReader and read from certain parts of the text file?

我正在尝试制作一个已完成注册的登录系统。 我想把它放在你按下登录按钮的地方,然后它使用 StreamReader 读取已使用我的注册表单更新的文件。 问题是我已经构建了文件的编写方式(例如:当用户输入他们的详细信息时,它会将他们的详细信息保存在像 Username: johndoe Password: Password1 这样的结构中,在我的注册表单中使用 StreamWriter)。 但是当我使用 StreamReader 时,它会读取整行而不是某些部分。 我如何只读取文本文件的某些部分?

注册表单代码:

        bool valid = true;
        List<string> errorMessages = new List<string>();

        if (string.IsNullOrWhiteSpace(txtUsername.Text))
        {
            valid = false;
            errorMessages.Add("Username cannot be left empty.");
        }
        if (string.IsNullOrWhiteSpace(txtPassword.Text))
        {
            valid = false;
            errorMessages.Add("Please enter a password.");
        }
        if (txtConfirmPass.Text != txtPassword.Text)
        {
            valid = false;
            errorMessages.Add("Passwords do not match. Please enter matching passwords.");
        }
        if (valid == false)
        {
            string message = string.Join(Environment.NewLine, errorMessages);
            MessageBox.Show(message, "Validate Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        else if(valid == true)
        {
            Random rnd = new Random();
            string userID = rnd.Next(0, 100000).ToString("D6");
            //Use StreamWriter class.
            using (StreamWriter sw = new StreamWriter("Test.txt", true))
            {
                sw.Write("\n" + "UserID: " + userID + "\n");
                sw.Write("Username: " + txtUsername.Text + "\n");
                sw.Write("Password: " + txtPassword.Text + "\n");
                sw.Write("------------------------------------");

                MessageBox.Show("Details have been saved");
                frmLogin login = new frmLogin();
                login.Show();
                this.Hide();
            }
        }           

登录表单代码:

private void btnLogin_Click(object sender, EventArgs e)
    {
        bool valid = false;
        using (StreamReader sr = new StreamReader("Test.txt"))
        {
            if(txtboxUser.Text == sr.ReadToEnd() && txtboxPass.Text == sr.ReadToEnd())
            {
                valid = true;
                MessageBox.Show("Granted.");
            }
            else if(valid == false)
            {
                MessageBox.Show("Error");
            }
        }
    }

您可以尝试在 StreamReader 中使用ReadLine()方法,如下所示,您应该跟踪第 2 行包含用户名,第 3 行包含密码。 此外,您应该使用正则Regex从文本中拆分和获取值,或者您可以使用:分隔符并在比较之前修剪值。

using (StreamReader sr = new StreamReader(path))
{
    int counter = 0;
    while (sr.Peek() >= 0)
    {
        string content = sr.ReadLine();
        var userName = content.split(':')[1].trim()...
        counter++;
    }
}

注意: StreamReader 直接从文件中读取,因此您必须执行字符串操作操作。 相反,您还可以考虑使用其他方法(例如缓存或数据库操作)来跨页面/窗口保留值。

你想通过遍历txt文件来检查用户是否输入了正确的用户名和密码?

测试信息结构:

UserID: 016696
Username: kkk
Password: p123

这里有一个简单的你可以参考。

private void btnLogin_Click(object sender, EventArgs e)
{
    string username = "";
    string password = "";
    bool ischecked = false; // check if the Username line is read
    bool loginsuccess = false; // check if succeed

    string line;

    // Read the file and display it line by line.  
    System.IO.StreamReader file = new System.IO.StreamReader("Test.txt");
    while ((line = file.ReadLine()) != null)
    {
        // if true, this is password line
        if (ischecked)
        {
            // get password
            // call Trim to remove extra spaces
            password = line.Split(':')[1].Trim();

            // check username and password
            if (txtUsername.Text == username && txtPassword.Text == password)
            {
                MessageBox.Show("Login Successfully");
                loginsuccess = true; //  login in success
                break;
            }
            // reset boolean
            ischecked = false;
        }

        // read Username line, next line is the corresponding password
        if (line.Split(':')[0] == "Username")
        {
            username = line.Split(':')[1].Trim();
            // set boolean to true
            ischecked = true;
        }
    }

    file.Close();
    
    // login failed
    if(!loginsuccess)
    {
        MessageBox.Show("Wrong username or password");
    }
}

您的代码有问题,因为您想在一种方法中做太多事情。 你应该分开你的顾虑

在您的情况下:您不应该将与操作员的通信与输入数据的序列化方式混合在一起。

如果将 HMI 与保存和读取输入的方式分开:

  • 更易于重复使用:如果您需要读取已保存的登录数据,而无需再次询问操作员:只需读取即可。
  • 更容易更改:如果您想要不同的 HMI,您仍然可以以原始格式保存。 如果你想以加密格式保存它,你的HMI不需要改变。
  • 更易于测试:您可以对保存/读取文件进行单元测试,而无需操作员输入。

因此将HMI与保存/读取文件分开,与处理登录数据分开。 这将需要一些额外的输入,但您的代码将更容易理解,更容易测试,并且未来的更改对现有代码的影响将更小。

为此,您需要一个包含登录数据的类。 像这样的东西:

class User
{
    public int Id {get; set;}
    public string Name {get; set;}
    public string Password {get; set;}
}

用户界面

在 HMI 中显示用户,或从 HMI 获取用户。 在您的表单类中:

public User ReadUser()
{
    return new User
    {
        Id = this.CreateUserId(),
        Name = this.txtUserName.Text,
        Password = this.txtPassword.Text,
    };
}

// not sure if you need this:
public void DisplayUser(User user)
{
    this.txtUserName.Text = user.Name,
    this.txtPassword.Text = user.Password,
}

考虑创建一个属性:

public User User
{
    get => new User {Id = this.CreateUserId(), ...},
    set
    {
        this.txtUserName.Text = value.Name,
        ...
    }
}

如果将来您想以不同的方式显示用户,例如在 DataGridView 或 ComboBox 中,将只有一次您必须实施更改的地方。

序列化用户

我的建议是坚持使用通用格式,如 CSV、XML、JSon。 这将使您的生活变得更加轻松,因为您可以为此使用 NUGET 包。

如果你不能说服你的项目负责人这是一个更好的解决方案,而他仍然希望你使用你自己发明的格式,你需要两种方法:

public void Serialize(User user, string fileName)
{
     using (var textWriter = System.IO.File.CreateText(fileName, ...))
     {
          ... // see your own code
     }
}

顺便说一句:为什么要写`\\n,为什么不使用TextWriter.WriteLine

反序列化用户

目前您的文件具有以下布局:

  • 空行

  • 一行带有“UserId:” + Id

  • 带有“用户名:”+ 名称的一行

  • 一行带有“密码:”+密码

    public User Deserialize(string fileName) { using (var textReader = System.IO.File.OpenText(fileName, ...)) { string emptyLine = textReader.ReadLine(); if (emptyLine == null) ... // TODO:决定文件格式无效时的处理方式。 例外?

     string txtId = textReader.ReadLine(); if (txtId == null) ... // TODO: decide what to do if invalid file format int id = Int32.Parse(txtId); // TODO: handle invalid txtId format. Exception? string name = textReader.ReadLine(); string password = textReader.ReadLine(); // TODO: handle invalid name / password; return new User { Id = id, Name = name, Password = password, } }

    }

您是否看到,如果您将来更改保存用户的格式,您只需要更改两种序列化方法? 例如,如果您认为密码需要在文件中加密,或者您认为 JSON 格式更好。

由于关注点分离,如果您不需要显示它,您也可以使用用户的序列化。

关注点分离也使单元测试更容易 } }

sw.Write("\\n" + "UserID:" + userID + "\\n"); sw.Write("用户名:" + txtUsername.Text + "\\n"); sw.Write("密码:" + txtPassword.Text + "\\n"); sw.Write("------------------------------------");

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM