我想做一个基本的登录和注册的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来循环浏览我的文件,但我不知道怎么做。
任何帮助感激不尽
要使用序列化为多个条目保留登录记录,你需要序列化一个对象列表。在你的情况下,你可以创建几个可序列化的类。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
对象,否则 null
和 ContainsAccount
方法也会这样做,如果你不需要返回一个 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
报表
由于OP提供了一个文件中多个凭证的细节.最常见的方式是序列化。二进制或xml都可以。
相关的主题。在C#中保存数据结构
然而版本兼容可能是你的下一个问题。
版本容忍的序列化 可能会解决你的问题。
======假设你的文件夹里有一串txt。
有两件事必须要做。
重写 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
.
几个点,你可能要看 -
Users
到 User
因为这是一个单一的代表 user
.你可以 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;
}
然后你可以在你的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!");
}
}
}
其他通知。
使用 using
在读取流时,正确处置。
检查 Null
或 empty
在序列化之前,对流进行序列化处理,以促进 defensive programming
类似
if (stream.Length != 0)