Unity3D在PC端快速高效的調取系統窗口,獲取本地文件和保存文件到本地

              Unity3D在PC端快速高效的調取系統窗口,獲取本地文件和保存文件到本地


目錄

1、博客介紹

2、內容

(1)效果展示

(2)核心方法

3、打開窗口獲取本地文件

4、打開窗口保存

5、封裝模塊化

6、推送

7、結語


1、博客介紹

       之前有功能需要在PC端調取Windows的系統窗口來獲取或者保存文件到本地,在網上扒了些資料,都是大同小異,基本都是利用win32的方式來調,這裏抽取了一個比較好的方式來介紹,主要是網上扒出來的都沒詳細介紹,看不太懂,這裏做些簡短的介紹,並且最後把功能攏一攏,打成一個dll,方便以後用,功能會慢慢補充,更新到github上面,有興趣可以收藏關注後續。


2、內容

(1)效果展示

(2)核心方法

我們先把核心代碼放上來,再分析好吧,看的同學,先大致把下面代碼瀏覽一下,代碼後面再做分析。

using System.Runtime.InteropServices;
using System;

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class FileDialogData
{
    public int structSize = 0;                  //結構的內存大小
    public IntPtr dlgOwner = IntPtr.Zero;       //設置對話框的句柄
    public IntPtr instance = IntPtr.Zero;       //根據flags標誌的設置,確定instance是誰的句柄,不設置則忽略
    public String filter = null;                //調取文件的過濾方式
    public String customFilter = null;          //一個靜態緩衝區 用來保存用戶選擇的篩選器模式
    public int maxCustFilter = 0;               //緩衝區的大小
    public int filterIndex = 0;                 //指向的緩衝區包含定義過濾器的字符串對
    public String file = null;                  //存儲調取文件路徑
    public int maxFile = 0;                     //存儲調取文件路徑的最大長度 至少256
    public String fileTitle = null;             //調取的文件名帶拓展名
    public int maxFileTitle = 0;                //調取文件名最大長度
    public String initialDir = null;            //最初目錄
    public String title = null;                 //打開窗口的名字
    public int flags = 0;                       //初始化對話框的一組位標誌  參數類型和作用查閱官方API
    public short fileOffset = 0;                //文件名前的長度
    public short fileExtension = 0;             //拓展名前的長度
    public String defExt = null;                //默認的拓展名
    public IntPtr custData = IntPtr.Zero;       //傳遞給lpfnHook成員標識的鉤子子程的應用程序定義的數據
    public IntPtr hook = IntPtr.Zero;           //指向鉤子的指針。除非Flags成員包含OFN_ENABLEHOOK標誌,否則該成員將被忽略。
    public String templateName = null;          //模塊中由hInstance成員標識的對話框模板資源的名稱
    public IntPtr reservedPtr = IntPtr.Zero;
    public int reservedInt = 0;
    public int flagsEx = 0;                     //可用於初始化對話框的一組位標誌
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class OpenDialogData : FileDialogData
{

}

/*這是C#引用非託管的C/C++的DLL的一種定義定義結構體的方式,主要是爲了內存中排序,LayoutKind有兩個屬性Sequential和Explicit

Sequential表示順序存儲,結構體內數據在內存中都是順序存放的Explicit表示精確佈局,需要用FieldOffset()設置每個成員的位置這都是

爲了使用非託管的指針準備的,知道什麼意思就行,C#的CLR提供了更爲靈活的自動管理方式,所以對C#來說可有可無。

CharSet=CharSet.Ansi表示編碼方式
*/
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class SaveDialogData : FileDialogData
{

}

public class OpenFileDialog
{
    [DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
    public static extern bool GetOpenFileName([In, Out] OpenDialogData ofd);
}
public class SaveFileDialog
{
    [DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
    public static extern bool GetSaveFileName([In, Out] SaveDialogData ofd);
}

 

       我們的核心思想是,通過C#去引用Comdlg32.dll這個Windows上C++寫的的dll,這個dll就是windows上關於系統窗口的一個類庫,引用方法我們用了[ DllImport ]的方法,該方法博主前一篇文章有介紹,不懂得可以跳過去,本文章結尾也有附贈的傳送門,這裏就不多做介紹了,代碼中還有一個定義方法[ StructLayout ],該特性在博主的上一篇博文中也有介紹,不懂得先跳過去看一下,該特性主要就是保證我們定義的數據結構順序不會被打亂。

核心1:FileDialogData ,這個是我們定義的一個數據結構,當然不是隨便定義的,這個是Comdlg32.dll內和窗口相關的數據結構,我們定義的結構必須和庫內的數據結構保持一致,裏面包含了我們需要窗口的相關信息,這裏面的數據,一部分是我們打開窗口前要提前設置的,一部分是我們獲取或者保存本地文件後,纔會被賦值的,註釋我都寫在上述代碼裏了,一條條看,還有不懂得,從下邊官方解釋裏看。

核心2:OpenDialogData,SaveDialogData 這裏我們通過繼承的方式,分了兩個不同的類出來,方便之後不同窗口的賦值。

核心3:OpenFileDialog,SaveFileDialog 這裏,我們通過外部引用的方式,用C#調用的Comdlg32.dll內的C++方法,然後將窗口相關的信息,賦值到我們定義的數據結構上。

 

官方C++APIhttps://docs.microsoft.com/zh-cn/windows/win32/api/commdlg/ns-commdlg-openfilenamea


3、打開窗口獲取本地文件

        提前賦值的數據 
     
        CustomOpenData = new OpenDialogData();
        CustomOpenData.structSize = Marshal.SizeOf(CustomOpenData);
        CustomOpenData.filter =  "All Files\0*.*\0\0";
        CustomOpenData.file = new string(new char[256]);
        CustomOpenData.maxFile = CustomOpenData.file.Length;
        CustomOpenData.fileTitle = new string(new char[1000]);
        CustomOpenData.maxFileTitle = CustomOpenData.fileTitle.Length;
        CustomOpenData.initialDir = Application.dataPath.Replace('/', '\\') + "\\aaa\\";
        CustomOpenData.title = "打開項目";
        CustomOpenData.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000200 | 0x00000008;

注意:這裏面我們首先實例化了一個OpenDialogData,這個就是我們之前根據庫內C++的數據結構自定義的那個數據結構,提前賦值的這些屬性,這裏不再單獨介紹,上邊代碼每條都有註釋,可以去看一眼。

    /// <summary>
    /// 打開窗口
    /// </summary>
    /// <returns></returns> 和該文件相關的數據
    public OpenDialogData OpenFileDlg()
    {
        if (OpenFileDialog.GetOpenFileName(CustomOpenData))
        {
            return CustomOpenData;
        }
        return null;
    }

注意:這個是重中之重,就是該方法打開窗口,GetOpenFileName是C++的方法,我們將數據結構作爲參數輸入,如果我們在打開的窗口內選擇了文件並打開,則會執行return CustomOpenData,將我們賦值好的數據結構傳回來,如果取消窗口了就返回 null,我們可以在CustomOpenData內查看,選中文件的文件名,路徑,拓展名等等的信息。

 


4、打開窗口保存

       保存和打開基本沒啥區別,不同的就是數據結構初始賦值有些不一樣,多了一個保存文件的拓展名defExt,然後調取的C++方式是GetSaveFileName

        提前賦值的數據
       
        CustomSaveData = new SaveDialogData();
        CustomSaveData.structSize = Marshal.SizeOf(CustomSaveData);
        CustomSaveData.filter = "All files (*.*)|*.*";
        CustomSaveData.file = new string(new char[256]);
        CustomSaveData.maxFile = CustomSaveData.file.Length;
        CustomSaveData.fileTitle = new string(new char[64]);
        CustomSaveData.maxFileTitle = CustomSaveData.fileTitle.Length;
        CustomSaveData.initialDir = Application.dataPath.Replace('/', '\\') ;  // default path  
        CustomSaveData.title = "保存項目";
        CustomSaveData.defExt = "txt";
        CustomSaveData.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000200 | 0x00000008;
    
    打開保存窗口的方法

    public SaveDialogData SaveFileDlg()
    {
        if (SaveFileDialog.GetSaveFileName(CustomSaveData))
        {
            return CustomSaveData;
        }
        return null;
    }

5、封裝模塊化

        根據上述的核心思想,博主準備將這個功能拓展拓展,打成Dll,用的時候更方便,目前比較簡單,調用方式如下,後續博主還會慢慢的更新功能,比如直接打開一個文本或者Json直接可以讀取內部數據等等的,dll和源碼都在github上,有興趣可以下一下。

    /// <summary>
    /// 打開本地文件
    /// </summary>
    public void OpenProject()
    {
        FileDialogMgr mgr = new FileDialogMgr();    //實例化窗口管理器
        mgr.SetFilteringWay(EnumFilteringWay.Png);  //設置過濾方式
        OpenDialogData mgrData = mgr.OpenFileDlg(); //獲取本地文件的信息
    }
    /// <summary>
    /// 保存文件到本地
    /// </summary>
    public void SaveProject()
    {
        FileDialogMgr mgr = new FileDialogMgr();    //實例化窗口管理器
        mgr.SetFileExtension("txt");                //設置保存文件的後綴
        SaveDialogData mgrData = mgr.SaveFileDlg(); //獲取保存文件的信息
    }

6、推送

github:https://github.com/KingSun5/FileDialogMgr

dllImport介紹:https://blog.csdn.net/Mr_Sun88/article/details/100626798

StructLayout介紹:https://blog.csdn.net/Mr_Sun88/article/details/101323222


7、結語

       若是覺得博主的文章寫的不錯,不妨關注一下博主,github點Star,star,star,點贊一下博文,另博主能力有限,若文中有出現什麼錯誤的地方,歡迎各位評論指摘。

       QQ交流羣:806091680(Chinar)

       該羣爲CSDN博主Chinar所創,推薦一下!我也在羣裏!

 

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