Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# reading a file

Tags:

c#

io

I've got two functions:

    public void SaveMap()
    {
        StreamWriter stream = new StreamWriter("file.txt");
        for (int j = 0; j < GameConstants.MapMaxTilesX; j++)
        {
            for (int i = 0; i < GameConstants.MapMaxTilesY; i++)
            {
                stream.Write( map[j,i] );
            }
        }
        stream.Close();
    }

    public void LoadMap()
    {
        StreamReader stream = new StreamReader("file.txt");
        for (int j = 0; j < GameConstants.MapMaxTilesX; j++)
        {
            for (int i = 0; i < GameConstants.MapMaxTilesY; i++)
            {
                map[j, i] = (int)stream.Read();
            }
        }
        stream.Close();
    }

And as it saves data properly, it doesn't read it. Random values are being read ( at least not those which are in file )

What did I wrong?

like image 884
Neomex Avatar asked Dec 04 '25 14:12

Neomex


2 Answers

Even though the StreamReader.Read() method returns an int, it doesn't read an int from the file. Instead it returns a single character. The reason the type is an int is so it can flag the end-of-file condition with a -1. This is a holdover from the old C style of doing things.

If you wanted to read characters from a file, you could call Read() and test the return value against -1. If something other than -1 is returned, then cast that to a char. Then you would be responsible for putting the characters together in a meaningful way. But there are much easier ways to do what you are trying to accomplish!

To do what you want to do, you will either have to delimit your integer values in some way, and then parse the strings in the file, or use a BinaryWriter/BinaryReader instead.

Perhaps the easiest way to do this is to put one value per line like this:

...
stream.WriteLine( map[j,i] );
...
map[j, i] = int.Parse(stream.ReadLine());

If you want to minimize the file size, then I recommend writing each int with a BinaryWriter, and then reading the values with the BinaryReader.ReadInt32() method. If you do that, then the file will be exactly 4 * GameConstants.MapMaxTilesX * GameConstants.MapMaxTilesY bytes long.

Another fun way to do this would be to write each row of your map on its own line, and separate each column with a tab character '\t'. Then you could read the values back a line at a time and use string.Split to separate the values on each line. The advantage of this approach is that you can edit the file in a spreadsheet program or text editor.

like image 84
Jeffrey L Whitledge Avatar answered Dec 07 '25 04:12

Jeffrey L Whitledge


When reading values from a stream byte by byte, the Stream.Read() returns the ASCII code of the current caracter so you first need to convert it to a regular char and then parse it as a int. So instead of doing:

map[j, i] = (int)stream.Read();

You need to do:

char c = (char)stream.Read();
map[j, i] = Int32.Parse(c.ToString());

And that should do the trick.

like image 41
Ucodia Avatar answered Dec 07 '25 02:12

Ucodia