• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[C#] Problem with StreamReader

Status
Not open for further replies.

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,219
hi. I am and a irl friend made a little coding project. We save data in a file with the StreamReader/StreamWrite. However we ran into a little issue. The code is working but we know we are doing one thing wrong.

we currently use

JASS:
StreamReader file = new System.IO.StreamReader(file1);

however we save data at 3 different places in the code. And since we lose the file we need to create a new variable each time. How can we change that?
 
Can you explain a little bit more or provide some more code (mostly the parts where you save the data and create the variable each time)? I don't fully understand your problem.

By save data, do you mean writing to the file? And is it 3 different places within the same method? Or is it at 3 different places in different methods?
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,219
its in the same method but not at the same place. First I read some data at the start and then I modify some data in the middle.

this is for example in the middle
JASS:
                        StreamReader data = new System.IO.StreamReader(file1);
                        SPengar = data.ReadLine();
                        SPengar = data.ReadLine();
                        SPengar = data.ReadLine();

and this is at the start

JASS:
                StreamReader file = new System.IO.StreamReader(file1);
                username = file.ReadLine();

this is toally wrong but im a newbie to c# so I dont know how to improve it. Waiting with closing the file gotta be bad right
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
How is that even going to give you correct results to begin with?
You are opening the same file for read operations, and then read data from the start, except for some reason you expect that data to be a continuation of previously read data...which will work fine if you don't open it again for no reason.

In your example, the first time you read into SPengar, SPengar is equal to username.

This is most likely not the behavior you wanted (and even if it was, there is no reason to close and reopen the file).

Simply open the file, read all the data you want, and close it when you finished reading data.

I am referring to closing the file, but unless you just didn't copy those lines, you are also not doing this at all.
After you finish reading from your file, you should call the Close() method of your stream reader.
If you don't do that, the file is never closed, which can result in unwanted behavior.
 
School example
JASS:
using System;
using System.IO;

namespace FileIOApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            FileStream F = new FileStream("test.dat", 
            FileMode.OpenOrCreate, FileAccess.ReadWrite);

            for (int i = 1; i <= 20; i++)
            {
                F.WriteByte((byte)i);
            }

            F.Position = 0;

            for (int i = 0; i <= 20; i++)
            {
                Console.Write(F.ReadByte() + " ");
            }
            F.Close();
            Console.ReadKey();
        }
    }
}
 
its in the same method but not at the same place. First I read some data at the start and then I modify some data in the middle.

this is for example in the middle
JASS:
                        StreamReader data = new System.IO.StreamReader(file1);
                        SPengar = data.ReadLine();
                        SPengar = data.ReadLine();
                        SPengar = data.ReadLine();

and this is at the start

JASS:
                StreamReader file = new System.IO.StreamReader(file1);
                username = file.ReadLine();

this is toally wrong but im a newbie to c# so I dont know how to improve it. Waiting with closing the file gotta be bad right

I don't see you editing any data in the middle here, all of it is just reading...

btw, what are you actually trying to achieve?
 
How is that even going to give you correct results to begin with?
You are opening the same file for read operations, and then read data from the start, except for some reason you expect that data to be a continuation of previously read data...which will work fine if you don't open it again for no reason.

In your example, the first time you read into SPengar, SPengar is equal to username.

This is most likely not the behavior you wanted (and even if it was, there is no reason to close and reopen the file).

Simply open the file, read all the data you want, and close it when you finished reading data.

I am referring to closing the file, but unless you just didn't copy those lines, you are also not doing this at all.
After you finish reading from your file, you should call the Close() method of your stream reader.
If you don't do that, the file is never closed, which can result in unwanted behavior.

In my opinion, if the filesize is small, you can just go with dumping the entire contents of the file onto a string array using String.Split('\n')
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,258
In my opinion, if the filesize is small, you can just go with dumping the entire contents of the file onto a string array using String.Split('\n')
Only if you are using a text file that you need to keep as text. Otherwise it is far more efficient to do either of the following.

1. Read the entire file into a buffer if it is small. The buffer may be bigger than the file and is preferably recycled between I/O operations. For larger files you read part of the file into a buffer and then use what you want from that buffer.
2. If the file data is directly accessible then memory map the file into memory. This turns the file into a buffer automatically and can really take advantage of the operating system file cache. Due to process address space limitations you may want to map only the parts you need from larger files.

Go with 1 if you plan to read data sequentially, need the process to be real-time safe, need to process the data before use (eg compressed data).
Go with 2 if you plan to read data randomly, require continuous I/O operations, require multiple processes/threads working on the same files, data is stored in native form and directly usable (caches).
 
Level 15
Joined
Oct 18, 2008
Messages
1,591
Okay how about posting some of the actual code so we can actually see what you are doing? :)

If I get you right, you need the 3rd line for SPengar and the 1st line for the username right? If so, load all the data into a struct if it's only this much:

C#:
public struct MyStruct
{
     public string SPengar;
     public string Line2;
     public string Username;
}

C#:
public MyStruct LoadData(string path)
{
    MyStruct myData = new MyStruct();
    try
    {
        FileStream file1 = new FileStream(path, FileMode.Open);
        StreamReader data = new System.IO.StreamReader(file1);
        myData.Username = data.ReadLine();
        myData.Line2 = data.ReadLine();
        myData.SPengar = data.ReadLine();
    }
    catch
    {
        //Error for missing file
    }
    return myData;
}

Also, about saving and loading data:

1. If you have a huge chunk of data, you do Dr Super Good's 1st advice and load the needed data into a buffer via a FileStream.
2. If you want to save usernames and passwords, hash them. Having them means online or multi-user usage, so these should not be accessed (can be still cracked but it takes someone who is willing to take his time and knows what he is doing). Better being safe than sorry.
3. If you want to save game state (units on the map, their orders, quests, heroes, etc.) you better use MVC (Model-View-Control = separating data, graphics data/rendering, algorithms/game logic) and serialize the model for saving. With that you pretty much download any serializer class and save everything with a single function, and load it back as well. Or write one. Or use the native one (if you want to go nuts when Microsoft changes the serializer). Native serializers are

C#:
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
System.Runtime.Serialization.DataContractSerializer
System.Runtime.Serialization.DataJSONContractSerializer
System.Xml.Serialization.XmlSerializer

Use the one you like the most. But, if you aren't as lazy as I am when I'm making something for myself, don't use these and get a manually coded serializer class. Also, BinaryFormatter creates data that can not be read properly by the user (except for string data, like the forementioned passwords), and I think it's the fastest out of these.
 
Last edited:
Status
Not open for further replies.
Top