如何通过文件循环获取数据?

问题描述 投票:0回答:3

我想做一个基本的登录和注册的c#控制台应用程序,但是,我需要循环浏览我的文件,看看用户在登录时输入的用户名和密码是否有匹配。如果用户输入了用户名和密码,我想让我的代码通过我的文件检查是否是现有的用户名和密码。

这是我的代码。

[Serializable]
public class Users
{
    public string UserName;
    public string Password;

    public Users(string userName, string password)
    {
        UserName = userName;
        Password = password;
    }
}

public class SaveToFile
{
    public static void SerializeSignUpDetails(string userName, string password)
    {
        Users obj = new Users(userName, password);
        IFormatter formatter = new BinaryFormatter();
        Stream stream = new FileStream("SignUp.txt", FileMode.Append, FileAccess.Write);
        formatter.Serialize(stream, obj);
        stream.Close();
    }
    public static Users DeserializeSignUpDetails()
    {
        Stream stream = new FileStream("SignUp.txt", FileMode.Open, FileAccess.Read);
        IFormatter formatter = new BinaryFormatter();
        Users objnew = (Users)formatter.Deserialize(stream);
        stream.Close();
        return objnew;
    }
}

public static void Main(string[] args)
{
    Console.WriteLine("To Login Type 1, To Create a new account Type 2");
    int LogInOrSignUp;
    do
    {
        int.TryParse(Console.ReadLine(), out LogInOrSignUp);
    } while (LogInOrSignUp != 1 && LogInOrSignUp != 2);

    string userName = "";
    string password = "";
    bool successfull = false;
    Users userDetails = SaveToFile.DeserializeSignUpDetails();
    while (!successfull)
    {
        if (LogInOrSignUp == 1)
        {
            Console.WriteLine("Write your username:");
            userName = Console.ReadLine();
            Console.WriteLine("Enter your password:");
            password = Console.ReadLine();
            if (userName == userDetails.UserName && password == userDetails.Password)
            {
                Console.WriteLine("You have logged in successfully!");
                successfull = true;
                break;
            }
            if (!successfull)
            {
                Console.WriteLine("Your username or password is incorect, try again!");
            }
        }

        else if (LogInOrSignUp == 2)
        {
            Console.WriteLine("Enter a username:");
            userName = Console.ReadLine();

            Console.WriteLine("Enter a password:");
            password = Console.ReadLine();

            successfull = true;
            SaveToFile.SerializeSignUpDetails(userName, password);
        }
    }
}

我想用foreach来循环浏览我的文件,但我不知道怎么做。

任何帮助感激不尽

c# serialization foreach binaryformatter binary-serialization
3个回答
4
投票

要使用序列化为多个条目保留登录记录,你需要序列化一个对象列表。在你的情况下,你可以创建几个可序列化的类。User 类,封装了单个条目的数据,和 Users 类,其中包含一个 List<User> 对象加上数据操作方法。

✔注。 根据你的喜好命名。

要导入的命名空间

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

用户 阶层

[Serializable]
public class User
{
    public string UserName { get; set; }
    public string Password { get; set; }
    //More details...

    public User(string userName, string password)
    {
        UserName = userName;
        Password = password;
    }

    public override string ToString() => $"{UserName}, {Password}";
}

用户 阶层

[Serializable]
public class Users
{
    public readonly List<User> Accounts;

    public Users() => Accounts = new List<User>();

    public void Save(string filePath)
    {
        if (string.IsNullOrEmpty(filePath)) return;

        var bf = new BinaryFormatter();
        using (var fs = new FileStream(filePath, FileMode.Create))
            bf.Serialize(fs, this);
    }

    public static Users Load(string filePath)
    {
        if (!File.Exists(filePath)) return null;

        var bf = new BinaryFormatter();
        using (var sr = new FileStream(filePath, FileMode.Open))
            return bf.Deserialize(sr) as Users;
    }

    public bool ContainsUserName(string userName) => 
        Accounts.Any(x => x.UserName == userName);

    public bool ContainsAccount(string userName, string pass) =>
        Accounts.Any(x => x.UserName == userName && x.Password == pass);

    public User Get(string userName, string pass) =>
        Accounts.FirstOrDefault(x => x.UserName == userName && x.Password == pass);

    public bool Add(string userName, string pass)
    {
        if (ContainsUserName(userName)) return false;

        Accounts.Add(new User(userName, pass));
        return true;
    }
}

在你的实现中,创建、加载和保存你的数据。

//Load...
users = Users.Load(dataFilePath);

//Or create new object...
if (users is null)
    users = new Users();

//and when it comes to save...
users.Save(dataFilePath);

使用 ContainsUserName 方法来查找一个给定的用户名是否已经存在,从而避免重复。该 Add 方法将做同样的事情,另外它还会将有效的新条目添加到列表中。列表中的 Get 方法为给定的用户名和密码搜索列表并返回一个 User 对象,否则 nullContainsAccount 方法也会这样做,如果你不需要返回一个 User 对象。

var user = users.Get("user", "pass");
if (user is null)
    Console.WriteLine("Incorrect username and/or password...");

//or
if (!users.ContainsAccount("user", "pass"))
    Console.WriteLine("Incorrect username and/or password...");

在你的 main:

public static void Main(string[] args)
{
    Console.WriteLine("To Login Type 1, To Create a new account Type 2");
    int LogInOrSignUp;
    do
    {
        int.TryParse(Console.ReadLine(), out LogInOrSignUp);
    } while (LogInOrSignUp != 1 && LogInOrSignUp != 2);

    var filePath = Path.Combine(AppContext.BaseDirectory, "SignUp.dat");
    var userName = "";
    var password = "";
    var successfull = false;
    var userDetails = Users.Load(filePath);

    if (userDetails is null)
        userDetails = new Users();

    while (!successfull)
    {
        if (LogInOrSignUp == 1)
        {
            Console.WriteLine("Write your username:");
            userName = Console.ReadLine();
            Console.WriteLine("Enter your password:");
            password = Console.ReadLine();
            if (userDetails.ContainsAccount(userName, password))
            {
                Console.WriteLine("You have logged in successfully!");
                successfull = true;
                break;
            }
            else
                Console.WriteLine("Your username or password is incorect, try again!");
        }

        else //if (LogInOrSignUp == 2)
        {
            Console.WriteLine("Enter a username:");
            userName = Console.ReadLine();

            if (userDetails.ContainsUserName(userName))
                Console.WriteLine("The username is taken. Try another one.");
            else
            {
                Console.WriteLine("Enter a password:");
                password = Console.ReadLine();

                successfull = true;
                userDetails.Add(userName, password);
                userDetails.Save(filePath);
                Console.WriteLine($"A new account for {userName} has been created.");
            }
        }
    }
    Console.ReadLine();
}

✔注意。 最好使用 开关 语句来选择 LogInOrSignUp 而非 if 报表

SOQ62185878


2
投票

由于OP提供了一个文件中多个凭证的细节.最常见的方式是序列化。二进制或xml都可以。

相关的主题。在C#中保存数据结构

然而版本兼容可能是你的下一个问题。

版本容忍的序列化 可能会解决你的问题。

======假设你的文件夹里有一串txt。

有两件事必须要做。

  1. 一个接受文件路径参数的函数。
  2. 一个帮助你遍历所有文件的函数。

重写 DeserializeSignUpDetails 取文件路径。

        public static Users DeserializeSignUpDetails( string szPath)
        {
            Stream stream = new FileStream( szPath, FileMode.Open, FileAccess.Read);
            IFormatter formatter = new BinaryFormatter();
            Users objnew = (Users)formatter.Deserialize(stream);
            stream.Close();
            return objnew;
        } 

循环浏览文件,得到所有的登录凭证。它可以放在你的主程序中。

        List<Users> GetAllLoginCredential()
        {
            List<Users> list = new List<Users>();
            string[] files = Paths.GetFileName( "D:\\YourDirectory" );
            foreach( var path in files ){
                Users user = SaveToFile.DeserializeSignUpDetails( path );
                list.Add( user );
            }
        }

然后你可以检查每个用户。另外,你可能需要缓存它,以防止重复打开文件。

顺便说一下。Users 只有一个用户信息,你可能希望它是 User.


1
投票

几个点,你可能要看 -

  1. 将班级名称从 UsersUser 因为这是一个单一的代表 user.
  2. 你可以 convert 所有存储在文件中的用户都会被分配到 List<User> 如下图所示。

       public static List<Users> DeserializeSignUpDetails()
        {
            List<Users> users = new List<Users>();
    
            using (Stream stream = new FileStream(@"SignUp.txt", FileMode.Open, FileAccess.Read))
            {
                if (stream.Length != 0)
                {
                    BinaryFormatter formatter = new BinaryFormatter();
                    while (stream.Position != stream.Length)
                    {
                        users.Add((Users)formatter.Deserialize(stream));
                    }
                    return users;
                }
    
            }
    
            return users;
    
        }                    
    
  3. 然后你可以在你的Main类中使用它,就像下面这样。

      List<Users> userDetails = SaveToFile.DeserializeSignUpDetails();
    

AND 在登录验证时,如下图所示。

if (userDetails != null)
    {
       foreach (Users user in userDetails)
         {
             if (userName == user.UserName && password == user.Password)
                 {
                    Console.WriteLine("You have logged in successfully!");
                    successfull = true;
                    break;
                  }
              if (!successfull)
                 {
                   Console.WriteLine("Your username or password is incorect, try again!");
                 }
        }
    }

其他通知。

  1. 使用 using 在读取流时,正确处置。

  2. 检查 Nullempty 在序列化之前,对流进行序列化处理,以促进 defensive programming 类似

    if (stream.Length != 0)
    
© www.soinside.com 2019 - 2024. All rights reserved.