views:

3262

answers:

7

I have the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ConsoleApplication28
{
class Program
{

    static void Main()
    {
        List<string> dirs = FileHelper.GetFilesRecursive(@"c:\Documents and Settings\bob.smith\Desktop\Test");
        foreach (string p in dirs)
        {
            Console.WriteLine(p);
        }

        //Write Count
        Console.WriteLine("Count: {0}", dirs.Count);
        Console.Read();

    }

    static class FileHelper
    {
        public static List<string> GetFilesRecursive(string b)
        {
            // 1.
            // Store results in the file results list.
            List<string> result = new List<string>();

            // 2.
            // Store a stack of our directories.
            Stack<string> stack = new Stack<string>();

            // 3.
            // Add initial directory.
            stack.Push(b);

            // 4.
            // Continue while there are directories to process
            while (stack.Count > 0)
            {
                // A.
                // Get top directory
                string dir = stack.Pop();

                try
                {
                    // B
                    // Add all files at this directory to the result List.
                    result.AddRange(Directory.GetFiles(dir, "*.*"));

                    // C
                    // Add all directories at this directory.
                    foreach (string dn in Directory.GetDirectories(dir))
                    {
                        stack.Push(dn);
                    }
                }
                catch
                {
                    // D
                    // Could not open the directory
                }
            }
            return result;
        }
    }
}
}

The code above works well for recursively finding what files/directories lie in a folder on my c:.
I am trying to serialize the results of what this code does to an XML file but I am not sure how to do this.

My project is this: find all files/ directories w/in a drive, serialize into an XML file. Then, the second time i run this app, i will have two XML files to compare. I then want to deserialize the XML file from the first time i ran this app and compare differences to the current XML file and produce a report of changes (i.e. files that have been added, deleted, updated).

I was hoping to get some help as I am a beginner in C# and i am very very shaky on serializing and deserializing. I'm having lots of trouble coding. Can someone help me?

Thanks

A: 

Help #1. Indent code by four spaces to have it be seen as code when you post here.

2: get rid of that try/catch block, as it will eat all exceptions, including the ones you want to know about.

3: Did you make any attempt at all to serialize your results? Please edit your question to show what you tried. Hint: use the XmlSerializer class.

John Saunders
well the thing is, i'm not clear how to exactly implement the XMLSerializer class. i've been doing C# for 3 months now...and i have raging gaps in my knowledge. i did follow examples i found on the web but i have no idea of how i'd use the example to help me here...and where to put any of the code itself.
@yeahumok: You may want to consider whether "finding examples" is the right way for you to learn. Some people learn well in this unstructured manner. Others require someone who already knows the structure of the knowledge, to present it in a rational order. Maybe that's what you need. Maybe something like http://msdn.microsoft.com/en-us/library/90c86ass(VS.85).aspx would help you, and not random examples you happen to find.
John Saunders
A: 

This class serializes and deserializes itself....hopefully this helps.

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using System.Xml;

namespace TestStuff
{
    public class Configuration
    {
        #region properties

        public List<string> UIComponents { get; set; }
        public List<string> Settings { get; set; }

        #endregion

        //serialize itself
        public string Serialize()
        {
            MemoryStream memoryStream = new MemoryStream();

            XmlSerializer xs = new XmlSerializer(typeof(Configuration));
            using (StreamWriter xmlTextWriter = new StreamWriter(memoryStream))
            {
                xs.Serialize(xmlTextWriter, this);
                xmlTextWriter.Flush();
                //xmlTextWriter.Close();
                memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
                memoryStream.Seek(0, SeekOrigin.Begin);
                StreamReader reader = new StreamReader(memoryStream);

                return reader.ReadToEnd();
            }
        }

        //deserialize into itself
        public void Deserialize(string xmlString)
        {
            String XmlizedString = null;

            using (MemoryStream memoryStream = new MemoryStream())
            {
                using (StreamWriter w = new StreamWriter(memoryStream))
                {
                    w.Write(xmlString);
                    w.Flush();

                    XmlSerializer xs = new XmlSerializer(typeof(Configuration));
                    memoryStream.Seek(0, SeekOrigin.Begin);
                    XmlReader reader = XmlReader.Create(memoryStream);

                    Configuration currentConfig = (Configuration)xs.Deserialize(reader);

                    this.Settings = currentConfig.Settings;
                    this.UIComponents = currentConfig.UIComponents;

                    w.Close();
                }
            }
        }
        static void Main(string[] args)
        {
            Configuration thisConfig = new Configuration();
            thisConfig.Settings = new List<string>(){
                "config1", "config2"
            };
            thisConfig.UIComponents = new List<string>(){
                "comp1", "comp2"
            };
            //serializing the object
            string serializedString = thisConfig.Serialize();


            Configuration myConfig = new Configuration();
            //deserialize into myConfig object
            myConfig.Deserialize(serializedString);
        }
    }


}
CSharpAtl
@CSharpAll: Your class also leaks resources if an exception is thrown: no using blocks.
John Saunders
am i missing any Using statements? i'm using these: using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Xml;using System.Runtime.Serialization;using System.Xml.Serialization;using System.IO;
what error are you getting?
CSharpAtl
if you are using my exact class....SerializableDictionary is my object (not in example).
CSharpAtl
@John - good call.....added using statements
CSharpAtl
Here are my errors:The type or namespace name 'RegisteredUIComponent' could not be found (are you missing a using directive or an assembly reference?) andthe same error...except for "serializabledictionary"how do i fix this?
both of those classes are my classes...they are not part of the framework. I was just giving you an example of the serializing and deserializing....put your own properties in there.
CSharpAtl
added more generic example....this should compile fully.
CSharpAtl
+1  A: 

Your result is List<string> and that is not directly serializable. You'll have to wrap it, a minimal approach:

[Serializable]
class Filelist: List<string> {  }

And then the (De)Serialization goes like:

Filelist data = new Filelist(); // replaces List<string>
// fill

using (var stream = File.Create(@".\data.xml"))
{
    var formatter = new System.Runtime.Serialization.Formatters.Soap.SoapFormatter();
    formatter.Serialize(stream, data);
}    

data = null; // loose it

using (var stream = File.OpenRead(@".\data.xml"))
{
    var formatter = new System.Runtime.Serialization.Formatters.Soap.SoapFormatter();
    data = (Filelist) formatter.Deserialize(stream);
}

But note that you will not be comparing the XML in any way (not practical). You will compare (deserialzed) List instances. And the XML is SOAP formatted, take a look at it. It may not be very useful in another context.

And therefore you could easily use a different Formatter (binary is a bit more efficient and flexible).

Or maybe you just want to persist the List of files as XML. That is a different question.

Henk Holterman
A: 

Hi, for xml serialisation, you have several possibilities:

  • Doing it manually
  • Using XmlSerializer as detailed above
  • Using System.Xml.Serialization
  • Using Linq to Xml

for the last two, see a code example in this answer. (See some gotchas here)

And for your recursive directory visitor, you could consider making it really recursive: here's some interesting code examples.

Benjol
A: 

John:

May I suggest an improvement? Instead of using filenames, use the FileInfo object. This will allow you to get much more accurate information about each file rather than just if it exists under the same name.

Also, the XmlSerializer class should do you just fine. It won't serialize generic lists, so you'll have to output your List<> to an array or some such, but other than that:

 XmlSerializer serial = new XmlSerializer(typeof(FileInfo[]));
 StringWriter writer = new StringWriter(); 
 FileInfo[] fileInfoArray = GetFileInfos(); 
 serial.Serialize(writer, fileInfoArrays);

Simple and easy, unless it matters to you how the serialized XML looks.

Whatever you do, lose the empty catch block. You WILL regret swallowing exceptions. Log them or re-throw them.

Faqa
A: 

This question is exactly like this one. I also have a posted answer which will work for you as well:

http://stackoverflow.com/questions/970971/how-to-serialize/971115#971115

Jason Heine
+2  A: 

For anyone who is having trouble with xml serialization and de-serialization. I have created a sample class to do this below. It works for recursive collections also (like files and directories).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Sample
{
        [Serializable()]
        [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false, ElementName = "rootnode")]
        public partial class RootNode
        {

            [System.Xml.Serialization.XmlElementAttribute("collection1")]
            public List<OuterCollection> OuterCollections { get; set; }
        }

        [Serializable()]
        public partial class OuterCollection
        {

            [XmlAttribute("attribute1")]
            public string attribute1 { get; set; }

            [XmlArray(ElementName = "innercollection1")]
            [XmlArrayItem("text", Type = typeof(InnerCollection1))]
            public List<InnerCollection1> innerCollection1Stuff { get; set; }

            [XmlArray("innercollection2")]
            [XmlArrayItem("text", typeof(InnerCollection2))]
            public List<InnerCollection2> innerConnection2Stuff { get; set; }
        }

        [Serializable()]
        public partial class InnerCollection2
        {

            [XmlText()]
            public string text { get; set; }
        }

        public partial class InnerCollection1
        {

            [XmlText()]
            public int number { get; set; }
        }
}
Tim
-1: You say you created these class "to do this", but I don't see that they _do_ anything.
John Saunders
As he said, it is a 'sample' class. It has all the commonly used elements, you don't have to do anything, but you do have to declare it. Quite nice thanks
TFD