Bir metin dosyasını kilitlemeden nasıl okuyabilirim?


96

Windows hizmetim, günlüğünü bir metin dosyasına basit bir biçimde yazıyor.

Şimdi, hizmetin günlüğünü okumak için küçük bir uygulama oluşturacağım ve hem mevcut günlüğü hem de eklenmiş olanı canlı görüntü olarak göstereceğim.

Sorun, hizmetin yeni satırları eklemek için metin dosyasını kilitlemesi ve aynı zamanda görüntüleyici uygulamasının dosyayı okumak için kilitlemesidir.

Servis Kodu:

void WriteInLog(string logFilePath, data)
{
    File.AppendAllText(logFilePath, 
                       string.Format("{0} : {1}\r\n", DateTime.Now, data));
}

Görüntüleyici Kodu:

int index = 0;
private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                using (StreamReader sr = new StreamReader(logFilePath))
                {
                    while (sr.Peek() >= 0)  // reading the old data
                    {
                        AddLineToGrid(sr.ReadLine());
                        index++;
                    }
                    sr.Close();
                }

                timer1.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }


private void timer1_Tick(object sender, EventArgs e)
        {
            using (StreamReader sr = new StreamReader(logFilePath))
            {
                // skipping the old data, it has read in the Form1_Load event handler
                for (int i = 0; i < index ; i++) 
                    sr.ReadLine();

                while (sr.Peek() >= 0) // reading the live data if exists
                {
                    string str = sr.ReadLine();
                    if (str != null)
                    {
                        AddLineToGrid(str);
                        index++;
                    }
                }
                sr.Close();
            }
        }

Kodumda okuma ve yazma şeklinde bir sorun var mı?

Problem nasıl çözülür?


Yanıtlar:


123

Hem hizmetin hem de okuyucunun günlük dosyasını özel olmayan bir şekilde açtığından emin olmanız gerekir. Bunu dene:

Hizmet için - örneğinizdeki yazar - FileStreamaşağıdaki gibi oluşturulmuş bir örnek kullanın :

var outStream = new FileStream(logfileName, FileMode.Open, 
                               FileAccess.Write, FileShare.ReadWrite);

Okuyucu için aynısını kullanın, ancak dosya erişimini değiştirin:

var inStream = new FileStream(logfileName, FileMode.Open, 
                              FileAccess.Read, FileShare.ReadWrite);

Ayrıca, FileStreamuygulamalar IDisposableher iki durumda da bir usingifade kullanmayı düşündüğünüzden emin olun, örneğin yazar için:

using(var outStream = ...)
{
   // using outStream here
   ...
}

İyi şanslar!



Mükemmel - FileAccess.Read ile File.Open () 'ın yeterli olduğunu düşünmüştüm, ancak yeterli değil. Yine de bu. :)
neminem

Yazara göre, FileShare, sadece bir yazar olduğu için okumak yeterli olmaz mı?
crokusek

2
Ayrıca, FileStreamuygulandığını da belirtmek gerekirIDisposable
weekdev

28

Metin dosyasını okurken paylaşım modunu açıkça ayarlayın.

using (FileStream fs = new FileStream(logFilePath, 
                                      FileMode.Open, 
                                      FileAccess.Read,    
                                      FileShare.ReadWrite))
{
    using (StreamReader sr = new StreamReader(fs))
    {
        while (sr.Peek() >= 0) // reading the old data
        {
           AddLineToGrid(sr.ReadLine());
           index++;
        }
    }
}

2
StreamReader.Dispose otomatik olarak kapattığı için akışı açıkça kapatmak gereksizdir.
nothrow

2
Dosya paylaşımının sadece okuma değil, HER İKİ okuma ve yazma akışında ayarlanması gerektiğine inanıyorum.
LEO

StreamReader.Dispose ayrıca yanılmıyorsam FileStream'i de atıyor. Burada iki kez atılıyor.
Eregrith

13
new StreamReader(File.Open(logFilePath, 
                           FileMode.Open, 
                           FileAccess.Read, 
                           FileShare.ReadWrite))

-> bu, dosyayı kilitlemez.


1
Veri okurken işe yarıyor gibi görünüyor. Kilitli dosya yazılırken hata oluşur.
webzy

8

Sorun, günlüğe yazarken yalnızca dosyayı kilitlemenizdir, böylece StreamReader'ınızın onu hiç açmasına izin verilmez.

Dosyayı salt okunur modda açmayı denemelisiniz .

using (FileStream fs = new FileStream("myLogFile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    using (StreamReader sr = new StreamReader(fs))
    {
        while (!fs.EndOfStream)
        {
            string line = fs.ReadLine();
            // Your code here
        }
    }
}

Şimdi bildiğim gibi, File.ReadAllText()salt okunur modda başarısız oluyor.
bohdan_trotsenko

@modosansreves evet DokümanlarUnauthorizedAccessException , dosyanın salt okunursa bir atacağını belirttiği için cevabın bu kısmını kaldırdım - cevaplama sırasında bunu kaçırmış olmalı!
James

5

Birkaç yıl önce aynı şeyi yaptığımı hatırlıyorum. Bazı Google sorgularından sonra şunu buldum:

    FileStream fs = new FileStream(@”c:\test.txt”, 
                                   FileMode.Open, 
                                   FileAccess.Read,        
                                   FileShare.ReadWrite);

yani FileStream () üzerinde FileShare.ReadWrite özniteliğini kullanın.

( Balaji Ramesh'in blogunda bulundu )


1

Dosyayı kopyalayıp sonra okumayı denediniz mi?

Kopyayı, büyük değişiklikler yapıldığında güncellemeniz yeterlidir.


2
Bunu denedim ve en iyi çözüm değil. 4mb'lik bir dosyanın kopyalanması çok uzun sürüyor, çünkü 20 saniye gibi.
Seichi

-1

Bu yöntem, bir metin dosyasını kilitlemeden en hızlı şekilde okumanıza yardımcı olacaktır.

private string ReadFileAndFetchStringInSingleLine(string file)
    {
        StringBuilder sb;
        try
        {
            sb = new StringBuilder();
            using (FileStream fs = File.Open(file, FileMode.Open))
            {
                using (BufferedStream bs = new BufferedStream(fs))
                {
                    using (StreamReader sr = new StreamReader(bs))
                    {
                        string str;
                        while ((str = sr.ReadLine()) != null)
                        {
                            sb.Append(str);
                        }
                    }
                }
            }
            return sb.ToString();
        }
        catch (Exception ex)
        {
            return "";
        }
    }

Umarım bu yöntem size yardımcı olur.


1
Anladığım kadarıyla, bu yöntem bütün bir dosyayı bir dizeye okur ve yol boyunca istisnaları yutar. Bunun dosya kilitlemeye nasıl yardımcı olacağını tahmin edemiyorum.
varsayılan yerel ayar
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.