fStream Check username in file - ACCOUNT Registration

Hi,

I have been messing with this so much that its so cluttered. I need a way to let get line check next line after a semi colon.

1
2
3
4
5
 
 while(!openFile.eof()){
        getline(openFile, tempUser, ';');
        if(tempUser == username){cout << "Username exsists, please select a new username: " << endl; break;}
      };


So what this does is lets say I have USERNAME;PASSWORD it simply checks username then password, instead of going to next line to check only the usernames. I have been stuck on this project for a few days now, and would really appreciate the help. Ty.

Edit: Please keep it simple, Im a beginner and want to master the basics.

My check pass is:

getline(openFile.ignore(tempUser.length,';'),tempPass);

but still do not know how to have it ignore the pass, and check next line.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void AccountManager::registerAcc(AccountManager &account){
  string username, password, tempUser, passwordConf;
  fstream openFile("UserPass.txt", ios::out | ios::in | ios::app);
  if(openFile.good()){
    do{//check if username exsists
      cout << "Type in your username: " << endl;
      getline(cin, username);
      cin.sync();
      while(!openFile.eof()){
        getline(openFile, tempUser, ';');
        if(tempUser == username){cout << "Username exsists, please select a new username: " << endl; break;}
      };
    }while(tempUser == username);
    openFile << username << ';';
    do{
      cout << "Type in a password: " << endl;
      getline(cin, password);
      cout << "Retype password: " << endl;
      getline(cin,passwordConf);
      if(password != passwordConf){cout << "Password does not match confirmation. " << endl;}
    }while(password != passwordConf);
    openFile << password << endl;
  }
  else{
    cerr << "Error Opening File!" <<endl;
    exit(1);
  }
  account.UserPass[username] = password; /// <<< if EXSISTS 
  openFile.close();
}


Mind you the purpose of the map is to confirm user/pass if file fails to open.
Last edited on
Why not preload the contents of the file?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
std::map<std::string, std::string> name_pass_map;
std::string hold("");
/* Assuming the format is
    name0;pass0
    name1;pass1
...
*/
while(std::getline(openFile, hold)){
    name_pass_map.insert(std::make_pair(
        hold.substr(0, hold.find(';')),
        hold.substr(hold.find(';')+1)
    ));
    hold.clear();
}
//...
if(name_pass_map.find(username) != name_pass_map.end())
    std::cout << "Username exists, please select a new username:\n";


Edit:
For your original question, just take a substring and ignore the password:
1
2
3
4
5
6
7
8
std::string hold("");
while(std::getline(openFile, hold)){
    if(hold.substr(0, hold.find(';') == username){
        std::cout << "Username exists, please select a new username:\n";
        break;
    }
    hold.clear();
}
Last edited on
This is a neat fix, ty.

What about checking the password? not sure on how to do a subtring for after the semi-colon.

as for :

1
2
3
 name_pass_map.insert(std::make_pair(
        hold.substr(0, hold.find(';')),
        hold.substr(hold.find(';')+1)


this is to use the map to input data onto my file? instead of
1
2
openFile << username << ';';
openFile << password << endl;


And partially the reason why I dont want a map to check is so that I can load username and password data via files.

Essentially the map is there to check user/pass if the file cannot open as an error handling.
Last edited on
The map I showed in my example is a database for data you load from the file, not to it. I did not show how to write data to your file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
std::map<std::string, std::string> name_pass_map;
std::string username;
std::string password;

//...Load data from file
std::string hold;
while(std::getline(openFile, hold)){
    name_pass_map.insert(std::make_pair(
        hold.substr(0, hold.find(';')),
        hold.substr(hold.find(';')+1)
    ));
    hold.clear();
}

//...Get username

//Check if the name already exists in the database
if(name_pass_map.find(username) != name_pass_map.end())
    cout << "Error. User already exists. Choose another name.\n";

//...Get password

name_pass_map[username] = password; //Register new user 


Also, you can look up how to use string::substr():
http://www.cplusplus.com/reference/string/string/substr/
And string::find():
http://www.cplusplus.com/reference/string/string/find/
1
2
3
4
// Let hold == "Username;Password"
 name_pass_map.insert(std::make_pair(
        hold.substr(0, hold.find(';')),  // Get "Username" substring
        hold.substr(hold.find(';')+1)  // Get "Password" substring 




And partially the reason why I dont want a map to check is so that I can load username and password data via files.

Essentially the map is there to check user/pass if the file cannot open as an error handling.

I apologize, but I don't really understand what you're trying to achieve. Are you saying you want to check the usernames as you're reading the file? Versus loading everything to a database first before checking?
You can do it, but I suggested preloading because I thought you were going to do something else with the map (like inserting the new username and password in the same database).

Let me try to guess what you're doing:
- Use a file as a source of usernames and passwords to check from
- If the file cannot be opened, default to a member map that also contains a list of usernames and passwords?
- Whether the file could be opened or not, always register the new user in the member map?
You guessed it right :P

I have not had the chance to test your code, will mess around with it tomorrow and let u know how it goes.

ty

EDIT:

Ok srry i took a while, the concept of make_pair is new to me:

1
2
3
4
5
6
7
8
  std::string hold;
  while(std::getline(openFile, hold)){
    account.UserPass.insert(std::make_pair(
      hold.substr(0, hold.find(';')),
      hold.substr(hold.find(';')+1)
      ));
    hold.clear();
  }


Make pair is basically the same as doing UserPass[username] = password, but ur chopping it up via strings correct? (im new to strings, etc)

This has been my current fix:

1
2
3
4
5
6
7
      while(!openFile.eof()){
        getline(openFile, tempUser, ';');
        getline(openFile, tempPass);
        if((tempUser == username)&&(tempPass == password)){
            wrongUser = 1;
            cout << "Thank you for logging in. " << endl;
            switchLog(account);


I was reading username only before, so it was reading the password instead of going to new line, I was told to include both getline's as such so it goes to the new line.

All in all your fix is closer to what I'm trying to do with error handling (will prob run it at beginning of program to eliminate any future errors with file handling. (To ensure the map is pre-loaded).

Lmk,
Last edited on
Hi,

Now my new problem is that it will not write to file via function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void AccountManager::registerAcc(AccountManager &account){
  string username, password, tempUser, passwordConf, tempHold;
  fstream openFile("UserPass.txt", ios::out | ios::in | ios::app);
  if(openFile.good()){
    do{//check if username exsists
      cout << "Type in your username: " << endl;
      getline(cin, username);
      while(!openFile.eof()){
        getline(openFile, tempUser, ';');
        getline(openFile, tempHold);
        if(tempUser == username){cout << "Username exsists, please select a new username: " << endl; openFile.seekg(0, ios::beg); break;}
      };
    }while(tempUser == username);
    openFile << username << ';'; // Not writing to file
    do{
      cout << "Type in a password: " << endl;
      getline(cin, password);
      cout << "Retype password: " << endl;
      getline(cin,passwordConf);
      if(password != passwordConf){cout << "Password does not match confirmation. " << endl;}
    }while(password != passwordConf);
    openFile << password << endl; // Not writing to file
  }
  else{
    cerr << "Error Accessing Data!" <<endl;
    exit(1);
  }
  account.UserPass[username] = password; /// <<< in case file fails to open its loaded onto backup map
  openFile.close();
}


fstream objects keep an internal pointer to keep track of where they are in the file. What you can do is reset the position of the pointer.

 
openFile.seekg(0); //Moves the get pointer to the beginning of the file 


You can try it out with this test program:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <string>
#include <fstream>


int main(){
    using namespace std;

    fstream file("InOut.txt", ios_base::in | ios_base::out | ios_base::app);

    string hold;
    file << "def";
    file.seekg(0);
    file >> hold;
    cout << hold;
    file.seekg(0);
    file << (hold+hold);
    file.close();

    return 0;
}


I wish I could explain more on why you need to do this, but I'm not sure about the details.

And perhaps the more experienced programmers can explain why this works resetting the get pointer only and not the put pointer.
Last edited on
Simpler if we first open the file for input, perform the duplicate check, and then close it and reopen it for output/append.

Something along these lines:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// this is a static member function of AccountManager, presumably
// why is it static?
// why not a non-static AccountManager::registerAcc()?
void AccountManager::registerAcc(AccountManager &account){

      const char DELIMITER = ';' ;
      string username ;
      cout << "Type in your username: " ;
      getline(cin, username);

      //check if username exsists
      {
          ifstream openFile("UserPass.txt") ; // open for input
          string tempUser, tempHold ;
          while( getline(openFile, tempUser, DELIMITER ) && getline(openFile, tempHold ) )
          {
              if( tempUser == username )
              {
                  cout << "Username exsists, please select a new username: " ;
                  openFile.seekg(0, ios::beg) ;
                  getline(cin, username);
              }

              // TODO: verify that username is not empty and does not contain the DELIMITER
          }
      }

      // accept password
      string password, passwordConf ;
      do{

      cout << "Type in a password: " << endl;
      getline(cin, password);
      cout << "Retype password: " << endl;
      getline(cin,passwordConf);

      if(password != passwordConf) cout << "Password does not match confirmation.\n" ;

      } while(password != passwordConf);

      // append username, password to file
      {
          ofstream openFile( "UserPass.txt", ios::app ); // open for output, append
          openFile << username << DELIMITER << password << '\n' ;
      }

      account.UserPass[username] = password; /// <<< if EXSISTS  
}
But why should I need to closeit and reopen it when :

fstream openFile ( "UserPass.txt", ios::out | ios::in | ios::app );

should already be doing that for us, (i like how you formatted it though, will steal it :) )

As for Daleth I ended up going with this piece of code:

openFile.seekg ( 0, ios::beg );

Thank you guys again, truly great help.

EDIT:

Borges, whats the benefit of doing while(getline) vs while(!eof)

Also not sure what you mean by static? in terms of &acc or?

yours seems clean and simple,
Last edited on
Topic archived. No new replies allowed.