2012-04-19 111 views
0

当前当我读取一个15Mb文件时,我的应用程序会经过一段内存。 请注意,在主代码的末尾,我将数据库中插入的数据与文件中的原始数组进行了比较。欢迎任何建议。需要优化此代码的建议

主要代码:

TestEntities entities = new TestEntities(); 

     using (FileStream fileStream = new FileStream(fileName + ".exe", FileMode.Open, FileAccess.Read)) 
     { 

      byte[] bytes = new byte[fileStream.Length]; 

      int numBytesToRead = (int) fileStream.Length; 
      int numBytesRead = 0; 

      while (numBytesToRead > 0) 
      { 
       int n = fileStream.Read(bytes, numBytesRead, numBytesToRead); 

       if (n == 0) 
        break; 

       numBytesRead += n; 
       numBytesToRead -= n; 
      } 

      var query = bytes.Select((x, i) => new {Index = i, Value = x}) 
       .GroupBy(x => x.Index/100) 
       .Select(x => x.Select(v => v.Value).ToList()) 
       .ToList(); 

      foreach (List<byte> list in query) 
      { 
       Binary binary = new Binary(); 
       binary.Name = fileName + ".exe"; 
       binary.Value = list.ToArray(); 
       entities.AddToBinaries(binary); 
      } 

      entities.SaveChanges(); 

      List<Binary> fileString = entities.Binaries.Where(b => b.Name == fileName + ".exe").ToList(); 

      Byte[] final = ExtractArray(fileString); 
      if (Compare(bytes, final)) 
      { 
       /// Some notification that was ok 
      } 

     } 

比较方法:

public bool Compare(Byte[] array1,Byte[] array2) 
    { 
     bool isEqual = false; 
     if (array1.Count() == array2.Count()) 
     { 

      for (int i = 0; i < array1.Count(); i++) 
      { 
       isEqual = array1[i] == array2[i]; 
       if (!isEqual) 
       { 
        break; 

       } 
      } 
     } 


     return isEqual; 
    } 

ExtractArray方法:

public Byte[] ExtractArray(List<Binary> binaries) 
    { 
     List<Byte> finalArray = new List<Byte>(); 

     foreach (Binary binary in binaries) 
     { 
      foreach (byte b in binary.Value) 
      { 
       finalArray.Add(b); 
      } 

     } 

     return finalArray.ToArray(); 
    } 
+1

比较大的二进制对象可以使用这里描述的方法来完成:http://stackoverflow.com/questions/968935/c-sharp-binary-file-compare – 2012-04-19 06:40:04

+0

是你所做的一个字节用于两个字节的比较文件?你为什么要这样做? – IanNorton 2012-04-19 06:44:45

+0

为什么不在数据库中存储文件的摘要,只是消化其他文件,而不是每次比较? – IanNorton 2012-04-19 06:45:31

回答

2

对于初学者来说,我强烈建议你在探查投资。这是确定代码运行时间如此之长或者使用大量内存的正确方法。这里有很多分析器,包括one built into Visual Studio 2010如果您有Premium或Ultimate。

见谷歌或这些职位他人:

What Are Some Good .NET Profilers?

Best .NET memory and performance profiler?

其次,你可能不应该假设你的应用程序should'nt走了过来一段记忆。 C#应用程序(实际上,所有.NET应用程序)都被垃圾收集。如果我有一台有足够内存的计算机,没有任何理由说明如果没有内存压力,GC应该运行,如果应用程序不能轻松使用内存。对于64位环境尤其如此,其中进程不受32位地址空间的内存限制。

+0

我确实需要一个分析器,但在这种情况下,配置文件会告诉我已经知道的内容,因为这里没有太多的代码,因此,为更好的想法提供集群是最好的选择。 – Oakcool 2012-04-24 23:31:44

+0

当你的应用程序读取一个15Mb文件并且它的内存达到6Gb时,你的第二点是真的错了,那就是现在发生的事情。 – Oakcool 2012-04-24 23:32:57

0

在头两个变种comapre的:

bool arraysAreEqual = Enumerable.SequenceEqual(array1, array2); 

或这一个

public bool Compare(Byte[] array1, Byte[] array2) 
    { 
     if (array1.Length != array2.Length) 
      return false; 

     for (int i = 0; i < array1.Length; i++) 
     { 
      if (array1[i] != array2[i]) 
       return false; 
     } 
     return true;    
    } 

关于提取试试这个:

foreach (Binary binary in binaries) 
{ 
    finalArray.AddRange(binary.Value); 
} 
+0

将Array.Length更改为IEnumerable.Count()。 – Asik 2012-04-19 06:49:39

+0

同意,现在编辑 – Likurg 2012-04-19 06:58:26

+0

不...还在那里:) – Rob 2012-04-19 07:34:05

0

1)你知道静态方法File.ReadAllBytes?可以为您节省前15行代码。

2)我讨厌Linq ......难以理解,很难理解到底发生了什么。

 var query = bytes.Select((x, i) => new {Index = i, Value = x}) 
      .GroupBy(x => x.Index/100) 
      .Select(x => x.Select(v => v.Value).ToList()) 
      .ToList(); 

因此,对于文件的每个字节,都会创建一个包含字节本身及其索引的对象。哇。如果你的文件是15MB,那就是15 728 640个对象。可以说这个对象需要64个字节,这是960mb的内存空间。

顺便说一句,你在做什么?

编辑

var bytes = File.ReadAllBytes(filename); 

var chunkCount = (int)Math.Ceilling(bytes.Length/100.0); 

var chunks = new List<ArraySegment<byte>>(chunkCount); 


for(int i = 0; i < chunkCount; i++) { 
    chunks.Add(new ArraySegment(
     bytes, 
     i * 100, 
     Math.Min(100, bytes.Length - i * 100) 
)); 
} 

这应该是快好几倍。

尽管如此,为了获得更好的性能,您可以在读取文件时将数据块插入数据库中,而不必将所有这些字节保留在内存中。

+0

所以GroupBy部分试图将文件分成一堆100字节长的卡盘,然后将每个块插入到数据库中。稍后我可以拉出所有的块并重建文件。 – Oakcool 2012-04-24 23:37:45

+0

@Oakcool编辑 – 2012-04-25 06:30:35