Saving FileSystemInfo Array to File

997 views Asked by At

I'm attempting to save an array of FileInfo and DirectoryInfo objects for use as a log file. The goal is to capture an image of a directory (and subdirectories) at a point in time for later comparison. I am currently using this class to store the info:

public class myFSInfo
{
    public FileSystemInfo Dir;
    public string RelativePath;
    public string BaseDirectory;
    public myFSInfo(FileSystemInfo dir, string basedir)
    {
        Dir = dir;
        BaseDirectory = basedir;
        RelativePath = Dir.FullName.Substring(basedir.Length + (basedir.Last() == '\\' ? 1 : 2));
    }
    private myFSInfo() { }
    /// <summary>
    /// Copies a FileInfo or DirectoryInfo object to the specified path, creating folders and overwriting if necessary.
    /// </summary>
    /// <param name="path"></param>
    public void CopyTo(string path)
    {
        if (Dir is FileInfo)
        {
            var f = (FileInfo)Dir;
            Directory.CreateDirectory(path.Substring(0,path.LastIndexOf("\\")));
            f.CopyTo(path,true);
        }
        else if (Dir is DirectoryInfo) Directory.CreateDirectory(path);
    }
}

I have tried XML and Binary serializing my class with no luck. I have also tried creating a new class that does not contain the actual FileInfo but only selected attributes:

public class myFSModInfo
{
    public Type Type;
    public string BaseDirectory;
    public string RelativePath;
    public string FullName;
    public DateTime DateModified;
    public DateTime DateCreated;
    public myFSModInfo(FileSystemInfo dir, string basedir)
    {
        Type = dir.GetType();
        BaseDirectory = basedir;
        RelativePath = dir.FullName.Substring(basedir.Length + (basedir.Last() == '\\' ? 1 : 2));
        FullName = dir.FullName;
        DateModified = dir.LastWriteTime;
        DateCreated = dir.CreationTime;
    }
    private myFSModInfo() { }
    /// <summary>
    /// Copies a FileInfo or DirectoryInfo object to the specified path, creating folders and overwriting if necessary.
    /// </summary>
    /// <param name="path"></param>
    public void CopyTo(string path)
    {
        if (Type == typeof(FileInfo))
        {
            Directory.CreateDirectory(path.Substring(0, path.LastIndexOf("\\")));
            File.Copy(FullName,path, true);
        }
        else if (Type == typeof(DirectoryInfo)) Directory.CreateDirectory(path);
    }
    public void Delete() 
    {
        if (Type == typeof(FileInfo)) File.Delete(FullName);
        else if (Type == typeof(DirectoryInfo)) Directory.Delete(FullName);
    }
}

I've also had no luck serializing this. I could list the errors I've encountered with my various attempts, but it would probably be easier to select the best approach first. Here is my serialization code:

public void SaveLog(string savepath, string dirpath)
    {
        var dirf = new myFSModInfo[1][];
        string[] patharr = {dirpath}; 
        GetFSInfo(patharr, dirf);

        var mySerializer = new System.Xml.Serialization.XmlSerializer(typeof(myFSModInfo[]));
        var myWriter = new StreamWriter(savepath);
        mySerializer.Serialize(myWriter, dirf[0]);
        myWriter.Close();

        /*var bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();   
        FileStream fs = new FileStream(savepath, FileMode.Create, FileAccess.Write);   
        bf.Serialize(fs, dirf[0]);  */
    }
1

There are 1 answers

12
devmb On BEST ANSWER

FileSystemInfo isn't serializable, because it is not a simple type. FileInfo isn't serializable, because it has no empty default constructor.

So if you want to save that information, you have to build your own class with simple types, that wrap that the information from FileInfo or FileSystemInfo.

[Serializable]
public class MyFileInfo
{
    public string Name { get; set; }

    public long Length { get; set;}

    /// <summary>
    /// An empty ctor is needed for serialization.
    /// </summary>
    public MyFileInfo(){
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="test.MyFileInfo"/> class.
    /// </summary>
    /// <param name="fileInfo">File info.</param>
    public MyFileInfo(string path)
    {
        FileInfo fileInfo = new FileInfo (path);
        this.Length = fileInfo.Length;
        this.Name = fileInfo.Name;
        // TODO: add and initilize other members
    }
}

Example usage:

List<MyFileInfo> list = new List<MyFileInfo> ();

foreach (string entry in Directory.GetFiles(@"c:\temp"))
{
    list.Add (new MyFileInfo (entry));
}

XmlSerializer xsSubmit = new XmlSerializer(typeof(List<MyFileInfo>));
StringWriter sww = new StringWriter();
XmlWriter writer = XmlWriter.Create(sww);
xsSubmit.Serialize(writer, list);

Console.WriteLine (sww.ToString());