如何检查用户输入是否已经存在于C#的文本文件中

时间:2019-01-09 18:50:40

标签: c# text-files

我正在为我的A级计算课程编写C#应用程序。我的课程要求我拥有注册和登录系统,而我目前仍受制于注册部分,因为我的注册系统旨在检查文本文件中是否已存在用户选择的用户名。

我已经搜索了解决方案的堆栈溢出问题,并尝试实现了类似的解决方案,但由于我的代码仍然允许新用户使用已经存在的密码进行注册,因此它似乎起作用了

 string firstname = txtBoxFirstname.Text;
 string surname = txtBoxSurname.Text;
 string fullname = txtBoxFirstname.Text+" "+txtBoxSurname.Text;
 string username = txtBoxUsername.Text;
 string password = txtBoxPassword.Text;
 string confirmedPassword = txtBoxConfirmedPassword.Text;
 DateTime lastlogin = DateTime.Now;
 bool containsUser = File.ReadLines("users.txt").Contains(username);

if ((!string.IsNullOrEmpty(firstname)) && 
   ((!string.IsNullOrEmpty(surname)) && 
   ((!string.IsNullOrEmpty(username)) && 
   (!string.IsNullOrEmpty(password)) && 
   (!string.IsNullOrEmpty(confirmedPassword)))))
{

    if ((!username.Contains("~")) || (!password.Contains("~")))
    {
        if (password == confirmedPassword)
        {
            if (containsUser == false)//this is the part that check if a username already exists
            {
                FileStream fileStream = new FileStream("users.txt", FileMode.Append, FileAccess.Write);
                StreamWriter streamWriter = new StreamWriter(fileStream);

                try
                {
                    streamWriter.WriteLine(fullname + "~" + username + "~" + password + "~" + lastlogin);

                    MessageBox.Show("User registered successfully", "Registration Successful");

                    this.Hide();
                    var homeForm = new HomeForm();
                    homeForm.Closed += (s, args) => this.Close();
                    homeForm.Show();

                }
                catch (Exception)
                {
                    MessageBox.Show("Error registering the user", "Please try again");
                }
                finally
                {
                    streamWriter.Close();
                    fileStream.Close();
                }
            }
            else
            {
                MessageBox.Show("Sorry this username is already taken", "Please try again");
            }
        }
        else
        {
            MessageBox.Show("Passwords must match",
                        "Incorrect Details");
        }
    }
    else
    {
        MessageBox.Show("Username and password must not contain any special characters i.e. ~", "~ entered");
    }

}
else
{
    MessageBox.Show("Please ensure all data is entered into the fields",
        "Details missing");
}

如果输入的用户名已经存在,但我的程序仍会为该用户创建一个帐户,则我的预期代码应该返回一条消息,指出已经使用了该用户名

2 个答案:

答案 0 :(得分:1)

这里是一种单行代码,它将检查您的文件是否包含用户名:

bool usernameExists = File.ReadAllText(@"C:\path\to\your\file.txt").Contains("~" + username + "~");

您的程序一直在注册新用户的原因是因为您在使用ReadLines()时犯了一个轻微的逻辑错误-它返回一个字符串数组。如果文件有3行:

John smith~john~password1
Jane smith~jane~password2
Fred smith~fred~password3

这就是作为数组得到的结果,就像您在代码中完成的一样:

var array = new string[3];
array[0] = "John smith~john~password1";
array[1] = "Jane smith~jane~password2";
array[2] = "Fred smith~fred~password3"; 

然后,如果您询问整个数组是否为.Contains()用户名,则只有当数组中的字符串之一恰好是“ john”时,它才会响应true。

此数组没有一个完全是“ john”的字符串,尽管其中的一行中确实有文本“ john”。但是当您在字符串数组上使用.Contains()时,它将仅在数组中的字符串之一等于“ john”的情况下返回true。

数组中的所有字符串都不等于John

如果你说:

File.ReadLines(...).Contains("John smith~john~password1");

则结果将为true,因为数组中的字符串之一实际上等于“ John smith〜john〜password1”。

或者,如果您遍历了字符串数组并询问每个字符串中是否包含“ john”:

string[] lines = File.ReadLines(...);
foreach(string line in lines)
  if(line.Contains("~" + username + "~"))
    contains = true;

这也可以解决。

TLDR:

  • ArrayOfString.Contains(“ john”)->检查数组中的字符串之一何时等于字符串“ john”
  • ASingleString.Contains(“ john”)->检查单个字符串内是否有“ john”

我知道,可能令人困惑的是,Array和String类都具有一个称为Contains的方法,但是这种情况经常发生-名称相同,行为不同


ReadAllText()起作用的原因是它只是将文件作为一个长字符串提供给您。您的用户名总是带有〜,因此,John smith~john~password1\r\nJane smith~jane~password2\r\nFred smith~fred~password3的字符串确实包含~john~

这有一个潜在的小错误:如果密码之一是“ john”,这种方式也将返回true。当然,为了安全起见,您将对密码进行哈希处理,以使它们无法读取。 ;),但有可能会意识到并适当处理(以后)


我很想使用File.AppendAllText将用户名添加到文件中,而不是使用完成方式:这是一种单行方法,用于打开文件,写入文件并再次关闭文件。

您可能想使它比我的File.ReadAllText更复杂,并使用您的方法,但请记住要正确处理字符串数组:

string[] lines = File.ReadLines(...);
foreach(string line in lines){
  string[] bits = line.Split('~');
  string fullname = bits[0];
  string username = bits[1];
  string password = bits[2];
  string lastlogin= bits[3];

  //now you can do more thorough checks
  if(userinput.Equals(username, InvariantCultureIgnoreCase)) //case insensitive compare
}

将字符串拆分到〜组件中是一种更可靠的数据检查方法,稍后将有助于检查他们是否键入了正确的密码,返回欢迎消息的全名等。

答案 1 :(得分:0)

在此处检查文件是否包含与用户名完全完全匹配的行

File.ReadLines("users.txt").Contains(username)

但是您的行看起来像fullname + "~" + username + "~" + password + "~" + lastlogin,当然不会有任何行username。您应该做的是在正在使用的分隔符(~)上分割每一行,并从中获取用户名:

var registeredUsers =
      from line in File.ReadLines("users.txt")
      let parts = line.Split('~')
      select parts[1]; // because first goes full name

bool containsUser = registeredUsers.Contains(username);

一些注意事项:

  • 保持密码不是一个好主意-您应该存储密码哈希。
  • 考虑使用数据库避免每次用户登录或注册时都解析所有用户数据
  • 考虑使用保护条件来避免使用箭头代码反模式
  • 请考虑将UI代码,业务逻辑和与持久性相关的代码分开。它将大大简化您的程序。例如。在这种情况下,您可以使用UserRepository来知道如何从存储中隐藏用户,UserService来负责业务逻辑(例如,在注册新用户之前检查用户名是否已在使用),以及负责从控件中获取数据并向用户显示结果(应致电服务以获取结果)。