开发者

How to save a human readable file

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)
        {
            t开发者_JS百科hrow 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;
        }
    }


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));


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


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();
    }
}


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


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.


Try the DataContractSerializer

It serializes objects to XML and is very easy to use


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.


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());
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜