TextReader.Read() not returning correct integer?

158 views Asked by At

So my method should in theory work, I'm just not getting my expected result back.

I have a function that creates a new TextReader class, reads in a character (int) from my text file and adds it too a list.

The textfile data looks like the following (48 x 30):

111111111111111111111111111111111111111111111111 111111111111111111111111111111111111111111111111 111111111111100000000001111111111000000111111111 111111110000000000000000000000000000000011111111 100000000000000000000000000000000000000001111111 000000000000001111111111111111111111000001111111 100000001111111111111111111112211221000001111111 100000111111122112211221122111111111000001111111 111111111221111111111111111112211110000011111111 111112211111111111111111111111111100000111221111 122111111111111122111100000000000000001111111111 111111111111111111100000000000000000011111111111 111111111111111111000000000000000001112211111111 111111111111221110000001111110000111111111111111 111111111111111100000111112211111122111111111111 111111112211110000001122111111221111111111111111 111122111111000000011111111111111111112211221111 111111110000000011111111112211111111111111111111 111111000000001111221111111111221122111100000011 111111000000011111111111000001111111110000000001 111111100000112211111100000000000000000000000001 111111110000111111100000000000000000000000000011 111111111000011100000000000000000000000011111111 111111111100000000000000111111111110001111111111 111111111110000000000011111111111111111111111111 111111111111100000111111111111111111111111111111 111111111111111111111111111111111111111111111111 111111111111111111111111111111111111111111111111 111111111111111111111111111111111111111111111111 111111111111111111111111111111111111111111111111

My method is as follows:

private void LoadReferenceMap(string FileName)
    {
        FileName = Path.Combine(Environment.CurrentDirectory, FileName);
        List<int> ArrayMapValues = new List<int>();

            if (File.Exists(FileName))
            {
                // Create a new stream to write to the file
                using (TextReader reader = File.OpenText(FileName))
                {
                    for (int i = 0; i < 48; i++)
                    {
                        for (int j = 0; j < 30; j++)
                        {
                            int x = reader.Read();

                            if (x == -1)
                                break;

                            ArrayMapValues.Add(x);
                        }
                    }
                }

                level.SetFieldMap(ArrayMapValues);
            }
    }

Returns:

enter image description here

As you can see once it reaches the end of the first line Read() returns 13 and then 10 before moving on to the next row?

3

There are 3 answers

4
Steve On BEST ANSWER

A different approach that removes both problems with conversion of chars to integers and the skipping of Environment.NewLine characters

private void LoadReferenceMap(string FileName)
{
    List<int> ArrayMapValues = new List<int>();

    if (File.Exists(FileName))
    {
        foreach(string line in File.ReadLines(FileName))
        {
            var lineMap = line.ToCharArray()
                              .Select(x => Convert.ToInt32(x.ToString()));
            ArrayMapValues.AddRange(lineMap);
        }
        level.SetFieldMap(ArrayMapValues);
    }
}

The file is small, so it seems to be convenient to read a line as a string (this removes the Environment.NewLine), process the line converting it to a char array and applying the conversion to integer for each char. Finally the List of integers of a single line could be added to your List of integers for all the file.

I have not inserted any check on the length of a single line (48 chars) and the total number of lines (30) because you say that every file has this format. However, adding a small check on the total lines loaded and their lengths, should be pretty simple.

0
VMAtm On

This is because you need to convert the symbol you've got to the char, like this:

(char)sr.Read();

After that you can parse it as int with different approach, for example:

int.Parse(((char)sr.Read()).ToString());

More information on MSDN.

As you can see once it reaches the end of the first line Read() returns 13 and then 10 before moving on to the next row?

The line break in the .NET looks like this: \r\n, and not the \n (Check the Environment.NewLine property.

2
Chris On

The actual text file has line breaks in it. This means that once you have read the first 48 characters the next thing in the file is a line break. In this case it is a standard windows new line which is a Carriage Return (character 13) followed by a Line Feed (character 10).

You need to deal with these line breaks in your code somehow. My preferred way of doing this would be the method outlined by Steve above (using File.ReadAllLines). You could alternatively though just at the end of each of your sets of 48 character reads check for the 13/10 character combo. One thing of note though is that some systems just use Line Feed without the carriage return to indicate new lines. Depending on the source of these files you may need to code something to deal with possible different line breaks. Using ReadAllLines will let something else deal with this issue though as would using reader.ReadLine()

If you are also unsure why it is returning 49 instead of 1 then you need to understand about character encoding. The file is stored as bytes which are interpreted by the reading program. In this case you are reading out the values of the characters as integers (which is how .NET stores them internally). You need to convert this to a character. In this case you can just cast to char (ie (char)x). This will then return a char which is '1'. If you want this as an integer you would then need to use Integer.Parse to parse from text into an integer.