Unity 之 实现读取代码写进Word文档功能实现 -- 软著脚本生成工具
Unity 之 实现读取代码写进Word文档功能
- 前言
- 一,实现步骤
- 1.1 逻辑梳理
- 1.2 用到工具
- 二,实现读写文件
- 2.1 读取目录相关
- 2.2 读写文件
- 三,编辑器拓展
- 3.1 编辑器拓展介绍
- 3.2 实现界面可视化
- 四,源码分享
- 4.1 工具目录
- 4.2 完整代码
前言
之所以有一篇这样的文章,是因为最进在申请软著时,要复制60页的代码到Word文档中,手动复制了一次,下一次就在也不想去复制了。记得之前好像看见过有人用Py写过这样的工具,但是Py我有不熟。就有了使用Unity写一个这样的工具的想法,一起来看看效果吧~
看看效果:
只需要选择想导出的脚本的根目录和保存Word文件的根目录(不选默认执行到工程的Asset目录);然后点击:"开始读取CS并写Word"即可:
生成的脚本在WPS打开:
PS:生成的文档完全按照代码中的格式来处理的,没有剔除空格和注释。需要的童鞋可以自行拓展一下工具脚本。
一,实现步骤
1.1 逻辑梳理
基本思路
- 在文件夹中找到要复制的Csharp脚本
- 读取Csharp脚本
- 保存读取到的内容到Word文档中
知识点
- 遍历文件夹,根据后缀找到指定文件
- 读取文件中的数据
- 将读取到的数据保存到文档中
- 编辑器拓展 - 分装成工具
1.2 用到工具
用到的是NPOI库:
- NPOI是指构建在POI 3.x版本之上的一个程序,NPOI可以在没有安装Office的情况下对Word或Excel文档进行读写操作。
- NPOI是一个开源的C#读写Excel、WORD等微软OLE2组件文档的项目。
工程目录:
PS:需要插件的同学,可以到文末工具资源包中获取。
二,实现读写文件
这里只对用的逻辑进行讲解,若需要全面学习文件的读取相关,可以看我之前写过的博文:
- 本地数据交互 – 文件概述 – File类介绍和使用
- 本地数据交互 – 文件相关类介绍 – 读写txt文本文件
2.1 读取目录相关
- 判断是否存在目录文件
private static string filePath = "Assets/ScriptTemp.docx";
// 检查目录是否存在
if (Directory.Exists(filePath))
{// 存在就删除Directory.Delete(filePath);
}
- 创建指定文件
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方法是因为,我发现在后续写入的时候会不会自动换行。所以使用循环的方式一行一行的读取文件内容。
// 读取脚本内容
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步骤:创建文档 —> 创建段落 —>设置格式 —> 写入内容 —> 生成文档
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
标识可以为编辑器添加新的菜单。点击后执行一些特定的逻辑,没有额外的操作界面。只有静态方法可以使用该标识,该标识可以把静态方法转换为菜单命令。
比如:
[MenuItem("Tools/生成Word")]
public static void CreateWindow()
{Debug.Log("todo... 点了按钮");
}
- EditorWindow
继承自EditorWindow
的类,可以实现更复杂的编辑器窗口功能。且这种窗口是可以自由内嵌到Unity编辑器内,共同组成编辑器的Layout
。
通过在OnGUI()函数内调用GUILayout、EditorGUILayout、GUI等类的一些方法来实现复杂的界面。
下面是结果常用Layout 示例代码:
private void OnGUI()
{// 接受用户输入float size = EditorGUILayout.FloatField("输入size:", size);EditorGUILayout.LabelField("提示信息 :");// 添加空行EditorGUILayout.Space();if (GUILayout.Button("点击按钮")){pathRoot = EditorUtility.OpenFolderPanel("路径选择", pathRoot, "");}
}
3.2 实现界面可视化
- 创建脚本引用Editor命名空间,继承EditorWindow
- 新建OnGUI方法实现,可视化界面
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("打包开始执行");csScriptFullName.Clear();FileName(pathRoot);CreatOrOpenDoc();EditorUtility.ClearProgressBar();AssetDatabase.Refresh();Debug.Log("打包执行结束");}/// <summary>/// 暂存遍历到的CS脚本全路径/// </summary>static List<string> csScriptFullName = new List<string>();/// <summary>/// 创建或打开文档/// </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($"创建失败,同名文件被打开!问题:{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, ""));}}}
}
相关文章:

Unity 之 实现读取代码写进Word文档功能实现 -- 软著脚本生成工具
Unity 之 实现读取代码写进Word文档功能前言一,实现步骤1.1 逻辑梳理1.2 用到工具二,实现读写文件2.1 读取目录相关2.2 读写文件三,编辑器拓展3.1 编辑器拓展介绍3.2 实现界面可视化四,源码分享4.1 工具目录4.2 完整代码前言 之所…...

Typora图床配置:Typora + PicGo + 阿里云OSS
文章目录一、前景提要二、相关链接三、搭建步骤1. 购买阿里云对象存储OSS2. 对象存储OSS:创建Bucket3. 阿里云:添加OSS访问用户及权限4. 安装Typora5. 配置PicGo方法一:使用PicGo-Core (Command line)方法二:使用PicGo(app)6. 最后…...
二进制搭建以太坊2.0节点-2023最新详细版文档
文章目录 一、配置 JWT 认证二、部署执行节点geth2.1 下载geth二进制文件2.2 geth节点启动三、部署共识节点Prysm3.1 下载Prysm脚本3.2 Prysm容器生成四、检查节点是否同步完成4.1 检查geth执行节点4.2 检查prysm共识节点4.3 geth常用命令五、节点同步详细说明5.1 启动时日志5.…...

如何简化跨网络安全域的文件发送流程,大幅降低IT人员工作量?
为什么要做安全域的隔离? 随着企业数字化转型的逐步深入,企业投入了大量资源进行信息系统建设,信息化程度日益提升。在这一过程中,企业也越来越重视核心数据资产的保护,数据资产的安全防护成为企业面临的重大挑战。 …...

带你深入了解c语言指针后续
前言 🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻推荐专栏: 🍔🍟🌯 c语言进阶 🔑个人信条: 🌵知行合一 🍉本篇简介:>:介绍c语言中有关指针更深层的知识. 金句分享: ✨在该…...

借助Intune无感知开启Bitlocker
希望使用 Intune 部署 BitLocker,但不知道从哪里开始?这是人们最开始使用 Intune 时最常见的问题之一。在本博客中,你将了解有关使用 Intune 管理 BitLocker 的所有信息,包括建议的设置、BitLocker CSP 在客户端上的工作方式&…...

零基础该如何转行Python工程师?学习路线是什么?
最近1年的主要学习时间,都投资到了 python 数据分析和数据挖掘上面来了,虽然经验并不是十分丰富,但希望也能把自己的经验分享下,最近也好多朋友给我留言,和我聊天,问我python该如何学习,才能少走…...

Go项目(商品微服务-1)
文章目录简介建表protohandler商品小结简介 商品微服务主要在于表的设计,建哪些表?表之间的关系是怎样的? 主要代码就是 CURD表和字段的设计是一个比较有挑战性的工作,比较难说清楚,也需要经验的积累,这里…...

机器学习——集成学习
引言 集成学习:让机器学习效果更好,单个不行,群殴走起。 分类 1. Bagging:训练多个分类器取平均(m代表树的个数)。 2.Boosting(提升算法):从弱学习器开始加,通过加权来进行训练。…...

VS编译系统 实用调试技巧
目录什么是bug?调试是什么?有多重要?debug和release的介绍windows环境调试介绍、一些调试实例如何写出(易于调试)的代码编程常见的错误什么是bug?其实bug在英文翻译中有表示臭虫的含义,因为第一次被发现的导致计算机…...

【华为OD机试模拟题】用 C++ 实现 - GPU 调度(2023.Q1)
最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明GPU 调度题目输入输出示例一输入输出说明示例二输入输出说明Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。...
腾讯前端必会react面试题合集
React-Router的路由有几种模式? React-Router 支持使用 hash(对应 HashRouter)和 browser(对应 BrowserRouter) 两种路由规则, react-router-dom 提供了 BrowserRouter 和 HashRouter 两个组件来实现应用的…...

Linux搭建SVN服务器,并内网穿透实现公网远程访问
文章目录1. Ubuntu安装SVN服务2. 修改配置文件2.1 修改svnserve.conf文件2.2 修改passwd文件2.3 修改authz文件3. 启动svn服务4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射本地端口5. 测试公网访问6. 配置固定公网TCP端口地址6.1 保留一个固定的公网TCP端口地址6.2 配置…...

C++STL之list的模拟实现
目录 一.list准备 二. iterator迭代器 1._list_iterator 2.begin()、end() 3.const_begin()、const_end() 4.!&& 5. && -- 6.operator* 7.operator-> 三.Modify(修改) 1.insert() 2.erase() 3.push_back() && push_front() 4.pop_bac…...

为什么硬件性能监控很重要
当今的混合网络环境平衡了分布式网络和现代技术的实施。但它们并不缺少一个核心组件:服务器。保持网络正常运行时间归结为监控和管理导致网络停机的因素。极有可能导致性能异常的此类因素之一是硬件。使用硬件监控器监控网络硬件已成为一项关键需求。 硬件监视器是…...
HTTP缓存
HTTP缓存HTTP缓存引发的一个问题HTTP缓存的作用HTTP缓存的分类强制缓存协商缓存(解决强缓存下资源不更新问题)缓存策略HTTP缓存引发的一个问题 有一次在开发移动端H5项目,UI提了几个UI问题,经过样式调试,android上没有…...

SPI设备树处理过程
SPI设备树处理过程 文章目录SPI设备树处理过程参考资料:一、 spi_device结构体二、 SPI设备树格式2.1 SPI Master2.2 SPI Device2.3 设备树示例三、设备树实例3.1 使用GPIO模拟的SPI控制器3.2 IMX6ULL SPI控制器四、 设备树处理过程致谢参考资料: 内核头…...
数据有哪些重要的作用?
我们正处在科技高速发展的时代,如今互联网已经与我们的生活息息相关,我们每天在互联网产生大量的数据,这些数据散落在网络中看似没有怎么作用,但是这些数据经过系统的处理整合起来确实非常有价值的。 一、 发展大数据技术可以提高…...

spring面试题总结
1、spring是什么? spring是一个轻量级IOC和AOP容器框架,是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用的开发,开发者只需要关注业务需求即可: core container 容器组件 spring context,…...

使用MUI与H5+构建移动端app
前言 通过mui构建APP 效果图: <!DOCTYPE html> <html> <head><meta charset...

19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...

如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...

初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...