Jason94
Jason94

Reputation: 13620

Trying to open a file, wrong format?

Im trying to open a file. Here is my output (string i build up in try/catch):

Error opening c:\Program Files (x86)\MyApp\storedUsers.txt -> System.FormatException -> Input string was not in a correct format.

And here is how im opening it:

installPath = @"C:\Program Files (x86)\MyApp\";
FileStream userFile = new FileStream(installPath + "storedUsers.txt", FileMode.OpenOrCreate, FileAccess.Read);
StreamReader userStream = new StreamReader(userFile);
while (userStream.Peek() >= 0)
{
string line = userStream.ReadLine();
storedUsers.Add(line.Split(',')[0], int.Parse(line.Split(',')[0]));
}
userStream.Close();

My catch:

WriteToLogFile("Error opening " + installPath + "storedUsers.txt -> " + ex.GetType() + " -> " + ex.Message);

I cant wrap my head around whats wrong...

Upvotes: 1

Views: 871

Answers (2)

Nayan
Nayan

Reputation: 3224

I think you should start with a checklist (or test cases), like:

  1. Does the file exist? I am assuming here - yes.

  2. Am I opening the file to read or write? If only read, then don't use FileMode.OpenOrCreate, but FileMode.Open.

  3. What does string line contain?

    a) Is it blank?

4) What is the result of Split function call?

a) Is it null?

b) Are you accepting empty entries in this array?

c) Are there entries more than 0?

Then, avoid repeating code, if possible.

//Pseudo-code + C#
string line = userStream.ReadLine();
string[] arr = line.Split(','); //called once
if (arr.Length > 0 && arr[0].Trim().Length > 0) storedUsers.Add(arr[0], int.Parse(arr[0]));
//you can put extra checks.

Upvotes: 0

Lasse V. Karlsen
Lasse V. Karlsen

Reputation: 391634

I'm going to hazard a guess here, since you haven't given us enough to really give you a solid answer.

I bet the problem is the parsing of that line part, this expression:

int.Parse(line.Split(',')[0])

That this doesn't, in all cases, actually give you a number.

So you should look at the file, and possibly change the code to this:

string[] parts = line.Split(',');
... int.Parse(parts[0]) ...

Then you can inspect the contents of that array to see what is really in that first column.

As noted in the comments, a better approach would be to not blindly assume the parsing will succeed, and additionally you would probably want to ensure you're using the right cultural information.

Here's what I would do, assuming the numbers are output by a program, for reading into another program:

int value;
if (Int32.TryParse(parts[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
    ... your code here, use value where you need it
else
    what to do in the case of unable to parse the string as a number

On a hunch, do you need to trim the contents? Try this simple change:

... int.Parse(line.Split(',')[0].Trim()) ...
                                ^--+--^
                                   |
                                   +-- add this

Other tips:

  • Use Path.Combine to combine paths:

    new FileStream(Path.Combine(installPath, "storedUsers.txt")
    
  • Rewrite your reading loop to this:

    string line;
    while ((line = userStream.ReadLine()) != null)
    {
        ...
    }
    
  • Use the using clause for disposing of your stream:

    using (FileStream userFile = new FileStream(...))
    {
        ...
    }
    // delete the .Close() line, this is handled by the } on the preceeding line
    

Final version:

installPath = @"C:\Program Files (x86)\MyApp\";
using (FileStream userFile = new FileStream(
    Path.Combine(installPath, "storedUsers.txt"),
    FileMode.OpenOrCreate, FileAccess.Read))
using (StreamReader userStream = new StreamReader(userFile))
{
    string line;
    while ((line = userStream.ReadLine()) != null)
    {
        string[] parts = line.Split(',');
        int userId;
        if (Int32.TryParse(parts[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out userId))
            storedUsers.Add(userId);
    }
}

Of course, if the file isn't too big, you can rewrite the whole shebang using a bit of LINQ:

// warning, LINQ with side-effects, evaluate here, don't use it lazily
int tempUserId = 0;
List<int> userIds = File
    .ReadAllLines(Path.Combine(installPath, "storedUsers.txt"))
    .Select(l => l.Split(',')[0])
    .Where(p0 => Int32.TryParse(p0, NumberStyles.Integer, CultureInfo.InvariantCulture, out tempUserId))
    .Select(dummy => tempUserId)
    .ToList();

Upvotes: 5

Related Questions