天天看點

用C#接口實作通用的文本資料序列化

在企業應用中,經常遇到對文本資料的讀入和寫入問題。如一個移動話單檔案,或者使用SQLServer導出的文本資料,可能會包含這樣的内容:

13411112222,XXXX,20060225121800,1000

13512345678,YYYY,20060224101011,800

在解析這些檔案時,要将每行資料拆分成資料單元,然後儲存在預先定義好的資料對象中,一個資料檔案,經過解析,就會形成一個資料對象清單。

對于這類資料檔案,差別隻在于資料的列數、每列資料的含義,以及資料的分隔符,檔案讀入或寫入都是和檔案格式無關的。基于這樣的特性,可以考慮實作一個通用的資料檔案處理子產品,适用于所有這種模式存儲的資料檔案。

       要實作上述功能,我們需要把那些不确定的因素(資料的列數、每列資料的含義,以及資料的分隔符)盡量推遲到使用者實用階段,也就是把單獨一行的資料交給使用者定義的對象來解析,同時也允許使用者将生成好的一行資料交給我們的子產品來存儲。另外為了使序列化後的資料通路更快,這個記錄表在記憶體中應該使用哈希表來存儲,支援主鍵索引。

       先定義兩個接口類,限定使用者定義的對象的特性:支援一行資料的解析和生成、支援主鍵索引。

    /// <summary>

    /// 接口,表示可以從對象中得到主鍵

    /// guanzhong 2005

    /// http://blog.csdn.net/guanzhongs

    /// </summary>

    public interface IHashable

    {

        /// <summary>

        /// 獲得對象中的主鍵字段

        /// </summary>

        /// <returns></returns>

        Object GetKey();

    }

    /// <summary>

    /// 接口,表示可以将對象以文本方式導入導出到資料檔案中

    /// guanzhong 2005

    /// http://blog.csdn.net/guanzhongs

    /// </summary>

    public interface ITextSerialisable : IHashable

    {

        /// <summary>

        /// 可以将輸入字元串解釋為對象的屬性

        /// </summary>

        /// <param name="str"></param>

        /// <returns>傳回載入的字段數</returns>

        Int32 SerialIn(string str);

        /// <summary>

        /// 與 SerialIn 接口逆向,将對象屬性生成為字元串

        /// </summary>

        /// <returns></returns>

        String SerialOut();

    }

       當使用者希望他的資料對象支援文本記錄的序列化時,隻需要從ITextSerialisable派生即可。

下面代碼實作了具體的檔案資料讀取:

    /// <summary>

    /// 散清單資料的檔案存儲類

    /// 存儲時隻能接受從 ITextSerialisable 派生的對象

    /// 在 new 一個新對象時,需要指定所存儲資料類型

    /// guanzhong 2005

    /// http://blog.csdn.net/guanzhongs

    /// 效率測試

    /// 插入記錄 1000毫秒/10萬條

    /// 寫入檔案 250毫秒/10萬條

    /// 載入檔案 1800毫秒/10萬條

    /// </summary>

    public class FileData

    {

        private HashedList listData = null;

        System.Type typeData;

        /// <summary>

        /// 構造函數

        /// </summary>

        /// <param name="type">指定所存儲的資料類型,改類型必須從 ITextSerialisable 派生</param>

        public FileData(System.Type type)

        {

            listData = new HashedList();

            typeData = type;

        }

        /// <summary>

        /// 添加記錄

        /// </summary>

        /// <param name="itsa"></param>

        /// <returns></returns>

        public bool Add(ITextSerialisable itsa)

        {

            if(itsa.GetType() != typeData)

            {

                Exception ex = new Exception(string.Format("Invalid type of input parameter, only type /"{0}/" is accceptable",typeData.ToString()));

                throw(ex);

            }

            return listData.Add(itsa);

        }

        /// <summary>

        /// 根據主鍵擷取對象

        /// </summary>

        /// <param name="key"></param>

        /// <returns></returns>

        public Object Get(Object key)

        {

            return listData.Get(key);

        }

        /// <summary>

        /// 删除指定對象

        /// </summary>

        /// <param name="itsa"></param>

        /// <returns></returns>

        public bool Delete(ITextSerialisable itsa)

        {

            if(itsa.GetType() != typeData)

            {

                Exception ex = new Exception(string.Format("Invalid type of input parameter, only type /"{0}/" is accceptable",typeData.ToString()));

                throw(ex);

            }

            return listData.Delete(itsa);

        }

        /// <summary>

        /// 根據主鍵删除記錄

        /// </summary>

        /// <param name="key"></param>

        /// <returns></returns>

        public bool Delete(Object key)

        {

            return listData.Delete(key);

        }

        /// <summary>

        /// 清除儲存的所有對象

        /// </summary>

        public void Clear()

        {

            listData.Clear();

        }

        /// <summary>

        /// 從檔案加載記錄

        /// </summary>

        /// <param name="strFileName"></param>

        /// <returns>讀入記錄的行數</returns>

        public int Load(string strFileName)

        {

            if(strFileName == null || strFileName == "")

            {

                return -1;

            }

            FileStream stream = File.OpenRead(strFileName);

            if(stream == null)

            {

                return -1;

            }

            byte[] buf = new byte[stream.Length];

            int ptr = 0;

            int nlen = buf.Length;

            // 讀取檔案資料

            while(nlen > 0)

            {

                int nReaded = stream.Read(buf,ptr,nlen);

                if(nReaded == 0)

                {

                    break;

                }

                ptr += nReaded;

                nlen -= nReaded;

            }

            stream.Close();

            string strContent = Encoding.Default.GetString(buf);

            string[] lines = strContent.Split('/n');

            // 處理每一行

            int nRead = 0;

            foreach(string strLine in lines)

            {

                string strTmpLine = strLine.TrimEnd('/r');  // 如果檔案是以"/r/n"換行,則使用'/n'分割後每行末尾會遺留一個'/r'符,是以将其去掉

                // 讀取一行的記錄

                ITextSerialisable itsa = (ITextSerialisable)System.Activator.CreateInstance(typeData);

                if(itsa.SerialIn(strTmpLine) > 0)

                {

                    if(listData.Add(itsa))

                    {

                        nRead++;

                    }

                }

            }

            return nRead;

        }

        /// <summary>

        /// 将記錄儲存到檔案

        /// </summary>

        /// <param name="strFileName"></param>

        /// <returns>寫入的記錄數</returns>

        public int Store(string strFileName)

        {

            if(strFileName == null || strFileName == "")

            {

                return -1;

            }

            StreamWriter writer = File.CreateText(strFileName);

            if(writer == null)

            {

                return -1;

            }

            int nWrite = 0;

            for(int i=0;i<listData.Count;i++)

            {

                ITextSerialisable itsa = (ITextSerialisable)listData.GetAt(i);

                writer.WriteLine(itsa.SerialOut());

                nWrite++;

            }

            writer.Close();

            return nWrite;

        }

        public HashedList Datas

        {

            get

            {

                return listData;

            }

        }

        public int Count

        {

            get

            {

                return listData.Count;

            }

        }

        /// <summary>

        /// 散列記錄集

        /// guanzhong 2005

        /// http://blog.csdn.net/guanzhongs

        /// </summary>

        public class HashedList : ICollection

        {

            private SortedList list = null;

            private ArrayList array = null;     // 用于有序的存放清單元素,使得可以在GetEnumerator可以傳回IEnumerator對象

            public HashedList()

            {

                list = new SortedList();

                array = new ArrayList();

            }

            /// <summary>

            /// 以對象指定的主鍵将對象插入到清單中

            /// </summary>

            /// <param name="iek"></param>

            /// <returns></returns>

            public bool Add(IHashable iha)

            {

                if(iha == null)

                {

                    return false;

                }

                if(iha.GetKey() == null)

                {

                    Exception ex = new Exception(string.Format("Null hash key of object /"{0}/"",typeof(IHashable).ToString()));

                    throw(ex);

                }

                list.Remove(iha.GetKey());      // 删除舊的記錄(如果有的話)

                list.Add(iha.GetKey(),iha);     // 加入新的記錄

                return true;

            }

            /// <summary>

            /// 根據主鍵獲得對象

            /// </summary>

            /// <param name="key"></param>

            /// <returns></returns>

            public Object Get(Object key)

            {

                if(key == null)

                {

                    return null;

                }

                return list[key];

            }

            /// <summary>

            /// 根據索引獲得對象

            /// </summary>

            /// <param name="index"></param>

            /// <returns></returns>

            public Object GetAt(int index)

            {

                return list.GetByIndex(index);

            }

            /// <summary>

            /// 删除指定對象,必須保證對象中的主鍵有效

            /// </summary>

            /// <param name="iek"></param>

            /// <returns></returns>

            public bool Delete(IHashable iha)

            {

                if(iha == null)

                {

                    return false;

                }

                if(iha.GetKey() == null)

                {

                    Exception ex = new Exception(string.Format("Null hash key of object /"{0}/"",typeof(IHashable).ToString()));

                    throw(ex);

                }

                list.Remove(iha.GetKey());

                return true;

            }

            /// <summary>

            /// 根據主鍵删除記錄

            /// </summary>

            /// <param name="key"></param>

            /// <returns></returns>

            public bool Delete(Object key)

            {

                list.Remove(key);

                return true;

            }

            /// <summary>

            /// 清除清單

            /// </summary>

            public void Clear()

            {

                list.Clear();

            }

            /// <summary>

            /// 将對象複制到一維清單中,以便可以隻用foreach進行周遊

            /// </summary>

            /// <param name="array"></param>

            private void CopyToArrayList(ref ArrayList array)

            {

                array.Clear();

                for(int i=0;i<Count;i++)

                {

                    Object obj = list.GetByIndex(i);

                    array.Add(obj);

                }

            }

            #region ICollection Members

            public bool IsSynchronized

            {

                get

                {

                    // TODO:  Add PaydataCollection.IsSynchronized getter implementation

                    return false;

                }

            }

            public int Count

            {

                get

                {

                    // TODO:  Add PaydataCollection.Count getter implementation

                    return list.Count;

                }

            }

            public void CopyTo(Array array, int index)

            {

                // TODO:  Add PaydataCollection.CopyTo implementation

                list.CopyTo(array,index);

            }

            public object SyncRoot

            {

                get

                {

                    // TODO:  Add PaydataCollection.SyncRoot getter implementation

                    return null;

                }

            }

            #endregion

            #region IEnumerable Members

            public IEnumerator GetEnumerator()

            {

                // TODO:  Add PaydataCollection.GetEnumerator implementation

                CopyToArrayList(ref array);

                //return list.GetEnumerator();

                return array.GetEnumerator();

            }

            #endregion

        } // HashedList

    }

在Load方法中,這幾行

// 讀取一行的記錄

ITextSerialisable itsa =

     (ITextSerialisable)System.Activator.CreateInstance(typeData);

if(itsa.SerialIn(strTmpLine) > 0)

{

    if(listData.Add(itsa))

    {

        nRead++;

    }

}

是關鍵,它根據使用者在初始化FileData對象時,指定的存儲類型,将字元串資料還原成相應的類型對象(動态建立),儲存在對象清單中。