4

see comments for resolution--file was in wrong place

I've searched for an answer all over the place, but I haven't been able to find one. This is really frustrating to me because I've never had this much trouble reading from a file with any other programming language.

I'm trying to extract usernames and passwords from a text file for a basic instant messaging program. I'm not going to post all the code--it's too long, and it more than likely isn't relevant since the text file is being read at the very beginning of the program.

Here's the contents of the text file ("users.ul") I'm trying to read from:

admin.password
billy.bob
sally.sal

Here is the code that reads from the text file:

users = new Dictionary<string, User>();

System.Console.WriteLine("users.ul exists: " + File.Exists("users.ul"));

// Check the status of users.ul. If it exists, fill the user dictionary with its data.
if (File.Exists("users.ul"))
{
    // Usernames are listed first in users.ul, and are followed by a period and then the password associated with that username.
    StreamReader reader = new StreamReader("users.ul");
    string line;
    int count = 0;

    while ((line = reader.ReadLine()) != null)
    {
        string[] splitted = line.Split('.');
        string un = splitted[0].Trim();
        string pass = splitted[1].Trim();

        User u = new User(un, pass);

        // Add the username and User object to the dictionary
        users.Add(un, u);

        count++;
    }

    System.Console.WriteLine("count: " + count);

    reader.Close();
}

This is the output my code produces:

users.ul exists: True
count: 1

The only data added to the users dictionary is "admin" with the password "password". The other lines are ignored.

Please help me out here. My program is useless without multiple users. I've looked everywhere for a solution, including the other similar questions on this site. Never thought that reading from a file would cause me to waste so much time.

puretppc
  • 3,232
  • 8
  • 38
  • 65
Steve Schmith
  • 43
  • 1
  • 1
  • 4
  • 1
    @DGibbs there is a `while` around it, it's okay! – bash.d Mar 15 '13 at 21:46
  • 3
    Have you examined your program in a debugger? Looks like a Debugging issue to me... Apart from that, if not explicitly disposing your `StreamReader` use `using`-statement – bash.d Mar 15 '13 at 21:47
  • You should enclose `StreamReader reader = new StreamReader("users.ul");` in a `using` statement however, that small change shouldn't fix things. Your problem is likely with the file. Reading a file in C# is not difficult and aside form the lack of `using` statement you're code is good. – evanmcdonnal Mar 15 '13 at 21:50
  • 4
    My guess would be that "users.ul" contains a *different* "new line" separator than expected - perhaps ReadLine really reads the *entire* file in this case? –  Mar 15 '13 at 21:50
  • 4
    the file wasn't created on a non-MS system was it? ReadLine requires that the line end with CRLF, but many systems use just an LF. if thats the case, then you code would read the whole file as one line, but your split and trim would ignore everything past the first two tokens. check the count of splitted to see if it has too many tokens. – Frank Thomas Mar 15 '13 at 21:51
  • 1
    A simple Console.WriteLine(line) just inside the loop would help you tremendously here. – Steve Mar 15 '13 at 21:54
  • 1
    @FrankThomas [It should work fine for \n, \r, \r\n](http://msdn.microsoft.com/en-us/library/system.io.streamreader.readline.aspx), "A line is defined as a sequence of characters followed by a line feed ("\n"), a carriage return ("\r"), or a carriage return immediately followed by a line feed ("\r\n"). The string that is returned does not contain the terminating carriage return or line feed. The returned value is null if the end of the input stream is reached.". Now `\v` or `\l` might be problematic .. –  Mar 15 '13 at 21:55
  • 3
    Thanks for the help everyone, but it was my fault the code didn't work, not the language's. I had an older version of users.ul in the /bin/Release folder, instead of the newer, longer one, which was in the source folder. Obviously my program was reading from the old file in the bin folder... which only had the "admin.password" line in it. Gotta love it when you waste a ton of time over a stupid mistake. – Steve Schmith Mar 15 '13 at 21:56
  • glad you got it working – Frank Thomas Mar 15 '13 at 21:56

2 Answers2

10

Unless you have a specific need to go through the rigmarole of using StreamReader, I suggest using File.ReadAllLines(), which returns an (enumerable) string array.

Better yet, use linq :-)

System.Console.WriteLine("users.ul exists: " + File.Exists("users.ul"));

// Check the status of users.ul. If it exists, fill the user dictionary with its data.
if (File.Exists("users.ul")) {
    var lines = File.ReadAllLines("users.ul");
    // Usernames are listed first in users.ul, and are followed by a period
    // and then the password associated with that username.
    var users = lines.Select(o => o.Split('.'))
                     .Where(o => o.Length == 2)
                     .Select(o => new User(o[0].Trim(), o[1].Trim());

    System.Console.WriteLine("count: " + users.Count());
}
theMayer
  • 15,456
  • 7
  • 58
  • 90
  • 1
    See my comment above. I had the file in the wrong place. I'll just pick this answer so we don't have to wait 8 hours to close the question. Thanks for the help! I'll probably start using the File methods instead--I'm new to C#. – Steve Schmith Mar 15 '13 at 21:58
  • I wonder why Linq here is "even better". I understand your Linq query only by reading the comment. But I could understand the OP's code as is. Case of shiny object syndrome? – Sebastian Mach Sep 13 '17 at 14:03
  • The beauty of Linq is the compact syntax. When you are familiar with it and use it, there is nothing mysterious or confusing about the code. In fact, it's a lot easier to see what is going on than reading a whole bunch of `while` loops. – theMayer Sep 18 '17 at 21:20
5

Just couldn't resist the temptation to refactor this into a one-liner:

var users = File.ReadAllLines("users.ul").Select(l => new User(l.Substring(0, l.IndexOf('.')), l.Substring(l.IndexOf('.') + 1))).ToDictionary(u => u.Name);
Alexander Tsvetkov
  • 1,649
  • 14
  • 24