C# Comparing user input with data from external file C# - c#

Sorry if the post is duplicated, but I couldn't find any case like mine that is posted here or somewhere else.
I am working on a C# console application that should save the user input and then read it again "Something like a simple sign up and login application".
using System;
using System.IO;
namespace Reader
{
class Program
{
static void Main(string[] args)
{
string filepath = #"C:\myProgramingFiles\password.txt";
StreamReader reader = File.OpenText(filepath);
string line = reader.ReadLine();
Console.WriteLine("Write your username:");
string userInput = Console.ReadLine();
Console.WriteLine("Write your password:");
string password = Console.ReadLine();
Console.WriteLine(userInput);
Console.WriteLine(password);
while(line != null)
{
Console.WriteLine(userInput == line);
Console.WriteLine(password == line);
if (userInput == line)
{
Console.WriteLine("Your username is: " + line);
}
if(password == line)
{
Console.WriteLine("Your password is: " + line);
}
line = reader.ReadLine();
}
reader.Close();
}
}
}
I have this code that reads the data from password.txt, and everything works fine, but when I do the if-else it's first checks if both user inputs are the same as the username, and then it loops again and checks if both user inputs are like the password. Sorry if I couldn't make it clear, you can run this code if you want and mock up the password.txt, and check it.
It is actually a logical and expected result, but the thing is that I don't know how else I should do it. Can you please help me?
I have tried a lot of things that didn't work, and this was my last try, so I know that it is not the best code, but it explains the problem

Let's suppose your password.txt file is like this (which appears to be the case):
password.txt
User1
Pass123
User2
Pass456
etc.
The way your code is written, with that loop you have, if the user enters User1 for the username and Pass123 for the password, the output will be:
Your username is: User1
Your password is: Pass123
BUT if the same user enters User1 and Pass456 the output will be:
Your username is: User1
Your password is: Pass456
Which is obviously undesirable logic.
So what you need is to use your loop to check for the matching username, and only when that condition is met, check for the matching password.
Otherwise you even get results like this, if the user enters Pass123 for the username and Pass456 for the password:
Your username is: Pass123
Your password is: Pass456
This can happen because you are not associating the password with the username. To make them connected you would write the code like this, assuming that username and password are on separate lines:
SOLUTION:
while(line != null)
{
Console.WriteLine(userInput == line);
Console.WriteLine(password == line);
if (userInput == line)
{
// ** CHANGES BEGIN
line = reader.ReadLine(); // get password on next line
if (line == password)
{
Console.WriteLine("Credentials are valid");
}
else
{
Console.WriteLine("Credentials are invalid");
}
break; // no need to continue this loop
}
else {
// Important: skip past password line since the username didnt match
line = reader.ReadLine();
}
// ** CHANGES END
line = reader.ReadLine(); // this is now reading the next username or EOF
}

Put the following into your text file:
hello:world
Put the following into your code:
static void Main(string[] args)
{
string filepath = #"C:\myProgramingFiles\password.txt";
Console.WriteLine("Write your username:");
string username = Console.ReadLine();
Console.WriteLine("Write your password:");
string password = Console.ReadLine();
var lines = File.ReadAllLines(filepath);
var usrpwd = username + ":" + password;
foreach(line in lines)
{
if(usrpwd == line)
Console.WriteLine("Credentials accepted");
}
}
Run the app and type hello as the username and world as the password. Build from there ..
When it comes to saving new data in your text file look at File.AppendAllLines or read all your lines in, add new data in memory and then overwrite the whole file. That's probably most easily arranged by having the data in a list, rather than an array:
var lines = new List<string>(File.ReadAllLines(...));
Then you can lines.Add(...) a user:password pair and write it out again

Related

Looping through a list and checking for contents?

I'm trying to set up a simple command for entering all callers into a .txt file, everything is working out nicely except for the part where I want to loop through the list and check that no one is trying to enter more than once, it's not causing any problems to the application itself but it's not doing what it's supposed to do.
Any help would be much appreciated.
string filePath = Secret.Secrets.fileDestination;
var username = msg.Author.Username;
//ulong
var ID = msg.Author.Id;
string IDout = ID.ToString();
List<string> entries = File.ReadAllLines(filePath).ToList();
if(entries.Contains(IDout))
{
await msg.Channel.SendMessageAsync($"{msg.Author.Mention}, you have already been entered.");
Console.ForegroundColor = ConsoleColor.DarkRed;
Console.WriteLine($"Denied entry for {msg.Author.Mention}");
return;
}
entries.Add($"{username}, {ID}");
File.WriteAllLines(filePath, entries);
await msg.Channel.SendMessageAsync($"{msg.Author.Mention} has been entered!");

C# Console Application Password Input Checker

The following code has preset passwords that the user must enter to continue the code. However, when the set passwords (PASS1-PASS3) are entered, the code goes to the do-while regardless. What do I need to do in order to make the while recognize that the password is correct so that it does not go to the invalid password line?
// Program asks user to enter password
// If password is not "home", "lady" or "mouse"
// the user must re-enter the password
using System;
public class DebugFour1
{
public static void Main(String[] args)
{
const String PASS1 = "home";
const String PASS2 = "lady";
const String PASS3 = "mouse";
String password;
String Password;
Console.Write("Please enter your password ");
password = Console.ReadLine();
do
{
Console.WriteLine("Invalid password enter again: ");
password = Console.ReadLine();
} while (password != PASS1 || password != PASS2 || password != PASS3);
Console.WriteLine("Valid password");
Console.ReadKey();
}
}
You have your logic the wrong way around i.e. do something then check some conditions, whereas you want to check some conditions and then do something. So the following code:
do
{
Console.WriteLine("Invalid password enter again: ");
password = Console.ReadLine();
} while (password != PASS1 || password != PASS2 || password != PASS3);
Should read:
while (password != PASS1 && password != PASS2 && password != PASS3)
{
Console.WriteLine("Invalid password enter again: ");
password = Console.ReadLine();
}
Notice that I also changed the logical ORs || to logical ANDs &&. this is because you want to check if it is not equal to all of them, not just one.
On a side note the variable Password is unused and should be removed as it can lead to typo errors to your used variable password.
Try changing the "||" to "&&".
It will cannot equal all of them at once.

faulty login system, will not allow logins

ok, i got it sorted thanks to LordALMMa, but now i have another problem. I want to determine if the user clicks Admin or User radiobutton when registering. I think i should append it to the end of the line on the text file where the name and password is, but how would i do it? Here is the relevant code:
Radio Button Check
public bool radioButtons()
{
string usertypebutton;
if (!userButton.Checked && !adminButton.Checked)
{
MessageBox.Show("You must select an account type");
return false;
}
else
{
if (userButton.Checked)
{
usertypebutton = "User";
}
else
{
usertypebutton = "Admin";
}
return true;
}
}
Streamwriter for registering:
public void mySW()
{
string path = #"C:\Other\myFile.txt";
string userName = userNameBox.Text;
string password = passwordBox.Text;
string usertype = usertypebutton;
using (StreamWriter writer = new StreamWriter(path, true))
{
writer.WriteLine("Username: {0} Password: {1} Type: {3}" , userName, password, usertype);
// No need to close nor dispose your StreamWriter.
// You're inside a using statement for that!
}
MessageBox.Show("Thanks for registering! \n\nYou may now log in!", "Registration SuccessFul");
Application.OpenForms[0].Show();
this.Close();
}
Logging In:
private void logonButton_Click(object sender, EventArgs e)
{
// Loads your users storage
var users = File.ReadAllLines(#"C:\Other\myFile.txt");
// Creates the line with username + password
var usernamePassword = String.Format("Username: {0} Password: {1}", userNameBox.Text, passwordBox.Text);
// Locates the user on your storage
var userFound = users.SingleOrDefault(_u => _u.Equals(usernamePassword));
if (userFound != null)
{
MessageBox.Show("Welcome back, " + userNameBox.Text);
}
else
{
MessageBox.Show("Sorry, you have entered incorrect details\n\nPlease try again");
userNameBox.Text = "";
passwordBox.Text = "";
}
}
So (I think) essentially i want to pass the value usertypebutton from radiobutton method, to the SW. How would i do it, as i'm already passing a boolean value?
Anthony
One part of the problem is that you are not writing the same string that you're reading:
writer.WriteLine("Password: " + userName + " " + "Password: " + password);
I'm guessing that was a typo in your post... but if not that could be your issue.
The other problem is probably this right here:
using (StreamWriter writer = new StreamWriter(path, true))
If you look up the documentation on that overload of the StreamWriter constructor, you'd see that you specified append = true. You are appending each set of login credentials to a file on its own line. But then later, you are only reading the first line of that file. So you will always read the first set of credentials that were entered when the file was first created.
That aside, I hope you are just doing this as an experiment since it is not a secure way of managing passwords to write them to a file like that. Also, you don't need to call Close and Dispose on a Stream if you wrap it in a using block, so you should stick to doing that.
Anthony, dispite the fact that storing logins this way is a major security problem (it's not even a risk anymore), there are some changes to your code that I'd do.
The issue is that you're not storing "Username: [username] Password: [password]".
If you double-check your saving method, you're storing "Password: [username] Password: [password]". That's why they are never found.
Here follows some changes:
Consider:
public void mySW()
{
string path = #"C:\Other\myFile.txt";
string userName = userNameBox.Text;
string password = passwordBox.Text;
using (StreamWriter writer = new StreamWriter(path, true))
{
// This overload makes your life easier by auto-formatting variables for you.
// Also, avoid the "string1 + string2" concatenation mode.
// Use String.Format instead. It's easier to read and keep over time.
writer.WriteLine("Username: {0} Password: {1}", userName, password);
// No need to close nor dispose your StreamWriter.
// You're inside a using statement for that!
}
MessageBox.Show("Thanks for registering! \n\nYou may now log in!", "Registration SuccessFul");
Application.OpenForms[0].Show();
this.Close();
}
And your other method should look like:
{
// Loads your users storage
var users = File.ReadAllLines(#"C:\Other\myFile.txt");
// Creates the line with username + password
var usernamePassword = String.Format("Username: {0} Password: {1}", userNameBox.Text, passwordBox.Text);
// Locates the user on your storage
// This uses Linq syntax with lambda. Linq without lamba looks similar to SQL.
// Lambda is a bit more advanced but reduces code-size and it's easier to understand (IMHO).
// This code will iterate through users (list of string) and try to retrieve one that's equal to the contents of usernamePassword.
var userFound = users.SingleOrDefault(_u => _u.Equals(usernamePassword));
// If null, indicates that no username/password combination was found.
if (userFound != null)
{
MessageBox.Show("Welcome back, " + userNameBox.Text);
}
else
{
MessageBox.Show("Sorry, you have entered incorrect details\n\nPlease try again");
userNameBox.Text = "";
passwordBox.Text = "";
}
}
I'm not checking for the exception. SingleOrDefault will throw an exception if 2 or more records are found mathing the search pattern.
I'm not checking that because this will increase complexity here with try-catch and also because for that to work properly, I'd have to check if they exits BEFORE recording, so changing the register method.
But I think you've got the idea here.
Have you checked your output files? You are writing Password: X Password: Y:
writer.WriteLine("Password: " + userName + " " + "Password: " + password);
and you are checking Username: X Password: Y
if (user == ("Username: "+userNameBox.Text.Trim()+" "+"Password: "+passwordBox.Text.Trim()))
You are adding line as
writer.WriteLine("Password: " + userName + " " + "Password: " + password);
^1 ^2
^1 must be Username:
There are some points which I cannot pass without pointing:
What would you do if file structure corrupted?
What if a user wants to register twice with same username and password?
Please encode the passwords. This is not ethic. You put at risk your members who uses same account information in somewhere else.
Try using a database which is stronger and faster than a text file.

Is it possible to read unknown number of lines from console in C#?

There is a function, which can read a single line from the console input (Console.ReadLine()), but I wish to read or some arbitrary number of lines, which is unknown at compile time.
Of course it is. Just use just read a single line (using ReadLine() or whatever else you please) at a time within either a for loop (if you know at the beginning of reading how many lines you need) or within a while loop (if you want to stop reading when you reach EOF or a certain input).
EDIT:
Sure:
while ((line = Console.ReadLine()) != null) {
// Do whatever you want here with line
}
Some of the other answers here loop until a null line is encountered while others expect the user to type something special like "EXIT". Keep in mind that reading from the console could be either a person typing or a redirected input file:
myprog.exe < somefile.txt
In the case of redirected input Console.ReadLine() would return null when it hits the end of the file. In the case of a user running the program interactively they'd have to know to how to enter the end of file character (Ctrl+Z followed by enter or F6 followed by enter). If it is an interactive user you might need to let them know how to signal the end of input.
simple example:
class Program
{
static void Main()
{
CountLinesInFile("test.txt"); // sample input in file format
}
static long CountLinesInFile(string f)
{
long count = 0;
using (StreamReader r = new StreamReader(f))
{
string line;
while ((line = r.ReadLine()) != null)
{
count++;
}
}
return count;
}
}
The best thing to do here is use a loop:
string input;
Console.WriteLine("Input your text (type EXIT to terminate): ");
input = Console.ReadLine();
while (input.ToUpper() != "EXIT")
{
// do something with input
Console.WriteLine("Input your text(type EXIT to terminate): ");
input = Console.ReadLine();
}
Or you could do something like this:
string input;
do
{
Console.WriteLine("Input your text (type EXIT to terminate): ");
input = Console.ReadLine();
if (input.ToUpper() != "EXIT")
{
// do something with the input
}
} while (input.ToUpper() != "EXIT");

finding a line that contains… etc

Ok, well i'm basically trying to find a certain line withing "Users.txt"
Heres my code so far.
if (ok == "b" || ok == "B")
{
using (StreamWriter w = File.AppendText("Users.txt"))
{
//Test
Out.WriteLine("Please state the username");
string user = Console.ReadLine();
Out.WriteLine("Checking..");
if (w.Equals(user))
{
Out.WriteLine("Username is taken");
}
Thread.Sleep(pause);
Out.WriteLine("Please state the password for the user");
string pass = Console.ReadLine();
Logger(user, pass, w);
// Close the writer and underlying file.
w.Close();
Out.WriteLine("Checking..");
Out.WriteBlank();
Thread.Sleep(pause);
Out.WriteLine("Anything else Mr." + Environment.UserName + " ?");
}
string choice = Console.ReadLine();
if (choice == "no")
{
Boot();
}
if (choice == "yes")
{
Console.Clear();
Console.Title = "Administrator Panel";
Panel();
}
}
want it to see if the "user" is taken, then stop them from executing the process.
Thanks for the help.
Try reading (StreamReader with File.Open) each existing username into an array/List and then comparing user input against that list.
Your current code doesn't actually read anything since you're using a StreamWriter with File.AppendText which just lets you write to the end of a file.
Examples:
Reading File into a List
List<string> users = new List<string>();
using (StreamReader r = new StreamReader("Users.txt"))
{
string line;
while ((line = r.ReadLine()) != null)
{
users.Add(line);
}
}
...
string user = Console.ReadLine();
Out.WriteLine("Checking..");
if (users.Contains(user))
{
Out.WriteLine("Username is taken");
}
There are various problems with your code. Let's see if we can break it down one piece at a time.
using (StreamWriter w = File.AppendText("Users.txt"))
This code would be useful if you wanted to open "Users.txt" and append text to it. Since you want to open a file and read from it, you need to use a different object, the StreamReader object:
using (StreamReader r = File.Open("Users.txt"))
Next, you want to check if the given Username is in the file. You're doing:
if (w.Equals(user))
{
Out.WriteLine("Username is taken");
}
This isn't going to work. You are comparing a StreamWriter object with a String object. They will never be equal.
What you need to do instead is change the order of your program like this:
First, read the entire contents of the file into memory. Then, outside of the Using statement, process your user input and your username/password checking.
Let's assume the file is organized like this:
username,password
username2,password2
johnsmith,mysecretcode
janedoe,blahblah
You could, for example, read each line into a Dictionary object, where the Key is the username and the Value is the password.
Dictionary<String, String> myDictionary = new Dictionary<String, String>
// Example of adding ONE username/password to the dictionary
myDictionary.Add("username", "password");
Then, checking for the username would be as simple as
bool containsUsername = myDictionary.ContainsKey(username);
And checking the password would be:
bool doesPasswordMatch = myDictionary[username] == givenPassword;
Give it a shot! C# is a great language to learn.

Categories

Resources