[英]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与保存/读取文件分开,与处理登录数据分开。 这将需要一些额外的输入,但您的代码将更容易理解,更容易测试,并且未来的更改对现有代码的影响将更小。
为此,您需要一个包含登录数据的类。 像这样的东西:
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.