C#从文本文件登录系统报错

C# login system from text file error

好吧,我是编码新手,我知道 SQL 中的登录更安全,但这只是为了学习 streamwriter 和 reader。

namespace text_file_login
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

    private void btn_register_Click(object sender, EventArgs e)
    {

        StreamWriter user_reg = new StreamWriter(@"E:\SSD\Controled Assesment\text file login\text file login\username.txt",true);
        StreamWriter pass_reg = new StreamWriter(@"E:\SSD\Controled Assesment\text file login\text file login\password.txt",true);

        user_reg.WriteLine(textBox1.Text);
        user_reg.Close();
        pass_reg.WriteLine(textBox2.Text);
        pass_reg.Close();
    }

    private void textBox1_TextChanged(object sender, EventArgs e)
    {

    }
    string user = "";
    int txt_position = 0;
    private void btn_login_Click(object sender, EventArgs e)
    {
        StreamReader user_login = new StreamReader(@"E:\SSD\Controled Assesment\text file login\text file login\username.txt", true);
        StreamReader pass_login = new StreamReader(@"E:\SSD\Controled Assesment\text file login\text file login\password.txt", true);

        do
        {
            user = user_login.ReadLine() + "\r\n";
            txt_position++;
        } while (user_login.Peek() != -1);

        string pass = File.ReadLines(@"E:\SSD\Controled Assesment\text file login\text file login\password.txt").Skip(txt_position).Take(1).First();

        if ((pass == textBox2.Text) && (user == textBox1.Text))
        {
            quiz_details form2 = new quiz_details();

            form2.Show();
        }
        else
        {
            // message box
        }
      }
    }
}

好吧,我已经能够在文本文件中写入新行并登录(我想)我还没有检查,因为我一直收到这个错误 “在 System.Core.dll

中发生了 'System.InvalidOperationException' 类型的未处理异常

附加信息:序列不包含任何元素

我一直在尝试读取一个文本文件并先找到用户名,然后在找到用户名时停止并保存位置,这样我就可以将其输入 skip 以直接跳到另一个文本文件上的那一行,这样找到对应的密码。

有什么方法可以使它起作用,还是我只是在用这种方法浪费时间,而我完全错了。如果我是,我很抱歉。我想通过自己编写代码来学习,而不是仅仅复制代码并尝试理解。

错误来自 Skip().Take().First() 语句(或者更确切地说,来自您提供的值)

通过更多地拆分您的程序,之后您可以使它对程序员更加友好(不要看代码 6 个月然后再检查 :))

一种更好地组织这些东西的方法是以下方式(我将它写成一个控制台程序,所以你可以将它复制粘贴到一个新的控制台项目中,它应该可以工作(并显示逻辑给你))

using System;
using System.IO;

namespace RegisterUsers
{
    class Program
    {
        static void AppendToFile(string file, string value)
        {
            using (TextWriter writer = new StreamWriter(file, true))
            {
                writer.WriteLine(value);
            }
        }

        static void Register(string userFile, string passwordFile, string userName, string password)
        {
            AppendToFile(userFile, userName);
            AppendToFile(passwordFile, password);
        }

        static string[] GetLines(string file)
        {
            string[] result = null;
            using (TextReader reader = new StreamReader(file))
            {
                result = reader.ReadToEnd().Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
            }
            return result;
        }

        static bool TryLogin(string userFile, string passwordFile, string username, string password)
        {
            string[] userArray = GetLines(userFile);
            int index = -1, length = userArray.Length;
            for (int x = 0; x < length; x++)
            {
                if (string.Equals(userArray[x], username))
                {
                    index = x;
                    break;
                }
            }
            if (index < 0)
            {
                // no username found that matches your requirement
                return false;
            }
            string[] passArray = GetLines(passwordFile);
            if (index > passArray.Length)
            {
                // inconsistency, shouldn't happen...
                return false;
            }
            return string.Equals(passArray[index], password);
        }

        static void Main(string[] args)
        {
            // keep the filenames, don't have to repeat them all the time
            string usernameFile = Path.Combine(Environment.CurrentDirectory, "UserFile.txt");
            string passwordFile = Path.Combine(Environment.CurrentDirectory, "PassFile.txt");

            // register 2 users, one with falsely typed testUser2 as tesetUser2
            Register(usernameFile, passwordFile, "testUser1", "password1");
            Register(usernameFile, passwordFile, "tesetUser2", "password15");

            // try to login with the testUser1 should work
            if (TryLogin(usernameFile, passwordFile, "testUser1", "password1"))
            {
                Console.WriteLine("Login succesfull");
            }
            else
            {
                Console.WriteLine("Login failed!");
            }

            // try to login with testUser2 shouldn't work (now correctly typed)
            if (TryLogin(usernameFile, passwordFile, "testUser2", "password15"))
            {
                Console.WriteLine("Login succesfull");
            }
            else
            {
                Console.WriteLine("Login failed!");
            }
            Console.ReadLine();
        }
    }
}

所以你有一个包含用户名的文件和一个包含与这些用户名匹配的密码的文件。当用户单击 Login 按钮时,您试图从文件中查找他们输入的用户名,找到用户名所在的行,然后在密码文件中查找相应的密码。

让我们暂时忘记这是一种非常糟糕的安全处理方式,而只是为了指导目的而尝试让代码工作。

第一个任务是获取匹配用户名的行。我会写一个方法来做到这一点,就像这样:

private int GetUsernameIndex(string username)
{
    //Use a using statement so we don't leave the username.txt file
    //open after we're done reading from it, using will call Dispose for you
    using(var sr = new StreamReader(@"C:\temp\username.txt"))
    {
        string line;
        var index = 0;

        //when sr.ReadLine == null, we've reached the end of the file
        while((line = sr.ReadLine()) != null)
        {
            if(string.Equals(line, username))
                return index;
            index++;
        }

        //Return -1 if username not found
        return -1;
    }
}

此方法将 return 用户的索引,如果未找到用户,则为 -1。我们需要编写的下一个方法是获取密码的方法,它可能如下所示:

private string GetPassword(int index)
{
    //Don't bother to search a negative index
    if(index < 0) return string.Empty;

    //Find the line matching the index and return the value there
    using(var sr = new StreamReader(@"C:\temp\password.txt"))
    {
        string line;
        var currentLine = 0;
        while((line = sr.ReadLine()) != null)
        {
            if(index == currentLine)
                return line;
            currentLine++;
        }

        //Return string.Empty if line not found
        return string.Empty;
    }
}

最后,我们将编写一个方法将这两个放在一起并验证用户名和密码:

private bool IsUsernameAndPasswordValid(string username, string password)
{
    var index = GetUsernameIndex(username);
    var storedPassword = GetPassword(index);

    //If storedPassword is empty, then return false
    //If password and storedPassword do not match, then return false
    //Otherwise, the password is valid for this user
    return storedPassword != string.Empty && password == storedPassword; 
}

希望这能帮助您了解文件 I/O 的一些基础知识。同样,您的设计远非理想,但在我看来,如果您愿意,了解如何编写该代码会有所帮助。