views:

204

answers:

8

Currently i have an application that reads and writes several properties from one or two basic classes to a .txt file using the Binary Serializer.

I've opened up the .txt file in NotePad and as it's formatted for the application it's not very readable to the human eye, not for me anyway =D

I've heard of using XML but pretty much most of my searches seem to overcomplicate things.

The kind of data im trying to save is simply a collection of "Person.cs" classes,nothing more than a name and address, all private strings but with properties and marked as Serializable.

What would be the best way to actually save my data in a way that can be easily read by a person? It would also make it easier to make small changes to the application's data directly in the file instead of having to load it, change it and save it.

Edit:

I have added the current way i am saving and loading my data, my _userCollection is as it suggests and the nUser/nMember are an integer.

#region I/O Operations

    public bool SaveData()
    {
        try
        {
            //Open the stream using the Data.txt file
            using (Stream stream = File.Open("Data.txt", FileMode.Create))
            {
                //Create a new formatter
                BinaryFormatter bin = new BinaryFormatter();
                //Copy data in collection to the file specified earlier
                bin.Serialize(stream, _userCollection);
                bin.Serialize(stream, nMember);
                bin.Serialize(stream, nUser);
                //Close stream to release any resources used
                stream.Close();
            }
            return true;
        }
        catch (IOException ex)
        {
            throw new ArgumentException(ex.ToString());
        }
    }

    public bool LoadData()
    {
        //Check if file exsists, otherwise skip
        if (File.Exists("Data.txt"))
        {
            try
            {
                using (Stream stream = File.Open("Data.txt", FileMode.Open))
                {
                    BinaryFormatter bin = new BinaryFormatter();

                    //Copy data back into collection fields
                    _userCollection = (List<User>)bin.Deserialize(stream);
                    nMember = (int)bin.Deserialize(stream);
                    nUser = (int)bin.Deserialize(stream);
                    stream.Close();

                    //Sort data to ensure it is ordered correctly after being loaded
                    _userCollection.Sort();
                    return true;

                }
            }
            catch (IOException ex)
            {
                throw new ArgumentException(ex.ToString());
            }
        }
        else
        {
            //Console.WriteLine present for testing purposes
            Console.WriteLine("\nLoad failed, Data.txt not found");
            return false;
        }
    }
+2  A: 

You could implement your own PersonsWriter, that takes a StreamWriter as constructor argument and has a Write method that takes an IList<Person> as input to parse out a nice text representation.

For example:

public class PersonsWriter : IDisposable
{
    private StreamWriter _wr;

    public PersonsWriter(IList<Person> persons, StreamWriter writer)
    {
        this._wr = writer;
    }

    public void Write(IList<Persons> people) {
        foreach(Person dude in people)
        {
            _wr.Write(@"{0} {1}\n{2}\n{3} {4}\n\n",
                dude.FirstName,
                dude.LastName,
                dude.StreetAddress,
                dude.ZipCode,
                dude.City);
        }
    }

    public void Dispose()
    {
        _wr.Flush();
        _wr.Dispose();
    }
}
Tomas Lycken
It's a nice idea but i would like it to be generic so i can use it in other applications as they currently use the same method for saving data.
Jamie Keeling
+3  A: 

Using XmlSerializer is not really complicated. Have a look at this MSDN page for an example: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx

M4N
+6  A: 

Replace your BinaryFormatter with XMLSerializer and run the same exact code.

The only change you need to make is the BinaryFormatter takes an empty constructor, while for the XMLSerializer you need to declare the type in the constructor:

XmlSerializer serializer = new XmlSerializer(typeof(Person));
Yuriy Faktorovich
XmlSerializer has a number of limitations compared to BinaryFormatter... for instance it can't serialize private data. DataContractSerializer is probably a better choice
Thomas Levesque
The DataContractSerializer is fun, but personally I think the usage of the XMLSerializer is closer to the BinaryFormatter because of the non opt in nature and same attributes.
Yuriy Faktorovich
I think Thomas is closer to the truth here... in particular, with the service-pack, the default behaviour of DCS against a non-attributed type is very similar to BF. Of course, neither BF nor non-attributed DCS is a good option, for exactly this reason!
Marc Gravell
Thankyou for the advice, i've looked further into MSDN and hopefully it seems easier than first though. I'll be sure to add my updated XML incase anybody has a similar question.
Jamie Keeling
Why on earth do i have to make my fields public for it to work? Seems bad as i like to keep my fields private and use properties.I guess it's an advantage of using the BinaryFormatter.
Jamie Keeling
A: 

Try the DataContractSerializer

It serializes objects to XML and is very easy to use

Thomas Levesque
I'd argue that *easy to use* part.
Yuriy Faktorovich
A: 

Write a CSV reader writer if you want a good compromise between human and machine readable in a Windows environment

Loads into Excel too.

There's a discussion about it here:

http://knab.ws/blog/index.php?/archives/3-CSV-file-parser-and-writer-in-C-Part-1.html

EDIT

That is a C# article... it just confusingly has "C" in the URL.

martinr
A: 

YAML is another option for human readable markup that is also easy to parse. there are libraries available for c# as well as almost all other popular languages. Here's a sample of what yaml looks like:

invoice: 34843
date   : 2001-01-23
bill-to: &id001
    given  : Chris
    family : Dumars
    address:
        lines: |
            458 Walkman Dr.
            Suite #292
        city    : Royal Oak
        state   : MI
        postal  : 48046
Peter Recore
A: 

I really think you should go with XML (look into DataContractSerializer). Its not that complicated. You could probably even just replace BinarySerializer with XMLSerializer and go.

If you still don't want to do that, though, you can write a delimited text file. Then you'll have to write your own reader method (although, it could almost just use the split method).

//Inside the Person class:
public override string ToString()
{
    List<String> propValues = new List<String>();

    // Get the type.
    Type t = this.GetType();

    // Cycle through the properties.
    foreach (PropertyInfo p in t.GetProperties())
    {
        propValues.add("{0}:={1}", p.Name, p.GetValue(o, null));
    }

    return String.Join(",". propValues.ToArray())
}

using (System.IO.TextWriter tw = new System.IO.StreamWriter("output.txt"))
{
    tw.WriteLine(person.ToString());
}
Gabriel McAdams
+1  A: 

Frankly, as a human, I don't find XML to be all that readable. In fact, it's not really designed to be read by humans.

If you want a human readable format, then you have to build it.

Say, you have a Person class that has a First Name, a last Name and a SSN as properties. Create your file, and have it write out 3 lines, with a description of the field in the first fifty (random number from my head) and then with character 51 have the value start being written.

This will produce a file that looks like:

First Name-------Stephen
Last Name -------Wrighton
SSN -------------XXX-XX-XXXX

Then, reading it back in, your program would know where the data begins on each line, and what each line is for (the program would know that Line 3 is the SSN value).

But remember, to truly gain human readability, you sacrifice data portability.

Stephen Wrighton
Actually SGML, which XML is a derivitive of, was designed exactly to be human readable while maintianing the ability to programically parse it, hence it's verbosity. It is also in the XML 1.0 recommendation. `XML documents should be human-legible and reasonably clear.` Found: http://www.w3.org/TR/xml/#sec-origin-goals If it wasn't for this, JSON (or similar compact data oriented languages) would be a better choice. +1 for noting that "true" human readability sacs portability.
Kevin Peno
Good point, but IMO, there's a difference between human-legible and human-readable. human-legible means that it can be interpreted into a human-readable format with some thought but does not need computer interpretation, whereas human readable means that the data is stored/display in a format that humans can easily consume. A not quit perfect example: opening a HTML file in Notepad is human-legible whereas opening that same HTML file in FireFox is human-readable.
Stephen Wrighton