2012-03-28 73 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