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

C# 如何检查c中的文本文件中是否已经存在用户输入,c#,text-files,C#,Text Files,我正在为我的a级计算课程制作一个c应用程序。我的课程要求我有一个注册和登录系统,而我目前正忙于注册部分,因为我的注册系统旨在检查用户选择的用户名是否已经存在于文本文件中 我已经在一个解决方案上搜索了堆栈溢出,并尝试实现类似的解决方案,但它似乎不起作用,因为我的代码仍然允许新用户使用现有密码注册 string firstname = txtBoxFirstname.Text; string surname = txtBoxSurname.Text; string fullname = txt

我正在为我的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");
}

如果输入的用户名已经存在,但我的程序仍然为用户创建了一个帐户,那么我的预期代码应该会返回一条消息,说明此用户名已被使用。这里有一行代码可以检查您的文件是否包含用户名:

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"; 
然后,如果您询问整个数组是否包含用户名,则只有当数组中的一个字符串正好是john时,它才会响应true

这个数组没有一个完全是john的字符串,尽管其中一行的确有文本john。。但在字符串数组中使用.Contains时,只有当数组中的一个字符串等于john时,它才会返回true

数组中没有一个字符串与John相等

如果你说:

File.ReadLines(...).Contains("John smith~john~password1");
那么结果就是真的,因为数组中的一个字符串实际上等于John smith~John~password1

或者,如果您在字符串数组中循环,并询问每个字符串是否包含john:

string[] lines = File.ReadLines(...);
foreach(string line in lines)
  if(line.Contains("~" + username + "~"))
    contains = true;
这也可以解决问题

TLDR:

ArrayOfString.Containsjohn->检查数组中的一个字符串是否等于字符串john ASingleString.Containsjohn->检查单个字符串中是否有john 我知道,数组类和字符串类都有一个名为Contains的方法,这可能会让人感到困惑,但这种情况经常发生——名称相同,行为不同

ReadAllText之所以有效,是因为它只将文件作为一个长字符串提供给您。您的用户名两边总是有一个~字符,因此John smith~John~ password1\r\nJane smith~jane~ password2\r\nFred smith~fred~ password3字符串确实包含~John~

这有一个轻微的潜在错误:如果其中一个密码是john,这种方式也会返回true。当然,为了安全起见,您将对密码进行哈希运算,以使其无法读取,对吗;但这是一个风险,需要意识到并在以后适当处理

我很想使用File.AppendAllText将您的用户名添加到文件中,而不是使用您的方式:它是一个单行方法,用于打开文件、写入文件并再次关闭文件

您可能希望比my 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
}

将~上的字符串拆分为其组成部分是一种更可靠的检查数据的方法,它将有助于以后检查他们键入的密码是否正确,返回欢迎消息的全名等等。

在这里,您可以检查文件是否包含与用户名完全匹配的行

File.ReadLines("users.txt").Contains(username)
但是你的行看起来像全名+~+username+~+password+~+lastlogin,当然永远不会有一行是macheusername。您应该做的是拆分正在使用的分隔符~上的每一行,并从中获取用户名:

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负责业务逻辑,例如在注册新用户之前检查用户名是否已在使用,UI代码负责从控件中获取数据并向用户显示结果。它应该调用服务以获取结果。
旁注:看看你调试了吗?ContainesUser的价值是什么?如果不调试它,很难说,但是用户是否都在相同的情况下username1!=用户名1。我的建议是将检查文本中用户名的逻辑部分分开,并将其放在单独的函数中,传入字符串,然后编写单元测试。这将帮助您快速确定问题所在。您可以读取文本文件并从文件中获取所有用户名并将其放入列表中,对照listCo检查新用户名
ntains+username+~将不起作用,因为有人可以使用与给定用户名相等的密码。是的,我已经介绍过了。考虑到观众,我认为使用LINQ不是特别合适。我还想把这种适合观众的感觉延伸到你的大部分要点。考虑到“观众”已经被使用,林克,我看不出有任何理由离开它。同样,不仅仅是问问题的人,阅读答案的人都是“听众”。比如你。