.NET 6學習筆記(1)——通過FileStream實現不同進程對單一文件的同時讀寫

會寫這篇純屬機緣巧合,雖然一直以來認爲對單一文件的讀、寫操作是不衝突,可並行的,但實際並未實踐過。正好有個UWP的程序要並行讀取由Desktop Extension創建的文本,需要有個原型程序來驗證,那不妨點開最新的VS 2022,順手試試新的語法糖。
首先我們明確本篇對文件的操作均通過FileStream類來實現,FileStream在.NET 6進行了完全的重寫,提高了性能和可靠性。但是本篇提到的共享讀寫權限,在之前版本也是完全支持的。
本篇提到的同時讀寫功能依賴FileStream的這個構造函數:

public FileStream (string path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share);

接下來我們通過實際的代碼來進行分析。創建第一個工程CreateWriteSharedFile,該工程爲.NET 6的Console程序,用於新建和寫入內容到名爲TestFile.txt的文件中。

var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "TestFile.txt");
var fileStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
StreamWriter sw = new StreamWriter(fileStream);
int cout = 0;
while (true)
{
    for (var i = 0; i < 10; i++)
    {
        sw.WriteLine(cout++);
        Console.WriteLine(cout);
    }
    sw.Flush();
    await Task.Delay(1000);
}

沒有命名空間,沒有類名和Main函數,這是C# 10裏的新語法糖——頂級語句。作爲簡化後的程序入口點,十分適合簡短的示例程序,對初學者也更友好。

代碼的內容也很好懂,就是每隔1秒連續寫入10個自增的數字。唯一值得留意的是FileShare.ReadWrite,這個枚舉標識對應的是後續其他對該文件的請求,不管是該進程內還是另外進程,均給與ReadWrite的權限。

我們的第二個工程ReadSharedFile僅做讀取的操作,所以上面CreateWriteSharedFile中的FileShare只給Read也可以。但是相反,ReadSharedFile因爲要允許CreateWriteSharedFile來進行寫操作,所以它必須給與FileShare.Write枚舉。

var path =Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "TestFile.txt");
var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read,FileShare.Write);
var reader = new StreamReader(fileStream);

while (!reader.EndOfStream)
{
    Console.WriteLine(reader.ReadLine());
    await Task.Delay(1000);
}

上述代碼是在ReadSharedFile工程中讀取由CreateWirteSharedFile創建的TestFile.txt中的內容。想要測試的話,build成功後運行對應的exe文件即可。並行的讀和寫操作較爲容易理解,也不會存在衝突或生成髒數據的問題。

但如果是同時進行寫操作會怎麼樣呢?之前的FileShare.ReadWrite就是爲接下來的測試準備的。我們創建第二個寫文件的工程SecondWriteSharedFile,同樣要注意除了設置Read以外,還要爲CreateWriteSharedFile特別準備Write權限,才能實現兩邊同時寫入該文件的要求。

var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "TestFile.txt");
var fileStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
StreamWriter sw = new StreamWriter(fileStream);

while (true)
{
    for (var i = 0; i < 10; i++)
    {
        sw.WriteLine("A".PadRight(i,'A'));
        Console.WriteLine("A".PadRight(i, 'A'));
    }

    sw.Flush();
    await Task.Delay(1000);
}

非常不幸的是,SecondWriteSharedFile在默認情況下,同樣會從文件的頭部開始寫入,這樣就覆蓋了先運行的CreateWriteSharedFile在同樣位置寫入的內容。所以在一般情況下,我們要避免並行的寫操作,這樣極容易互相覆蓋產生髒數據。
本篇簡單地討論了通過FileShare枚舉,使用FileStream並行地讀寫文件的一般場景。希望能夠拋磚引玉,給各位大佬在實際生產場景中以微小的幫助。
示例代碼:(因爲GitHub經常打不開,我在gitee也同樣放了一份)

https://github.com/manupstairs/FileReadWriteSample
https://gitee.com/manupstairs/FileReadWriteSample

以下鏈接,是MS Learn上Windows開發的入門課程,單個課程三十分鐘到60分鐘不等,想要補充基礎知識的同學點這裏:

開始使用 Visual Studio 開發 Windows 10 應用

開發 Windows 10 應用程序

編寫首個 Windows 10 應用

創建 Windows 10 應用的用戶界面 (UI)

增強 Windows 10 應用的用戶界面

在 Windows 10 應用中實現數據綁定

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章