2012-03-28 5 views
1

私は問題がありました - 以前は、一部の問題を解決するアルゴリズムを行っていましたが(Combine LINQ queries)、大きな問題に遭遇しました。メモリマップファイルを使用してC#のメモリ不足を補うために

約540kのディレクトリでは、メモリ不足でクラッシュしています。 :(

会社のSANファイル情報を処理して保存しようとしていますが、私たちは25年以上データを保管している人がいるため、追跡するのが難しいため、これを行う必要があります。

私が読んだことから、メモリマップされたファイルは動的ではありませんか?これは本当ですか?私は確かにある前にどのように多くのファイル+のディレクトリを知ることができません。

ない場合、(ではないと言ってください)、誰かが私にに提供される短いダイナミックマップファイルを作成する方法についての例(コードを行うことができますCombine LINQ queries質問)。要するに、ディレクトリ→ディレクトリ+ファイル(名前、サイズ、アクセス日、変更日、作成日)を保持するメモリ内にディレクトリ構造を作成します。

可能であれば、これは私の問題を回避するための手がかりとなります。

+1

データベースの代わりに、メモリ内の表現を使用して検討していますか? –

+0

はい、私は持っていましたが、実行したいクエリーは、ディレクトリとそのサブパーツのサイズを読み、合計するなど非常に厄介なものになります。 – BugFinder

+0

それでもあなたのベスト・ベットです。確かにそれを確認してください。このタイプの問題を解決するのは、データベースのためのものです。 –

答えて

2

メモリにすべてを収めることができない場合は、IEnumerableでデータをストリーミングすることができます。私はperfの最後のドロップが必要なので、私はMemoryMappedファイルでも遊んでいますが、これまで私はBinaryReader/Writerに固執しました。

DB支持者の場合:実際にperfの最後のドロップが必要な場合は、自分のバイナリファイルも作成します。プロセスをDBにすると、実際にオーバーヘッドが増えます。また、全体のセキュリティ/ロギング、ACIDなどが追加されます。

ここでは、f_resultsクラスをストリームする例を示します。ディレクトリ情報のツリーを読む/書く方法を示すために例を更新しました

EDIT

。私はすべてのディレクトリを保持する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

+0

私はSSDを持っています。私はカスタムWindowsのビルドには32Bit(Bank)しか入っていないので、あまりにも多くのmemeoryを食べるだろうと私は恐れている。 – gjvdkamp

+0

これは有望に見えますが、それは私のディレクトリ構造を失うことになりますが、これは私に考えを与えてくれました!ありがとうございました! – BugFinder