Click here to Skip to main content
15,881,803 members
Please Sign up or sign in to vote.
1.50/5 (2 votes)
See more:
I'm having issues with a C# Winforms file IO. The code complies just fine, but then it returns errors on execution.

The output code is here:

C#
private void saveData()
       {
           string fullPath = System.Environment.GetEnvironmentVariable(@"%MyDocuments%\HellsingRPG\");

           StreamWriter writer = new StreamWriter(fullPath + textBox2.Text + ".txt");
           writer.WriteLine(textBox1.Text + "," + textBox2.Text + "," + textBox3.Text + "," + textBox4.Text + "," + comboBox1.SelectedText + "," +
               numericUpDown25.Value + "," + numericUpDown1.Value + "," + numericUpDown2.Value + "," + numericUpDown3.Value + "," + numericUpDown4.Value + "," +
               numericUpDown5.Value + "," + numericUpDown6.Value + "," + numericUpDown7.Value + "," + numericUpDown8.Value + "," + numericUpDown9.Value + "," +
               numericUpDown10.Value + "," + numericUpDown11.Value + "," + numericUpDown12.Value + "," + numericUpDown13.Value + "," + numericUpDown14.Value
               + "," + numericUpDown15.Value + "," + numericUpDown16.Value + "," + numericUpDown17.Value + "," + numericUpDown18.Value + "," +
               numericUpDown19.Value + "," + numericUpDown20.Value + "," + numericUpDown21.Value + "," + numericUpDown22.Value);
           writer.Close();
       }


And the code to load the data is here:

C#
private void loadData()
       {
           Stream myStream = null;
           OpenFileDialog openFileDialog1 = new OpenFileDialog();

           openFileDialog1.InitialDirectory = System.Environment.GetEnvironmentVariable(@"%MyDocuments%\HellsingRPG\");
           openFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
           openFileDialog1.FilterIndex = 2;
           openFileDialog1.RestoreDirectory = true;

           if (openFileDialog1.ShowDialog() == DialogResult.OK)
           {
               try
               {
                   if ((myStream = openFileDialog1.OpenFile()) != null)
                   {
                       using (myStream)
                       {
                           List<string> myData = parseCSV(System.Convert.ToString(myStream));
                           textBox1.Text = myData[0];
                           textBox2.Text = myData[1];  // here is the mistake
                           textBox3.Text = myData[3];   // <-----
                           textBox4.Text = myData[4];
                           comboBox1.SelectedText = myData[5];
                           numericUpDown25.Value = System.Convert.ToDecimal(myData[6]);
                           numericUpDown1.Value = System.Convert.ToDecimal(myData[7]);
                           numericUpDown2.Value = System.Convert.ToDecimal(myData[8]);
                           numericUpDown3.Value = System.Convert.ToDecimal(myData[9]);
                           numericUpDown4.Value = System.Convert.ToDecimal(myData[10]);
                           numericUpDown5.Value = System.Convert.ToDecimal(myData[11]);
                           numericUpDown6.Value = System.Convert.ToDecimal(myData[12]);
                           numericUpDown7.Value = System.Convert.ToDecimal(myData[13]);
                           numericUpDown8.Value = System.Convert.ToDecimal(myData[14]);
                           numericUpDown9.Value = System.Convert.ToDecimal(myData[15]);
                           numericUpDown10.Value = System.Convert.ToDecimal(myData[16]);
                           numericUpDown11.Value = System.Convert.ToDecimal(myData[17]);
                           numericUpDown12.Value = System.Convert.ToDecimal(myData[18]);
                           numericUpDown13.Value = System.Convert.ToDecimal(myData[19]);
                           numericUpDown14.Value = System.Convert.ToDecimal(myData[20]);
                           numericUpDown15.Value = System.Convert.ToDecimal(myData[21]);
                           numericUpDown16.Value = System.Convert.ToDecimal(myData[22]);
                           numericUpDown17.Value = System.Convert.ToDecimal(myData[23]);
                           numericUpDown18.Value = System.Convert.ToDecimal(myData[24]);
                           numericUpDown19.Value = System.Convert.ToDecimal(myData[25]);
                           numericUpDown20.Value = System.Convert.ToDecimal(myData[26]);
                           numericUpDown21.Value = System.Convert.ToDecimal(myData[27]);
                           numericUpDown22.Value = System.Convert.ToDecimal(myData[28]);
                       }
                   }
               }
               catch (Exception ex)
               {
                   MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
               }
           }
       }


And the parsing code is here:

C#
public System.Collections.Generic.List<string> parseCSV(string path)
        {
            System.Collections.Generic.List<string> parsedData = new System.Collections.Generic.List<string>();

            try
            {
                using (StreamReader readFile = new StreamReader(path))
                {
                    string line;
                    string[] row;

                    while ((line = readFile.ReadLine()) != null)
                    {
                        row = line.Split(',');
                        parsedData.Add(System.Convert.ToString(row));
                    }
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }

            return parsedData;
        }


And that compiles just fine. It runs as an executable. I can save the file without incident. But when I open the file I just saved, I get the following errors:

"Could not find file "C:\Users\collmark\Documents\Visual Studio 2015\Projects\WindowsFormsApplication1\WindowsFormsApplication1\bin\Release\System.IO.Filestream".

"Error: Could not read file from disk. Original error: Index out of range. Must be non-negative and less than the size of the collection. Parameter name: index."

Any ideas what I could be doing wrong? I'm a new/self taught c# users.
Posted
Updated 30-Jul-15 9:09am
v2
Comments
[no name] 30-Jul-15 14:25pm    
Debug your code and find out where the error is coming from. It's probably in the midst of all that getting values from myData. You should be using TryParse instead of the Convert class though.
Mark Anthony Collins 30-Jul-15 14:34pm    
The debugger doesn't return any errors. It just compiles. And I can run it just fine. Are you referring to " public System.Collections.Generic.List<string> parseCSV(string path)"
[no name] 30-Jul-15 14:57pm    
So you need to learn to use the debugger. The compiler is not the same as the debugger. Have no idea what you think that parseCSV method has anything to do with what I said.

The problem is the path you're passing to the parseCSV method:
C#
parseCSV(System.Convert.ToString(myStream))

Convert.ToString will call the ToString method on the object you passed in. Since Stream doesn't override that method, this will call the ToString method defined on the object class, which simply returns the type name - System.IO.FileStream.

You then pass that string to the StreamReader constructor, which is expecting a file path. Since it's not a fully qualified file path, the string you've passed in will be combined with the current working directory - C:\Users\collmark\Documents\Visual Studio 2015\Projects\WindowsFormsApplication1\WindowsFormsApplication1\bin\Release\ - to create the full path of the file to open.

Since there isn't a file in the path C:\Users\collmark\Documents\Visual Studio 2015\Projects\WindowsFormsApplication1\WindowsFormsApplication1\bin\Release\System.IO.FileStream, you then get a FileNotFoundException.

You should pass the Stream to the parseCSV method, and pass that on to the StreamReader constructor which accepts a Stream argument.

You'll also need to change how the parseCSV method works. With the current code, it would return a list of string values, one per row of the file, where each string would be "System.String[]". Instead, you need to return a list of string arrays, where each array represents a single row, and the elements of the array represent the values.

Something like this:
C#
public List<string[]> parseCSV(Stream fileStream)
{
    using (StreamReader readFile = new StreamReader(fileStream))
    {
        List<string[]> parsedData = new List<string[]>();

        string line;
        string[] row;
        while ((line = readFile.ReadLine()) != null)
        {
            row = line.Split(',');
            parsedData.Add(row);
        }

        return row;
    }
}

private void loadData()
{
    OpenFileDialog openFileDialog1 = new OpenFileDialog();
    openFileDialog1.InitialDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "HellsingRPG");
    openFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
    openFileDialog1.FilterIndex = 2;
    openFileDialog1.RestoreDirectory = true;
    
    if (openFileDialog1.ShowDialog() == DialogResult.OK)
    {
        try
        {
            using (Stream myStream = openFileDialog1.OpenFile())
            {
                if (myStream != null)
                {
                    List<string[]> myData = parseCSV(myStream);
                    if (myData.Count != 0)
                    {
                        string[] firstRow = myData[0];
                        if (firstRow.Length >= 29)
                        {
                            textBox1.Text = myData[0];
                            ...
                            numericUpDown22.Value = Convert.ToDecimal(myData[28]);
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.ToString());
        }
    }
}


NB: Environment.GetEnvironmentVariable(@"%MyDocuments%\HellsingRPG\") will always return null, as there is no environment variable with that name. Either use the ExpandEnvironmentVariables method, or a combination of the Environment.GetFolderPath and Path.Combine methods.

NB 2: The Convert.ToDecimal lines will fail if the value read from the file isn't a valid number. You should consider using the decimal.TryParse method[^] instead.

NB 3: Whilst this simple parser should work with the file that you've created, real CSV files can be much more complicated. For example, field values can contain commas, quotes, and new-lines. There are lots of ready-made libraries to handle this for you - for example, CsvHelper[^].
 
Share this answer
 
v2
Comments
Mark Anthony Collins 30-Jul-15 15:13pm    
Awesome this is the information I've been looking for! You guys are so much more helpful than StackOverflow. I'll work on these changes.
Wendelius 30-Jul-15 15:17pm    
Nice answer, 5
parseCSV(System.Convert.ToString(myStream))

I don't think you want to be turning your Stream into a String.


And you definitely need to learn not to use Convert.
 
Share this answer
 
Comments
Richard Deeming 30-Jul-15 15:01pm    
Beat me by two minutes, but I was busy typing! :)
Wendelius 30-Jul-15 15:18pm    
Good catch, 5
Mark Anthony Collins 30-Jul-15 15:23pm    
I will take all the tips I can get. Got halfway through a programming degree in 1997 and trying to get back into it.
If I'm not mistaken, you write 22 28 fields/columns to the CSV file but when you read, you expect to find 29 elements in the array parsed from the CSV. SO either you write too few columns or read too many.
 
Share this answer
 
v2
Comments
Mark Anthony Collins 30-Jul-15 14:37pm    
I write out 28 elements, textBox 1-4, comboBox1, numericUpDown25, and then numericUpDowns 1 - 22. I then read in the exact same elements. I write out 28 elements and then read in 28 elements.
Wendelius 30-Jul-15 14:48pm    
Sorry, I thought that the numbers were unique. But still you have a mismatch. You write 28 elements and in your array you expect to find 29 elements.
Mark Anthony Collins 30-Jul-15 14:51pm    
My bad. I'm importing and exporting 29 objects... I've quintiple checked that I'm exporting and importing the exact same items. I forgot that the list started at 0. But there is no mismatch. I know the code isn't the easiest to read.
Wendelius 30-Jul-15 14:56pm    
If you place a breakpoint on the line

row = line.Split(',');

and execute it and with debugger have a look at the size of the array, how many elements you have? No matter how many times I count the commas in your writer.WriteLine I always end up to 27 which means that when you split the row you'd have 28 elements (0-27) and based on that

numericUpDown22.Value = System.Convert.ToDecimal(myData[28]);

would cause an exception.
Ralf Meier 30-Jul-15 15:06pm    
@Mika:
I found the mistake :
You are right with the count of elements. He reads myData 0,1,3,4 ...
He misses the 2 and indexes the following elements wrong.(I marked it in the code)

@Mark Anthony:
Could you follow what I mean ?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900