程式之間的通訊是為了解決不同程式之間的資料傳輸問題,這樣可以讓不同程式互動資料。實現程式通訊的方式:1、剪下板;2、COM;3、記憶體對映檔案;4、WCF
1、剪下板Clipboard在程式間傳送物件
剪下板是一個供應用程式使用的公有區域。在.NET中定一個了一個DataFormats類,此類包含一些靜態欄位,定義了剪下板中可以存放的資料型別。使用Clipboard類可以向剪下板中放入資料。
IDataObject data = Clipboard.GetDataObject(); if (data.GetDataPresent(DataFormats.Text)) { label1.Text = data.GetData(DataFormats.Text).ToString(); }
將自定義的資料放置到剪下板,自定義一個圖片類,並標記為可序列化(此處使用的名稱空間是:TestClipboard)。將自定義資料型別物件放置到剪下板的關鍵是DataObject類,它實現了IDataObject介面。它就像一個容器,存放將被放置在剪下板上的資料。
[Serializable] public class MyPic { /// <summary> /// 圖片 /// </summary> public Image Img; /// <summary> /// 圖片資訊 /// </summary> public string ImgInfo; } public void SetMyPicToClipboard() { MyPic obj = new MyPic(); obj.Img = Properties.Resources.Image; obj.ImgInfo = "測試將自定義型別儲存至剪下板"; //建立資料物件,並將資料裝入 IDataObject dataObj = new DataObject(obj); //其他型別也可以放置在同一資料物件中 /* dataObj.SetData(DataFormats.UnicodeText, "測試文字"); dataObj.SetData(DataFormats.Bitmap, Properties.Resources.Image); */ //複製到剪下板,第二個參數列示程式退出時不清空 Clipboard.SetDataObject(dataObj, true); }
但是,使用Clipboard.SetDataObject方法將一個DataObject物件放到剪下板後,外界訪問時,需要指定物件的完整型別名稱。如果某種資料型別只能在指定的程式中訪問,則可以使用該方式,指定名稱空間。
//首先判斷剪下板上是否有我的資料:需要完全限定名稱空間型別 if (Clipboard.ContainsData("WindowsFormsApplication1.MyPic")) { IDataObject dataObj = Clipboard.GetDataObject();//讀取資料 MyPic myPic = dataObj.GetData("WindowsFormsApplication1.MyPic") as MyPic;//轉換資料 pictureBox1.Image = myPic.Img; textBox1.Text = myPic.ImgInfo; }
2、使用FileSystemWatcher實現程式同步
/// <summary> /// 實現寫入資料 /// </summary> /// <param name="fileName"></param> public void SetText(string fileName) { using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.Read)) { using (StreamWriter writer = new StreamWriter(fs, Encoding.UTF8)) { writer.Write("內容"); } } } /// <summary> /// 實現讀取資料 /// </summary> /// <param name="fileName"></param> public void ReadText(string fileName) { using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { using (StreamReader reader = new StreamReader(fs, Encoding.UTF8)) { string txt = reader.ReadToEnd(); } } }
然後,使用FileSystemWatcher元件的Changed事件監控檔案是否發生改變。在網路應用程式中,可以使用此元件監控特定的專用於上傳檔案的資料夾,當發現使用者上傳檔案之後,系統可以自動啟動一系列的處理流程。
3、使用記憶體對映檔案(Memory Mapped File)實現程式通訊
含義:在記憶體中開闢一塊存放資料的專用區域,這區域與硬碟上特定的檔案相對應。程式將這塊記憶體區域對映到自己的地址空間中,完成像訪問普通記憶體一樣訪問它。windows中的系統分頁檔案和休眠檔案就是如此實現的。需要引用名稱空間System.IO.MemoryMappedFiles。
MemoryMappedFile物件表示一個記憶體對映檔案,通過它的CreateFromFile方法根據磁碟現有檔案建立記憶體對映檔案(注意,使用完後要立即釋放資源,實際上它對應的是作業系統的核心物件)。其中,記憶體對映的容量在未指定時,預設與檔案大小相等。在指定大小時,它的值不能小於檔案的現有大小。若指定的大小大於磁碟檔案大小,磁碟檔案會自動增長到記憶體對映檔案宣告的容量大小。
建立MemoryMappedFile物件後,不能直接對其進行讀寫,必須使用MemoryMappedViewAccessor物件(記憶體對映檢視訪問物件)操作 。可以用MemoryMappedFile物件的方法建立一個訪問物件。其中,可以指定需要訪問檔案的範圍,從第幾個位元組到第幾個位元組。在寫入引數時,也需要指明想哪個位置寫入什麼。同時也可以使用MemoryMappedViewAccessor的Read方法讀取資料。
MemoryMappedFile memoryFile = MemoryMappedFile.CreateFromFile("Text.Config", FileMode.OpenOrCreate, "Config", 1400);//kb; MemoryMappedViewAccessor accessor = memoryFile.CreateViewAccessor(0, 1024); accessor.Write(0, '2');
在同一個程式中,可以針對同一個記憶體對映檔案建立多個“記憶體對映檢視訪問物件”,從而允許同時修改同一個檔案的不同部分,在關閉這些物件時,由作業系統保證將所有修改都寫回原始檔案。
MemoryMappedFile memoryFile = MemoryMappedFile.CreateFromFile("Text.Config", FileMode.OpenOrCreate, "Config", 1400);//kb; MemoryMappedViewStream stream = memoryFile.CreateViewStream(); MyPic obj = new MyPic(); stream.Seek(0, SeekOrigin.Begin); new BinaryFormatter().Serialize(stream, obj);
4、使用WCF通過管道實現程式通訊
“管道(Pipe)”是Windows所提供的一種程式間通訊機制,用於在兩個程式間相互傳送資料。Windows提供了兩種型別管道:匿名管道(Anonymous Pipe)、命名管道(Named Pipe)
- 匿名管道:只允許單向通訊,由於沒有名字,因此要通訊的兩個程式應該是父子關係,父程式在建立子程式時,負責將代表匿名管道的控制程式碼傳送給子程式,子程式可以通過該控制程式碼獲取父程式傳輸的資料。其優點是佔用資源少、效率高;缺點是通訊程式必須為父子關係,限制了使用場景。
- 命名管道:這種型別的管道擁有一個在本機唯一的名字,可以用於在一個服務程式和多個客戶程式之間進行單/雙向通訊。命名管道是基於訊息的通訊模式,即一個程式一次可以向另一方程式連續發生多個訊息(訊息之間通過訊息的定界符進行劃分),接收方通過定界符提取完整的訊息。
在名稱空間System.IO.Pipes中,提供了一些用於實現基於管道的程式間通訊,如AnonymousPipeClientStream和AnonymousPipeServerStream可用於實現匿名管道,而NamedPipeClientStream和NamedPipeServerStream可以實現命名管道。但相對於WCF,其比較繁瑣,WCF的管道程式通訊更加簡便和靈活。
WCF應用程式使用命名管道實現程式通訊:WCF提供了一個NetNamedPipeBinding繫結,它可以在地層使用命名管道實現程式通訊。