欢迎来到我的地盘:今天是

若得山花插满头,莫问奴归处!

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

在企业应用中,经常遇到对文本数据的读入和写入问题。如一个移动话单文件,或者使用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对象时,指定的存储类型,将字符串数据还原成相应的类型对象(动态创建),保存在对象列表中。

posted on 2007-12-04 17:51  莫问奴归处  阅读(767)  评论(0编辑  收藏  举报
轩轩娃