2015-07-06 23 views
5

Metin dosyasından çok uzun bir dizeyi nasıl okuyabilirim ve sonra işleyebilirim (sözcüklere bölünür)?Büyük bir dosya sözcüklere nasıl bölünür?

StreamReader.ReadLine() yöntemini denedim, ancak bir OutOfMemory istisnası alıyorum. Görünüşe göre, hatlarım çok uzun.

using (var streamReader = File.OpenText(_filePath)) 
    { 

     int lineNumber = 1; 
     string currentString = String.Empty; 
     while ((currentString = streamReader.ReadLine()) != null) 
     { 

      ProcessString(currentString, lineNumber); 
      Console.WriteLine("Line {0}", lineNumber); 
      lineNumber++; 
     } 
    } 

Ve kelimelere hat böler kodu: Bit boyutu bölüme

var wordPattern = @"\w+"; 
var matchCollection = Regex.Matches(text, wordPattern); 
var words = (from Match word in matchCollection 
      select word.Value.ToLowerInvariant()).ToList(); 
+0

Bölme işlemi için hangi algoritmayı/yöntemi kullandınız? – byako

+0

@byako, burada bunun için kullanmak yöntemdir: 'kamu statik IEnumerable GetLowercasedWords (string metin) { if (string.IsNullOrEmpty (metin)) { return null; } var wordPattern = @ "\ w +"; var matchCollection = Regex.Matches (metin, wordPattern); var words = (Maçtaki kelimeden eşlemeKoleksiyon word.Value.ToLowerInvariant()) ToList(); kelimeleri döndür; } 'Biçimlendirme için özür dilerim. –

+0

StreamReader'ı gerçekte nasıl uyguladığınızı daha iyi ekleyeceğinizden, insanlar orada hata bulabilirler. Sorular için 140 karakter sınırı yoktur. – Jens

cevap

5

sen giderken aynı anda tüm dosyayı okumak zorunda kalmamak Bunu ertelenmiş yapmak yield kullanarak kelimeleri bina, Char tarafından okuyabilir: Kod dosyayı okur

private static IEnumerable<string> ReadWords(string filename) 
{ 
    using (var reader = new StreamReader(filename)) 
    { 
     var builder = new StringBuilder(); 

     while (!reader.EndOfStream) 
     { 
      char c = (char)reader.Read(); 

      // Mimics regex /w/ - almost. 
      if (char.IsLetterOrDigit(c) || c == '_') 
      { 
       builder.Append(c); 
      } 
      else 
      { 
       if (builder.Length > 0) 
       { 
        yield return builder.ToString(); 
        builder.Clear(); 
       } 
      } 
     } 

     yield return builder.ToString(); 
    } 
} 

karakter ve kelime olmayan bir karakterle karşılaştığında, o zamana kadar oluşturulmuş sözcük (yield return) (yalnızca ilk harf olmayan karakter için) olacaktır. Kod, kelime dizgisini oluşturmak için StringBuilder kullanır.

Char.IsLetterOrDigit(), karakterler için the regex word character w gibi davranır, ancak alt çizgiler (diğerleri arasında) da ikinci kategoriye girer. Girişiniz de eklemek istediğiniz daha fazla karakter içeriyorsa, if()'u değiştirmeniz gerekir.

+2

StringBuilder bu yaklaşım için daha iyi bir seçenek olmaz mıydı? –

+2

Dikkatli olun! Bu, beyaz boşluk (ör. Tire işaretleri, noktalama işaretleri) dışında hiçbir şeyi işlemediği için '\ w +' değerine eşdeğer değildir. – Bas

+0

'\ w' ayrıca rakamları ve alt çizgi içerir. – Bas

0

Kesim bunu Bu benim okuma dosyası için kodudur. Bu yüzden, bir sayfanın boyutuyla ilgili olduğuna inandığım 4gb'yi okumak yerine, 8 500mb'lik parçaları okumaya çalışın ve bu yardımcı olacaktır.

+0

Kesin parçalara ayırmayacağınızı söylemeliyim. Ama nispeten yeterince yakın parçalar. Bunun sebebi, 500 mb'lik bir cutoff'unuz varsa, dosyayı parçalara ayırmak ya da bir kelimenin başlangıcını değil, ortada bölmek isteyebilirsiniz. Bu yüzden sadece dosyayı kesmeyin. Bunu daha akıllı bir şekilde yapın. – trinityalps

+0

doğru konum. Zorluklarla karşılaşmamın ana nedeni budur –

0

Çöp toplama bir çözüm olabilir. Sorun kaynağı olduğundan emin değilim. Ancak durum böyle ise, basit bir GC.Collect çoğu zaman yetersizdir ve performans sebebi için sadece gerçekten gerekli olduğunda çağrılmalıdır. Kullanılabilir bellek çok düşük olduğunda (yordam parametresi olarak sağlanan eşiğin altında) çöp çağıran aşağıdaki yordamı deneyin.

int charReadSinceLastMemCheck = 0 ; 
using (var streamReader = File.OpenText(_filePath)) 
{ 

    int lineNumber = 1; 
    string currentString = String.Empty; 
    while ((currentString = streamReader.ReadLine()) != null) 
    { 

     ProcessString(currentString, lineNumber); 
     Console.WriteLine("Line {0}", lineNumber); 
     lineNumber++; 
     totalRead+=currentString.Length ; 
     if (charReadSinceLastMemCheck>1000000) 
     { // Check memory left every Mb read, and collect garbage if required 
      CollectGarbage(100) ; 
      charReadSinceLastMemCheck=0 ; 
     } 
    } 
} 


internal static void CollectGarbage(int SizeToAllocateInMo) 
{ 
     long [,] TheArray ; 
     try { TheArray =new long[SizeToAllocateInMo,125000]; }low function 
     catch { TheArray=null ; GC.Collect() ; GC.WaitForPendingFinalizers() ; GC.Collect() ; } 
     TheArray=null ; 
} 
+0

@CodeCaster: kaldırdığınız yorumda yazdınız "Ayrıca, bazı Fransızca forumlarda bulduğunuz voodoo kodunu da göndermemelisiniz". Başka bir forumda zaten yayınladığınız kodu çoğaltmak için StackOverflow ilkelerine aykırı ise, hemen forumdan ayrılacağım. Fransızca forum yanıtının yazarına bakarsanız, isminin de "Graffito" olduğunu göreceksiniz. Ama kesinlikle başka birisini düşünüyorsun. – Graffito

+1

Graffito, CollectGarbage yönteminiz şeytan. Bunu daha önceki cevabınızdan tanıyorum. – usr

İlgili konular