你的網(wǎng)站正在建設中新聞稿件代發(fā)平臺
Unity 之 實現(xiàn)讀取代碼寫進Word文檔功能
- 前言
- 一,實現(xiàn)步驟
- 1.1 邏輯梳理
- 1.2 用到工具
- 二,實現(xiàn)讀寫文件
- 2.1 讀取目錄相關
- 2.2 讀寫文件
- 三,編輯器拓展
- 3.1 編輯器拓展介紹
- 3.2 實現(xiàn)界面可視化
- 四,源碼分享
- 4.1 工具目錄
- 4.2 完整代碼
前言
之所以有一篇這樣的文章,是因為最進在申請軟著時,要復制60頁的代碼到Word文檔中,手動復制了一次,下一次就在也不想去復制了。記得之前好像看見過有人用Py寫過這樣的工具,但是Py我有不熟。就有了使用Unity寫一個這樣的工具的想法,一起來看看效果吧~
看看效果:
只需要選擇想導出的腳本的根目錄和保存Word文件的根目錄(不選默認執(zhí)行到工程的Asset目錄);然后點擊:"開始讀取CS并寫Word"即可:
生成的腳本在WPS打開:
PS:生成的文檔完全按照代碼中的格式來處理的,沒有剔除空格和注釋。需要的童鞋可以自行拓展一下工具腳本。
一,實現(xiàn)步驟
1.1 邏輯梳理
基本思路
- 在文件夾中找到要復制的Csharp腳本
- 讀取Csharp腳本
- 保存讀取到的內容到Word文檔中
知識點
- 遍歷文件夾,根據(jù)后綴找到指定文件
- 讀取文件中的數(shù)據(jù)
- 將讀取到的數(shù)據(jù)保存到文檔中
- 編輯器拓展 - 分裝成工具
1.2 用到工具
用到的是NPOI庫:
- NPOI是指構建在POI 3.x版本之上的一個程序,NPOI可以在沒有安裝Office的情況下對Word或Excel文檔進行讀寫操作。
- NPOI是一個開源的C#讀寫Excel、WORD等微軟OLE2組件文檔的項目。
工程目錄:
PS:需要插件的同學,可以到文末工具資源包中獲取。
二,實現(xiàn)讀寫文件
這里只對用的邏輯進行講解,若需要全面學習文件的讀取相關,可以看我之前寫過的博文:
- 本地數(shù)據(jù)交互 – 文件概述 – File類介紹和使用
- 本地數(shù)據(jù)交互 – 文件相關類介紹 – 讀寫txt文本文件
2.1 讀取目錄相關
- 判斷是否存在目錄文件
private static string filePath = "Assets/ScriptTemp.docx";
// 檢查目錄是否存在
if (Directory.Exists(filePath))
{// 存在就刪除Directory.Delete(filePath);
}
- 創(chuàng)建指定文件
private static string filePath = "Assets/ScriptTemp.docx";
FileStream fs = new FileStream(savePath + filePath, FileMode.Create);
- 遍歷文件夾并篩選.cs后綴文件
/// <summary>
/// 遞歸文件夾下的cs文件
/// </summary>
/// <param name="folderPath"></param>
static void FileName(string folderPath)
{DirectoryInfo info = new DirectoryInfo(folderPath);foreach (DirectoryInfo item in info.GetDirectories()){FileName(item.FullName);}foreach (FileInfo item in info.GetFiles()){// 找到文件夾下的腳本if (item.FullName.EndsWith(".cs", StringComparison.Ordinal)){//將目錄緩存下來,之后讀文件的時候用//csScriptFullName.Add("Assets" + item.FullName.Replace(Application.dataPath, ""));}}
}
2.2 讀寫文件
- 讀取文件內容
這里不適用ReadToEnd方法是因為,我發(fā)現(xiàn)在后續(xù)寫入的時候會不會自動換行。所以使用循環(huán)的方式一行一行的讀取文件內容。
// 讀取腳本內容
StreamReader streamReader = new StreamReader(itemPath, Encoding.UTF8);
// 不適用
//string res = streamReader.ReadToEnd();
string res = "";
while (!streamReader.EndOfStream)
{res = streamReader.ReadLine() + "\n";//Debug.Log($"讀取腳本內容: {res}");
}
// 釋放資源
streamReader.Dispose();
- 寫入Word文件
引用命名空間,沒有的話就是沒有導入1.2說的.dll文件,在到文末工具包中下載:
using NPOI.XWPF.UserModel;
寫入Word步驟:創(chuàng)建文檔 —> 創(chuàng)建段落 —>設置格式 —> 寫入內容 —> 生成文檔
XWPFDocument doc = new XWPFDocument();
// 新建段落
XWPFParagraph paragraph = doc.CreateParagraph();
// 左對齊
paragraph.Alignment = ParagraphAlignment.LEFT;
// 新建運行行
XWPFRun run = paragraph.CreateRun();
// 設置顏色
run.SetColor("000000");
// 字體
run.FontFamily = "宋體";
// 字號
run.FontSize = 10;
// 設置內容
run.SetText("內容內容內容");// 寫入文檔
FileStream fs = new FileStream("文件目錄", FileMode.OpenOrCreate);
// 寫入
doc.Write(fs);
// 釋放資源
fs.Close();
fs.Dispose();
三,編輯器拓展
3.1 編輯器拓展介紹
- MenuItem
使用MenuItem
標識可以為編輯器添加新的菜單。點擊后執(zhí)行一些特定的邏輯,沒有額外的操作界面。只有靜態(tài)方法可以使用該標識,該標識可以把靜態(tài)方法轉換為菜單命令。
比如:
[MenuItem("Tools/生成Word")]
public static void CreateWindow()
{Debug.Log("todo... 點了按鈕");
}
- EditorWindow
繼承自EditorWindow
的類,可以實現(xiàn)更復雜的編輯器窗口功能。且這種窗口是可以自由內嵌到Unity編輯器內,共同組成編輯器的Layout
。
通過在OnGUI()函數(shù)內調用GUILayout、EditorGUILayout、GUI等類的一些方法來實現(xiàn)復雜的界面。
下面是結果常用Layout 示例代碼:
private void OnGUI()
{// 接受用戶輸入float size = EditorGUILayout.FloatField("輸入size:", size);EditorGUILayout.LabelField("提示信息 :");// 添加空行EditorGUILayout.Space();if (GUILayout.Button("點擊按鈕")){pathRoot = EditorUtility.OpenFolderPanel("路徑選擇", pathRoot, "");}
}
3.2 實現(xiàn)界面可視化
- 創(chuàng)建腳本引用Editor命名空間,繼承EditorWindow
- 新建OnGUI方法實現(xiàn),可視化界面
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;public class TestEditor : EditorWindow
{/// <summary>/// 讀取根目錄/// </summary>private static string pathRoot = "Assets";private static float size;[MenuItem("Tools/Test111")]public static void CreateWindow(){TestEditor window = GetWindow<TestEditor>(false, "測試調試窗口", true);window.Show();}// 顯示窗口private void OnGUI(){EditorGUILayout.LabelField("提示信息 :");size = EditorGUILayout.FloatField("輸入size:", size);// 換行EditorGUILayout.Space();EditorGUILayout.LabelField("換行后的提示信息 :");EditorGUILayout.Space();// 按鈕if (GUILayout.Button("選擇腳本路徑")){pathRoot = EditorUtility.OpenFolderPanel("路徑選擇", pathRoot, "");}}
}
四,源碼分享
4.1 工具目錄
打包后的工具目錄:
工程下載:源碼和步驟都在上面分享過了,若還有什么不明白的,可以 點擊鏈接下載 ,積分不夠的童鞋關注下方卡片,回復:“Word” 或者 “軟著腳本工具” 即可獲得Demo源碼~
4.2 完整代碼
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System;
using NPOI.XWPF.UserModel;
using System.Text;
using Debug = UnityEngine.Debug;public class CreateWordDocxEditor : EditorWindow
{/// <summary>/// 讀取根目錄/// </summary>private static string pathRoot = "Assets";/// <summary>/// 保存根目錄/// </summary>private static string savePath = "Assets";// 文件名稱private static string filePath = "/ScriptTemp.docx";[MenuItem("Tools/生成Word")]public static void CreateWindow(){CreateWordDocxEditor window = GetWindow<CreateWordDocxEditor>(false, "配置生成文檔需求", true);window.Show();}// 顯示窗口private void OnGUI(){EditorGUILayout.BeginHorizontal();EditorGUILayout.Space();EditorGUILayout.LabelField("當前腳本路徑 :" + pathRoot);EditorGUILayout.Space();EditorGUILayout.EndHorizontal();EditorGUILayout.BeginHorizontal();EditorGUILayout.Space();if (GUILayout.Button("選擇腳本路徑")){pathRoot = EditorUtility.OpenFolderPanel("路徑選擇", pathRoot, "");Debug.Log("選擇腳本路徑 : " + pathRoot);}EditorGUILayout.Space();EditorGUILayout.EndHorizontal();EditorGUILayout.BeginHorizontal();EditorGUILayout.Space();EditorGUILayout.LabelField("選擇保存路徑 :" + savePath);EditorGUILayout.Space();EditorGUILayout.EndHorizontal();EditorGUILayout.BeginHorizontal();EditorGUILayout.Space();if (GUILayout.Button("選擇保存路徑")){savePath = EditorUtility.OpenFolderPanel("路徑選擇", savePath, "");Debug.Log("選擇保存路徑 : " + savePath);}EditorGUILayout.Space();EditorGUILayout.EndHorizontal();EditorGUILayout.BeginHorizontal();EditorGUILayout.Space();if (GUILayout.Button("開始讀取CS并寫入Word")){CreateWordDocxFile();}EditorGUILayout.Space();EditorGUILayout.EndHorizontal();}static void CreateWordDocxFile(){Debug.Log("打包開始執(zhí)行");csScriptFullName.Clear();FileName(pathRoot);CreatOrOpenDoc();EditorUtility.ClearProgressBar();AssetDatabase.Refresh();Debug.Log("打包執(zhí)行結束");}/// <summary>/// 暫存遍歷到的CS腳本全路徑/// </summary>static List<string> csScriptFullName = new List<string>();/// <summary>/// 創(chuàng)建或打開文檔/// </summary>/// <param name="filePath"></param>private static void CreatOrOpenDoc(){try{// 檢查目錄是否存在if (Directory.Exists(savePath + filePath)){// 存在就刪除Directory.Delete(savePath + filePath);}FileStream fs = new FileStream(savePath + filePath, FileMode.OpenOrCreate);XWPFDocument doc = new XWPFDocument();int index = 0;foreach (var itemPath in csScriptFullName){//Debug.Log($"csScriptFullName[i]: {item}");// 讀取腳本內容StreamReader streamReader = new StreamReader(itemPath, Encoding.UTF8);//string res = streamReader.ReadToEnd();string res = "";while (!streamReader.EndOfStream){res = streamReader.ReadLine() + "\n";Debug.Log($"讀取腳本內容: {res}");// 新建段落 設置格式XWPFParagraph paragraph = doc.CreateParagraph();paragraph.Alignment = ParagraphAlignment.LEFT;XWPFRun run = paragraph.CreateRun();run.SetColor("000000");run.FontFamily = "宋體";run.FontSize = 10;run.SetText(res);}// 釋放資源streamReader.Dispose();EditorUtility.DisplayProgressBar("處理中...", "正在處理:" + itemPath,index * 1.0f / csScriptFullName.Count);index++;Debug.Log($"文件生成完成:{savePath} {filePath} ");}try{doc.Write(fs);}catch (Exception e){Debug.LogError($"文件不可寫入,請查看原因:{e}");}fs.Close();fs.Dispose();}catch (Exception e){Debug.LogError($"創(chuàng)建失敗,同名文件被打開!問題:{e}");}Debug.Log($"文件生成在: {savePath + filePath}");}/// <summary>/// 遞歸文件夾下的cs文件/// </summary>/// <param name="folderPath"></param>static void FileName(string folderPath){DirectoryInfo info = new DirectoryInfo(folderPath);foreach (DirectoryInfo item in info.GetDirectories()){FileName(item.FullName);}foreach (FileInfo item in info.GetFiles()){// 找到文件夾下的腳本if (item.FullName.EndsWith(".cs", StringComparison.Ordinal)){csScriptFullName.Add("Assets" + item.FullName.Replace(Application.dataPath, ""));}}}
}