内存映射文件mapping file:windows的C, C#实现
C++ 发送端:先用CreateFileMapping()创建共享内存,pBuf是内存中的内容,将内容写入其中。例如,在程序路径下有图片sample.jpg
,使用内存映射文件通过C++读取,再用C#读出内容并显示。
#include <cstdio> #include <windows.h> using namespace std; #define BUF_SIZE 388160 const char szName[] = "fileMapping_01"; // 共享内存的名字 int main() { char x; char msg[BUF_SIZE]; // 创建共享文件句柄 HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // 物理文件句柄 NULL, // 默认安全级别 PAGE_READWRITE, // 可读可写 0, // 高位文件大小 BUF_SIZE, // 地位文件大小 (LPCSTR)szName // 共享内存名称 ); char *pBuf = (char *)MapViewOfFile( hMapFile, // 共享内存的句柄 FILE_MAP_ALL_ACCESS, // 可读写许可 0, 0, BUF_SIZE ); FILE *fp = fopen("sample.jpg","rb"); int i=0; while(fscanf(fp,"%c",&pBuf[i])!=EOF) { i+=1; } pBuf[i]=0; fclose(fp); scanf("%c",&x); UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
C#接收端:新建C#的winform项目,为button1编写click方法,读取共享内存中的内容,展示在picturebox1上。
using System; using System.Drawing; using System.Windows.Forms; using System.IO; using System.IO.MemoryMappedFiles; namespace client_csharp { public partial class Form1 : Form { const int BUF_SIZE = 388160; public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { using (var mmf = MemoryMappedFile.OpenExisting("fileMapping_01")) { MemoryMappedViewAccessor viewAccessor = mmf.CreateViewAccessor(0, BUF_SIZE); byte[] charsInMMf = new byte[BUF_SIZE]; viewAccessor.ReadArray<byte>(0, charsInMMf, 0, BUF_SIZE); var p = Image.FromStream(new MemoryStream(charsInMMf)); pictureBox1.BackgroundImage = (Bitmap)p; } } } }
另外,用C编写接收端,从中读数据输出到控制台:
#include <cstdio> #include <windows.h> using namespace std; #define BUF_SIZE 1025 const char szName[] = "fileMapping_01"; // 共享内存的名字 int main() { // 创建共享文件句柄 HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // 物理文件句柄 NULL, // 默认安全级别 PAGE_READWRITE, // 可读可写 0, // 高位文件大小 BUF_SIZE, // 地位文件大小 (LPCSTR)szName // 共享内存名称 ); char *pBuf = (char *)MapViewOfFile( hMapFile, // 共享内存的句柄 FILE_MAP_ALL_ACCESS, // 可读写许可 0, 0, BUF_SIZE ); printf("%s",pBuf); UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
C#的发送端,类似,但C#的char是2字节的,若要与C进行字符上的通信,必须用byte进行数据流的交换,再对byte进行转换才可以。
using System; using System.IO; using System.IO.MemoryMappedFiles; using System.Runtime.InteropServices; using System.Threading; namespace sendfm { class Program { public struct ServiceMsg { public int Id; public long NowTime; } static void Main(string[] args) { String shareName = "sharedMem"; using (MemoryMappedFile mmf = MemoryMappedFile.CreateOrOpen(shareName, 1024000, MemoryMappedFileAccess.ReadWrite)) { bool mutexCreated; //进程间同步 var mutex = new Mutex(true, "testmapmutex", out mutexCreated); using (MemoryMappedViewStream stream = mmf.CreateViewStream()) //创建文件内存视图流 { var writer = new BinaryWriter(stream); for (int i = 0; i < 5; i++) { writer.Write(10*i); Console.WriteLine("{0}位置写入流:{0}", i); } } mutex.ReleaseMutex(); Console.WriteLine("启动状态服务,按【回车】读取共享内存数据"); Console.ReadLine(); mutex.WaitOne(); using (MemoryMappedViewStream stream = mmf.CreateViewStream()) { var reader = new BinaryReader(stream); for (int i = 0; i < 10; i++) { Console.WriteLine("{1}位置:{0}", reader.ReadInt32(), i); } } using (MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor(1024, 10240)) { int colorSize = Marshal.SizeOf(typeof(ServiceMsg)); ServiceMsg color; for (int i = 0; i < 50; i += colorSize) { accessor.Read(i, out color); Console.WriteLine("{1}\tNowTime:{0}", new DateTime(color.NowTime), color.Id); } } mutex.ReleaseMutex(); } } } }