2012-03-28 69 views
1

我有一个问题 - 以前我是在算法解决其中的一部分后(无论如何,请参阅Combine LINQ queries),并且我遇到了一个大问题。使用内存映射文件来弥补C#内存不足的问题

在540k左右的目录下,内存不足会崩溃。 :(

我想处理和存储公司SAN文件信息,我们需要这样做,因为我们有保留数据25年并且不需要的人,但很难追踪。总共有多达70   TB的文件,所以,你可以想象,它是很多文件。

从我读过的内容,但映射文件不能动态?这是真的吗?我不知道以前有多少文件+目录肯定有

如果没有,(请不要说),有人可以为我做一个简短的例子,了解如何制作动态映射文件(代码在Combine LINQ queries问题)。简而言之,我在内存中创建一个目录结构,用于存放目录→目录+文件(名称,大小,访问日期,修改日期和创建日期)。

任何线索将不胜感激,因为如果可能的话,这将解决我的问题。

+1

你有没有考虑使用一个数据库,而不是在内存中表示的? – 2012-03-28 07:49:06

+0

是的,我有,但是我想运行的查询会变得非常隐晦,比如阅读并总结一个目录及其子部分的大小......等等。 – BugFinder 2012-03-28 07:50:19

+0

不过,它可能是您最好的选择。做到这一点。解决这种类型的问题是数据库的用途。 – 2012-03-28 07:52:00

回答

2

当你不能将整个东西放入内存时,你可以使用IEnumerable下载数据流。下面是一个例子。我一直在玩MemoryMapped文件,因为我需要最后一滴perf,但到目前为止,我坚持使用BinaryReader/Writer。

对于DB提倡者:当你真的需要最后一滴perf时,我也会自己创建二进制文件。退出到数据库真的会增加开销。另外整个安全/日志记录,ACID等的确加起来。

下面是一个流f_results类的例子。

编辑

更新例子来说明如何读/写的目录信息树。我保留了1个包含所有目录的文件。该树一次加载到内存中,然后指向所有f_results所在的文件。 您仍然必须为每个包含所有文件的f_results的目录创建一个单独的文件。如何做到这一点取决于你的代码,但你应该能够弄清楚。

祝你好运!

public class f_results { 
    public String name { get; set; } 
    public DateTime cdate { get; set; } 
    public DateTime mdate { get; set; } 
    public DateTime adate { get; set; } 
    public Int64 size { get; set; } 

    // write one to a file 
    public void WriteTo(BinaryWriter wrtr) { 
     wrtr.Write(name); 
     wrtr.Write(cdate.Ticks); 
     wrtr.Write(mdate.Ticks); 
     wrtr.Write(adate.Ticks); 
     wrtr.Write(size); 
    } 

    // read one from a file 
    public f_results(BinaryReader rdr) { 
     name = rdr.ReadString(); 
     cdate = new DateTime(rdr.ReadInt64()); 
     mdate = new DateTime(rdr.ReadInt64()); 
     adate = new DateTime(rdr.ReadInt64()); 
     size = rdr.ReadInt64(); 
    } 

    // stream a whole file as an IEnumerable (so very little memory needed) 
    public static IEnumerable<f_results> FromFile(string dataFilePath) { 
     var file = new FileStream(dataFilePath, FileMode.Open); 
     var rdr = new BinaryReader(file); 
     var eos = rdr.BaseStream.Length; 
     while (rdr.BaseStream.Position < eos) yield return new f_results(rdr); 
     rdr.Close(); 
     file.Close(); 
    } 
} 

class Program { 
    static void Main(string[] args) { 

     var d1 = new DirTree(@"C:\", 
      new DirTree(@"C:\Dir1", 
       new DirTree(@"C:\Dir1\Dir2"), 
       new DirTree(@"C:\Dir1\Dir3") 
       ), 
       new DirTree(@"C:\Dir4", 
       new DirTree(@"C:\Dir4\Dir5"), 
       new DirTree(@"C:\Dir4\Dir6") 
       )); 

     var path = @"D:\Dirs.dir"; 

     // write the directory tree to a file 
     var file = new FileStream(path, FileMode.CreateNew | FileMode.Truncate); 
     var w = new BinaryWriter(file); 
     d1.WriteTo(w); 
     w.Close(); 
     file.Close(); 

     // read it from the file 
     var file2 = new FileStream(path, FileMode.Open); 
     var rdr = new BinaryReader(file2); 
     var d2 = new DirTree(rdr); 

     // now inspect d2 in debugger to see that it was read back into memory 

     // find files bigger than (roughly) 1GB 
     var BigFiles = from f in f_results.FromFile(@"C:\SomeFile.dat") 
         where f.size > 1e9 
         select f; 
    } 
} 

class DirTree { 
    public string Path { get; private set; } 
    private string FilesFile { get { return Path.Replace(':', '_').Replace('\\', '_') + ".dat"; } } 

    public IEnumerable<f_results> Files() { 
     return f_results.FromFile(this.FilesFile); 
    } 

    // you'll want to encapsulate this in real code but I didn't for brevity 
    public DirTree[] _SubDirectories; 

    public DirTree(BinaryReader rdr) { 
     Path = rdr.ReadString(); 
     int count = rdr.ReadInt32(); 
     _SubDirectories = new DirTree[count]; 
     for (int i = 0; i < count; i++) _SubDirectories[i] = new DirTree(rdr); 
    } 

    public DirTree(string Path, params DirTree[] subDirs){ 
     this.Path = Path; 
     _SubDirectories = subDirs; 
    } 

    public void WriteTo(BinaryWriter w) { 
     w.Write(Path);   
     w.Write(_SubDirectories.Length); 
     // depth first is the easiest way to do this 
     foreach (var f in _SubDirectories) f.WriteTo(w); 
    } 
} 

}

+0

在开始使用内存映射文件之前,我会先考虑使用RAM磁盘。 – weismat 2012-03-28 08:45:19

+0

我有一个SSD。我在一个自定义的windows版本中,现在只有32Bit(银行),所以我会害怕吃太多的memeory。 – gjvdkamp 2012-03-28 08:47:04

+0

这看起来很有前途,它会失去我的目录结构,但这绝对是给了我一个主意!谢谢! – BugFinder 2012-03-28 08:51:20