在.NET CF下保存和读取XML文件数据不是一般的慢……

测试机器规格:
CPU:           TI OMAP 200MHz
FreeMem:   大约 7.5M
WinCE ver: 4.20(build 0)
.NET CF:    1.0

对一个格式大致为(保护公司机密,所以名称和结果不是很真实)

的XML文件用XmlDocument直接进行读取,我的实测结果是:
< Root >
  
< Item  attr  = "something" >
     
< ID > 1 </ ID >
     
< Name > abcdef </ Name >
     
< Something  ref  = "alpha"  type  = "beta" > abcdefg </ Something >
     
< Other  type  = "abc" > 1 </ Other >
     
< Extension  type  = "linkSame" > Parent </ Extension >
     
< Parent  xxx  = "yyy" > 3 </ Parent >
  
</ Item >
  
</ Root >

当Item数量为150个左右的时候,读取所有信息需要时间大约为6-9秒。当数量为300左右时(此时文件大小大约为110k),时间大约需要11-14秒。当数量暴增到接近6000的时候(大小约为2M),时间需要大约200秒。在桌面下,我们可以轻松的使用XML来进行非结果化数据的存储,但是到了CE平台下面,我们就不能够继续这么干了,至少大量数据这么做是不行的。当然,XML也从来不是为了存储和检索大量数据而设计的,大家主要还是利用XML相对来说非常强大和灵活的描述能力来对一些非结构化的信息进行描述。虽然说6000项数据相对于大型数据库动辄上百万的级别来说还是芝麻绿豆,并且在桌面上也完全能够胜任(大概1.1秒),但对于SmartPhone这种资源较为有限的机器来说就是一个大规模级别的物体了。而非常不幸的是,.NET CF 1.0在这方面的设计也比较糟糕(据传说在2.0会有较大的改进),这两个条件的共同作用造就了上面那个非常糟糕的测试结果。这仅仅是把数据读进内存当中,还没有进行任何的处理,如果让用户去等待这么长的时间去读数据,估计用户肯定得把手机扔掉。

不过这不代表着没有任何改善的余地,比如说,我们可以把文件内容分割。前提条件是实际上不需要所有的内容,并且内容能够有效地分割(包括容易管理)。这个方法的好处是,仍然可以用XML来进行存储。有好处当然也有坏处:需要将内容分割,意味着你需要管理这些分割的部分,比如在程序需要的时候必须能够调度到内存当中,同时检索的难度也加大了(可能需要一个额外的索引文件或者机制来完成)。

在进行这样的分割之前,最好考虑一下是否有其他的解决方案,比如说XmlReader。说起来好像有点复杂,似乎要自己手动处理Xml文件,其实并没有那么复杂,比如下面的这个函数可以用来定位某一个指定的element:
         //  Seek a specified element node.
        
//  true: The specified element was found.
        
//  false: reached the end of file
         bool  SeekElement(XmlReader reader,  string  name)
        
{
            
while(reader.Read())
            
{
                
if (reader.NodeType == XmlNodeType.Element && reader.Name == name)
                
{
                    
return true;
                }

            }

            
return false;
        }


当然了,相对于一句doc.Load(path)来说,还是会复杂不少。此外xml文件内容的结果复杂度也需要简化,这样才便于手动处理。好在我们也不指望在手机上做什么特别复杂的应用,比如说什么内容排版之类的,一般来说数据也不是很复杂。如果你同意我的说法,那么也许可以参考一下我写的代码:

         void  Travel(XmlReader reader)
        
{

            
while (SeekElement(reader, "Item"))
            
{
                
if (reader.IsEmptyElement == false)
                
{
                    FillAttributes(reader);
                    
while (SeekElementWithEndCheck(reader, "Item") )
                    
{
                        FillAttribute(reader);
                        
if (reader.IsEmptyElement == false)
                        
{
                            
if (SeekTextWithEndCheck(reader, property))
                            
{
                                text 
= reader.Value;
                                MoveToEnd(property);
                            }
 // end if Text found
                        }
 // end if Item is not empty
                    }
 // end while find elements under "Item" element
                }
 // end if element "Item" is empty
            }
 // end while seeking all "Item" elements
        }


        
//  Seek a specified element node.
        
//  true: The specified element was found.
        
//  false: reached the end of file
         bool  SeekElement(XmlReader reader,  string  name)
        
{
            
while(reader.Read())
            
{
                
if (reader.NodeType == XmlNodeType.Element && reader.Name == name)
                
{
                    
return true;
                }

            }

            
return false;
        }


        
//  Seek an element with checking the end of a specified element node
        
//  true: an element found(the name of element can be retrieve from reader.Name, etc.)
        
//  false: reached the end of file, or reached the *end element* node "</name>"
         bool  SeekElementWithEndCheck(XmlReader reader,  string  name)
        
{
            
while(reader.Read())
            
{
                
switch(reader.NodeType)
                
{
                    
case XmlNodeType.EndElement:
                        
if (reader.Name == name)
                        
{
                            
return false;
                        }

                        
break;
                    
case XmlNodeType.Element:
                        
return true;
                }

            }

            
return false;
        }


        
//  Seek text within the bound of element *name*
        
//  true: text found (in reader.Value)
        
//  false: reached the end of file, or reached the </name> node.
         bool  SeekTextWithEndCheck(XmlReader reader,  string  name)
        
{
            
while(reader.Read())
            
{
                
switch(reader.NodeType)
                
{
                    
case XmlNodeType.EndElement:
                        
if (reader.Name == name)
                        
{
                            
return false;
                        }

                        
break;
                    
case XmlNodeType.Text:
                        
return true;
                }

            }

            
return false;
        }


        
//  travel all the attributes
         void  FillAttribute(XmlReader reader)
        
{
            
if (reader.MoveToFirstAttribute())
            
{
                
do
                
{
                    
// fill your code here
                    Console.WriteLine(reader.Name + " : \t" + reader.Value);
                }
while(reader.MoveToNextAttribute());
            }

        }



待续……

你可能感兴趣的:(读取xml)