<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title><![CDATA[木子屋 - Win编程]]></title>
<link>http://www.mzwu.com/</link>
<description><![CDATA[Dnawo&#39;s BLOG]]></description>
<language>zh-cn</language>
<copyright><![CDATA[Copyright 2005 PBlog3 v2.8]]></copyright>
<webMaster><![CDATA[service@mzwu.com(Dnawo)]]></webMaster>
<generator>PBlog2 v2.4</generator> 
<image>
	<title>木子屋</title>
	<url>http://www.mzwu.com/images/logos.gif</url>
	<link>http://www.mzwu.com/</link>
	<description>木子屋</description>
</image>

			<item>
			<link>http://www.mzwu.com/article.asp?id=5231</link>
			<title><![CDATA[C#生成文件清单命令行工具（DeepSeek版）]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Wed,27 May 2026 23:09:02 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=5231</guid>
		<description><![CDATA[<img src="http://www.mzwu.com/pic/202605/019.jpg" border="0" alt=""/><br/><br/>FileList 是 DeepSeek 编写的 Windows 控制台工具，用于快速生成指定文件夹下的文件清单，并将结果保存为 FileList.txt 文件。它支持两种输出模式：<br/><br/>■ 树形模式（默认） —— 以树状结构展示目录和文件，清晰直观。<br/>■ 内容模式 —— 输出每个文件的完整路径和文本内容，便于批量查看或搜索。<br/><br/>支持按扩展名过滤（包含或排除），自动跳过非文本文件或超大文件，完美兼容命令行和双击运行两种使用场景。<br/><br/><strong>命令行格式</strong><br/><br/><div class="UBBPanel quotePanel"><div class="UBBTitle"><img src="http://www.mzwu.com/images/quote.gif" style="margin:0px 2px -3px 0px" alt="引用内容"/> 引用内容</div><div class="UBBContent">FileList.exe [文件夹路径] [包含扩展名] [排除扩展名] [是否显示内容]</div></div><br/>调用示例：<br/><br/><div class="UBBPanel quotePanel"><div class="UBBTitle"><img src="http://www.mzwu.com/images/quote.gif" style="margin:0px 2px -3px 0px" alt="引用内容"/> 引用内容</div><div class="UBBContent">REM 查看帮助<br/>FileList.exe /?<br/><br/>REM 列出当前目录树<br/>FileList.exe<br/><br/>REM 列出 D:\Project 下所有 .cs 和 .csproj 文件（树形）<br/>FileList.exe &#34;D:\Project&#34; &#34;.cs|.csproj&#34;<br/><br/>REM 排除 .tmp 和 .log 文件，并显示文件内容<br/>FileList.exe &#34;D:\Project&#34; &#34;&#34; &#34;.tmp|.log&#34; true</div></div><br/><strong>程序代码</strong><br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code29003);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code29003>using System;<br/>using System.Collections.Generic;<br/>using System.Diagnostics;<br/>using System.IO;<br/>using System.Linq;<br/>using System.Management;<br/>using System.Text;<br/><br/>namespace FileList<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;class Program<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 常见文本文件扩展名集合，用于内容模式判断文件是否为文本类型。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 不区分大小写。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static readonly HashSet&lt;string&gt; TextExtensions = new HashSet&lt;string&gt;(<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringComparer.OrdinalIgnoreCase)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#34;.txt&#34;, &#34;.md&#34;, &#34;.markdown&#34;, &#34;.html&#34;, &#34;.htm&#34;, &#34;.css&#34;, &#34;.js&#34;, &#34;.ts&#34;, &#34;.tsx&#34;, &#34;.jsx&#34;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#34;.json&#34;, &#34;.xml&#34;, &#34;.csv&#34;, &#34;.config&#34;, &#34;.cs&#34;, &#34;.vb&#34;, &#34;.cpp&#34;, &#34;.c&#34;, &#34;.h&#34;, &#34;.hpp&#34;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#34;.py&#34;, &#34;.php&#34;, &#34;.asp&#34;, &#34;.aspx&#34;, &#34;.ini&#34;, &#34;.log&#34;, &#34;.bat&#34;, &#34;.cmd&#34;, &#34;.sh&#34;, &#34;.yml&#34;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#34;.yaml&#34;, &#34;.sql&#34;, &#34;.svg&#34;, &#34;.rb&#34;, &#34;.java&#34;, &#34;.pl&#34;, &#34;.pm&#34;, &#34;.go&#34;, &#34;.rs&#34;, &#34;.toml&#34;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#34;.lock&#34;, &#34;.gitignore&#34;, &#34;.gitattributes&#34;, &#34;.editorconfig&#34;, &#34;.env&#34;, &#34;.proto&#34;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 程序入口。支持4个位置参数，按顺序为：<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 1. 文件夹路径（空则当前目录）<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 2. 包含扩展名（|分隔）<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 3. 排除扩展名（|分隔）<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 4. 是否显示文件内容（true/false）<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static int Main(string[] args)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 检测当前运行环境是否为 cmd 或 powershell，决定最终是否等待按键<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bool isCmdEnv = IsRunningFromCmd();<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 处理帮助请求<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (args.Length &gt;= 1 &amp;&amp; !string.IsNullOrEmpty(args[0]) &amp;&amp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(args[0] == &#34;/?&#34; || args[0].Equals(&#34;-h&#34;, StringComparison.OrdinalIgnoreCase) ||<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; args[0].Equals(&#34;--help&#34;, StringComparison.OrdinalIgnoreCase)))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ShowHelp();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!isCmdEnv) WaitForKey();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 解析第一个参数：文件夹路径<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string folderPath = null;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (args.Length &gt;= 1 &amp;&amp; !string.IsNullOrEmpty(args[0]))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;folderPath = args[0];<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (string.IsNullOrEmpty(folderPath))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;folderPath = AppDomain.CurrentDomain.BaseDirectory; // 默认为 exe 所在目录<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 解析第二个参数：包含扩展名列表<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string[] includeExts = null;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (args.Length &gt;= 2 &amp;&amp; !string.IsNullOrEmpty(args[1]))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;includeExts = NormalizeExtensions(<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;args[1].Split(new char[] { &#39;|&#39; }, StringSplitOptions.RemoveEmptyEntries));<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 解析第三个参数：排除扩展名列表<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string[] excludeExts = null;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (args.Length &gt;= 3 &amp;&amp; !string.IsNullOrEmpty(args[2]))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;excludeExts = NormalizeExtensions(<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;args[2].Split(new char[] { &#39;|&#39; }, StringSplitOptions.RemoveEmptyEntries));<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 解析第四个参数：是否显示文件内容<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bool showContent = false;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (args.Length &gt;= 4 &amp;&amp; !string.IsNullOrEmpty(args[3]))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!bool.TryParse(args[3], out showContent))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.Error.WriteLine(&#34;Error: fourth parameter must be &#39;true&#39; o&#114; &#39;false&#39;.&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!isCmdEnv) WaitForKey();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 检查目录是否存在<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!Directory.Exists(folderPath))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.Error.WriteLine($&#34;Error: directory not found: {folderPath}&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!isCmdEnv) WaitForKey();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 检查输出路径是否是已存在的目录<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string outputFile = Path.Combine(folderPath, &#34;FileList.txt&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (Directory.Exists(outputFile))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.Error.WriteLine($&#34;Error: &#39;{outputFile}&#39; is a directory, cannot write.&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!isCmdEnv) WaitForKey();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 根据模式生成清单<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (showContent)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GenerateContentList(folderPath, outputFile, includeExts, excludeExts);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GenerateTreeList(folderPath, outputFile, includeExts, excludeExts);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;FileList.txt cr&#101;ated successfully.&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!isCmdEnv) WaitForKey();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch (UnauthorizedAccessException ex)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.Error.WriteLine($&#34;Error: access denied - {ex.Message}&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!isCmdEnv) WaitForKey();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch (IOException ex)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.Error.WriteLine($&#34;Error: I/O error - {ex.Message}&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!isCmdEnv) WaitForKey();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch (Exception ex)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.Error.WriteLine($&#34;Error: {ex.Message}&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!isCmdEnv) WaitForKey();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 显示命令行帮助信息。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static void ShowHelp()<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;FileList - List files in a directory tree.&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;Usage:&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;&nbsp;&nbsp;FileList.exe [folderPath] [includeExts] [excludeExts] [showContent]&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;Parameters:&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;&nbsp;&nbsp;folderPath&nbsp;&nbsp; : Target directory. Default: current directory.&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;&nbsp;&nbsp;includeExts&nbsp;&nbsp;: Use &#39;|&#39; separated extensions (e.g. .cs|.php).&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If provided, only these extensions are listed. (ignore excludeExts)&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;&nbsp;&nbsp;excludeExts&nbsp;&nbsp;: Extensions to exclude (e.g. .tmp|.log).&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;&nbsp;&nbsp;showContent&nbsp;&nbsp;: &#39;true&#39; to output file paths and content, &#39;false&#39; for tree view.&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;Notes:&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;&nbsp;&nbsp;- In CMD, escape &#39;|&#39; with ^ o&#114; use quotes: \&#34;.cs|.php\&#34;&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;&nbsp;&nbsp;- Extensions are case-insensitive and may be specified with o&#114; without leading dot.&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 标准化扩展名数组：去除空白，保证每个扩展名以点开头。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static string[] NormalizeExtensions(string[] exts)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i = 0; i &lt; exts.Length; i++)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exts[i] = exts[i].Trim();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!exts[i].StartsWith(&#34;.&#34;))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exts[i] = &#34;.&#34; + exts[i];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return exts;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 通过 WMI 查询父进程，判断是否由 cmd 或 powershell 启动。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 如果判断失败则默认按独立运行处理（返回 false）。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static bool IsRunningFromCmd()<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;using (var current = Process.GetCurrentProcess())<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string query = $&#34;Sel&#101;ct ParentProcessId FROM Win32_Process Wh&#101;re ProcessId = {current.Id}&#34;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;using (var searcher = new ManagementObjectSearcher(query))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach (var obj in searcher.Get())<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int parentId = Convert.ToInt32(obj[&#34;ParentProcessId&#34;]);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var parent = Process.GetProcessById(parentId);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string name = parent.ProcessName.ToLower();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return name == &#34;cmd&#34; || name == &#34;powershell&#34;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 无法查询时按独立运行处理<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 独立运行时等待用户按键，防止窗口立即关闭。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static void WaitForKey()<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;Press any key to exit...&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.ReadKey();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 生成树形结构的文件列表（不含文件内容）。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static void GenerateTreeList(string rootPath, string outputFile, string[] includeExts, string[] excludeExts)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 构建根节点<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var root = new TreeNode<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Name = rootPath,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IsDirectory = true,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FullPath = rootPath<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 递归构建树，并过滤掉无匹配文件的空目录<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BuildTree(root, includeExts, excludeExts);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var sb = new StringBuilder();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RenderTree(root, &#34;&#34;, true, sb); // 渲染成字符串<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File.WriteAllText(outputFile, sb.ToString(), Encoding.UTF8);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 生成含文件内容的列表（扁平，无目录树）。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static void GenerateContentList(string rootPath, string outputFile, string[] includeExts, string[] excludeExts)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 获取所有符合过滤条件的文件，并按完整路径排序（不区分大小写）<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var files = GetFilteredFiles(rootPath, includeExts, excludeExts);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;files.Sort(StringComparer.OrdinalIgnoreCase);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;using (var writer = new StreamWriter(outputFile, false, Encoding.UTF8))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach (var filePath in files)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writer.WriteLine(filePath + &#34;:&#34;);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var fileInfo = new FileInfo(filePath);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const long maxSize = 1 * 1024 * 1024; // 1 MB<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 文件过大则跳过内容<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (fileInfo.Length &gt; maxSize)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writer.WriteLine(&#34;[File size exceeds 1MB, content not displayed]&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 非文本文件（根据扩展名）跳过内容<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (!IsTextFile(filePath))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writer.WriteLine(&#34;[Non-text file, content not displayed]&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 读取文件全部文本（UTF-8）<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string content = File.ReadAllText(filePath, Encoding.UTF8);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writer.WriteLine(content);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch (UnauthorizedAccessException)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw; // 权限错误直接抛出，终止程序<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch (IOException)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writer.WriteLine(&#34;------------------------------------------------------------&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 判断指定文件是否属于文本文件（基于扩展名）。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static bool IsTextFile(string filePath)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string ext = Path.GetExtension(filePath);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return TextExtensions.Contains(ext);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 递归构建树节点，并根据过滤条件判断是否保留该节点。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 返回 true 表示该节点（目录）下至少有一个匹配文件，应保留。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static bool BuildTree(TreeNode node, string[] includeExts, string[] excludeExts)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 如果是文件，直接判断是否符合过滤条件<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!node.IsDirectory)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return IsFileIncluded(node.FullPath, includeExts, excludeExts);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var dirInfo = new DirectoryInfo(node.FullPath);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileSystemInfo[] items;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;items = dirInfo.GetFileSystemInfos(); // 包含隐藏文件和系统文件<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch (UnauthorizedAccessException)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw; // 无权访问时直接抛出，由上层终止程序<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var children = new List&lt;TreeNode&gt;();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach (var item in items)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var child = new TreeNode<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Name = item.Name,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FullPath = item.FullName,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IsDirectory = (item.Attributes &amp; FileAttributes.Directory) == FileAttributes.Directory<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 递归检查子项，只有包含匹配文件的子项才加入列表<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bool hasFiles = BuildTree(child, includeExts, excludeExts);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (hasFiles)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;children.Add(child);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 同级条目（文件+目录）按字母升序，不区分大小写<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;children.Sort((a, b) =&gt; string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase));<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;node.Children = children;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 该目录是否保留：只要至少有一个子节点（文件或包含文件的子目录）<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return children.Count &gt; 0;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 判断单个文件是否符合包含/排除扩展名规则。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 如果指定了包含列表，则文件扩展名必须在列表中；<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 否则，如果指定了排除列表，文件扩展名不能在其中；<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 都未指定则匹配所有文件。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static bool IsFileIncluded(string filePath, string[] includeExts, string[] excludeExts)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string ext = Path.GetExtension(filePath);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (includeExts != null &amp;&amp; includeExts.Length &gt; 0)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return includeExts.Any(e =&gt; string.Equals(e, ext, StringComparison.OrdinalIgnoreCase));<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (excludeExts != null &amp;&amp; excludeExts.Length &gt; 0)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return !excludeExts.Any(e =&gt; string.Equals(e, ext, StringComparison.OrdinalIgnoreCase));<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 递归获取指定目录下所有符合过滤条件的文件完整路径（扁平列表）。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static List&lt;string&gt; GetFilteredFiles(string rootPath, string[] includeExts, string[] excludeExts)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var result = new List&lt;string&gt;();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var dirInfo = new DirectoryInfo(rootPath);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileSystemInfo[] items;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;items = dirInfo.GetFileSystemInfos();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch (UnauthorizedAccessException)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach (var item in items)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ((item.Attributes &amp; FileAttributes.Directory) == FileAttributes.Directory)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 递归添加子目录中的文件<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result.AddRange(GetFilteredFiles(item.FullName, includeExts, excludeExts));<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch (UnauthorizedAccessException)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (IsFileIncluded(item.FullName, includeExts, excludeExts))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result.Add(item.FullName);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return result;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 递归渲染树形结构到 StringBuilder。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;node&#34;&gt;当前节点&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;indent&#34;&gt;当前行的缩进前缀&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;isLast&#34;&gt;当前节点是否为同级最后一个（决定使用 └── 还是 ├──）&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;sb&#34;&gt;输出缓冲&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static void RenderTree(TreeNode node, string indent, bool isLast, StringBuilder sb)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 根节点特殊处理：直接输出完整路径，不加树形符号<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (node.IsDirectory &amp;&amp; node.Name == node.FullPath)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sb.AppendLine(node.Name);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sb.Append(indent);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sb.Append(isLast ? &#34;└──&#34; : &#34;├──&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sb.AppendLine(node.Name);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 处理子节点<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (node.IsDirectory &amp;&amp; node.Children != null)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i = 0; i &lt; node.Children.Count; i++)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bool lastChild = (i == node.Children.Count - 1);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 根节点的直接子节点缩进为空（不产生多余空格）<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string childIndent;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (node.Name == node.FullPath)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;childIndent = &#34;&#34;; // 根下一级无额外缩进<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;childIndent = indent + (isLast ? &#34;&nbsp;&nbsp;&nbsp;&nbsp;&#34; : &#34;│&nbsp;&nbsp; &#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RenderTree(node.Children[i], childIndent, lastChild, sb);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// 树节点，表示文件或目录。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class TreeNode<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public string Name;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 文件/目录名<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public string FullPath;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 完整路径<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public bool IsDirectory;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 是否为目录<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public List&lt;TreeNode&gt; Children; // 子节点列表（仅目录有效）<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>}</div></div><br/>运行效果：<br/><br/><div class="UBBPanel quotePanel"><div class="UBBTitle"><img src="http://www.mzwu.com/images/quote.gif" style="margin:0px 2px -3px 0px" alt="引用内容"/> 引用内容</div><div class="UBBContent">E:\Web<br/>├──AIAPP.md<br/>├──index.html<br/>├──package-lock.json<br/>├──package.json<br/>├──postcss.config.js<br/>├──src<br/>│&nbsp;&nbsp; ├──app.tsx<br/>│&nbsp;&nbsp; ├──components<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──ImagePreview.tsx<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; └──Layout.tsx<br/>│&nbsp;&nbsp; ├──context<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; └──AuthContext.tsx<br/>│&nbsp;&nbsp; ├──index.css<br/>│&nbsp;&nbsp; ├──index.tsx<br/>│&nbsp;&nbsp; ├──lib<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──captcha.ts<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──image-compressor.ts<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──supabase.ts<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; └──utils.ts<br/>│&nbsp;&nbsp; ├──pages<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──AdminListPage.tsx<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──CustomerListPage tbody.txt<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──CustomerListPage.tsx<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──CustomerListPage.tsx.bak<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──DashboardPage.tsx<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──InitPage.tsx<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──ItemListPage.tsx<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──LoginPage.tsx<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; └──PublicCustomerRepairsPage.tsx<br/>│&nbsp;&nbsp; └──types<br/>│&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; └──database.ts<br/>├──supabase<br/>│&nbsp;&nbsp; ├──migration<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──001_cr&#101;ate_customer_share_tokens.sql<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──002_truncate_tables.sql<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──003_fix_latitude_longitude_type.sql<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──004_add_admin_login_security.sql<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──005_add_administrator_to_repair_items.sql<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──006_change_images_to_single_url.sql<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──007_up&#100;ate_admin_roles_to_three_levels.sql<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; ├──add_admin_login_fields.sql<br/>│&nbsp;&nbsp; │&nbsp;&nbsp; └──fix_last_login_ip_length.sql<br/>│&nbsp;&nbsp; └──tables<br/>│&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; └──schema.sql<br/>├──tailwind.config.js<br/>├──tsconfig.json<br/>├──tsconfig.node.json<br/>└──vite.config.ts</div></div><br/><strong>相关链接</strong><br/><br/>[1].FileList开发文档：<a target="_blank" href="http://www.mzwu.com//pic/202605/FileList.pdf" rel="external">https://www.mzwu.com/doc/FileList.pdf</a>]]></description>
		</item>
		
			<item>
			<link>http://www.mzwu.com/article.asp?id=5227</link>
			<title><![CDATA[黄金价格急涨急跌判断函数（C#版）]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Wed,13 May 2026 23:18:34 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=5227</guid>
		<description><![CDATA[<img src="http://www.mzwu.com/pic/202605/010.jpg" border="0" alt=""/><br/><br/>准备写一个黄金价格急涨急跌判断函数，短时间内黄金价格上涨或下跌幅度达到指定值即认为发生了急涨或急跌，但这中间要考虑到小波动（如上图示），和豆包来回沟通了几次，第一版代码如下：<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code46230);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code46230>/// &lt;summary&gt;<br/>/// 判断金价是否出现急涨<br/>/// &lt;/summary&gt;<br/>/// &lt;param name=&#34;prices&#34;&gt;金价数组，按时间从旧到新排列（索引0最早，索引Length-1最新）&lt;/param&gt;<br/>/// &lt;param name=&#34;sharpRiseThreshold&#34;&gt;急涨阈值：最新价与前面某价格的差值≥此值则视为急涨&lt;/param&gt;<br/>/// &lt;param name=&#34;maxPullbackTolerance&#34;&gt;反向下跌容忍阈值：连续下跌区间的头尾最大差值&lt;/param&gt;<br/>/// &lt;returns&gt;是否急涨&lt;/returns&gt;<br/>public static bool IsGoldPriceSharpRise(decimal[] prices, decimal sharpRiseThreshold, decimal maxPullbackTolerance)<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;if (prices == null || prices.Length &lt; 2)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;decimal latestPrice = prices[prices.Length - 1];<br/>&nbsp;&nbsp;&nbsp;&nbsp;int i = prices.Length - 2;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;while (i &gt;= 0)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 1. 先检查当前价格是否已经满足急涨条件<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal riseAmount = latestPrice - prices[i];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (riseAmount &gt;= sharpRiseThreshold)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 2. 检测是否进入连续下跌区间<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (prices[i] &gt; prices[i + 1])<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 记录下跌区间的右端点（最晚时间，区间最低点位置）<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int pullbackEndIndex = i + 1;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 继续往左找，直到下跌趋势结束<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i--;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (i &gt;= 0 &amp;&amp; prices[i] &gt;= prices[i + 1])<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i--;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 此时i+1是下跌区间的左端点（最早时间，区间最高点位置）<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int pullbackStartIndex = i + 1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal pullbackHigh = prices[pullbackStartIndex];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal pullbackLow = prices[pullbackEndIndex];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal totalPullback = pullbackHigh - pullbackLow;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 3. 检查整个下跌区间的总跌幅是否超过容忍度<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (totalPullback &gt; maxPullbackTolerance)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 下跌区间处理完毕，继续往前遍历<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 没有下跌，继续往前推<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i--;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;// 遍历完所有价格都未达到急涨条件<br/>&nbsp;&nbsp;&nbsp;&nbsp;return false;<br/>}<br/><br/>/// &lt;summary&gt;<br/>/// 判断金价是否出现急跌<br/>/// &lt;/summary&gt;<br/>/// &lt;param name=&#34;prices&#34;&gt;金价数组，按时间从旧到新排列（索引0最早，索引Length-1最新）&lt;/param&gt;<br/>/// &lt;param name=&#34;sharpDro&#112;Threshold&#34;&gt;急跌阈值：前面某价格与最新价的差值≥此值则视为急跌&lt;/param&gt;<br/>/// &lt;param name=&#34;maxReboundTolerance&#34;&gt;反向上涨容忍阈值：连续上涨区间的头尾最大差值&lt;/param&gt;<br/>/// &lt;returns&gt;是否急跌&lt;/returns&gt;<br/>public static bool IsGoldPriceSharpDro&#112;(decimal[] prices, decimal sharpDro&#112;Threshold, decimal maxReboundTolerance)<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;if (prices == null || prices.Length &lt; 2)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;decimal latestPrice = prices[prices.Length - 1];<br/>&nbsp;&nbsp;&nbsp;&nbsp;int i = prices.Length - 2;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;while (i &gt;= 0)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 1. 先检查当前价格是否已经满足急跌条件<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal dro&#112;Amount = prices[i] - latestPrice;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (dro&#112;Amount &gt;= sharpDro&#112;Threshold)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 2. 检测是否进入连续上涨区间（急跌时的反向趋势）<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (prices[i] &lt; prices[i + 1])<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 记录上涨区间的右端点（最晚时间，区间最高点位置）<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int reboundEndIndex = i + 1;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 继续往左找，直到上涨趋势结束<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i--;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (i &gt;= 0 &amp;&amp; prices[i] &lt;= prices[i + 1])<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i--;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 此时i+1是上涨区间的左端点（最早时间，区间最低点位置）<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int reboundStartIndex = i + 1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal reboundLow = prices[reboundStartIndex];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal reboundHigh = prices[reboundEndIndex];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal totalRebound = reboundHigh - reboundLow;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 3. 检查整个上涨区间的总涨幅是否超过容忍度<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (totalRebound &gt; maxReboundTolerance)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 上涨区间处理完毕，继续往前遍历<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 没有上涨，继续往前推<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i--;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;// 遍历完所有价格都未达到急跌条件<br/>&nbsp;&nbsp;&nbsp;&nbsp;return false;<br/>}</div></div><br/><img src="http://www.mzwu.com/pic/202605/011.jpg" border="0" alt=""/><br/><br/>不久我又想到新的情况，比如判断急涨时（如上图），每一次反向时都没有超过容忍阈值，但可能发生多次反向，最终加起来可能远远超过容忍阈值了，便又有了新的想法，记录下每次反向的高值和低值，最后再看一下最高值和最低值的差值是不是超过容忍阈值，我和豆包说了想法，豆包提出了瑕疵，比如下图这种情形：<br/><br/><img src="http://www.mzwu.com/pic/202605/012.jpg" border="0" alt=""/><br/><br/>最低值在最高值前面，从最低到最高其实是上涨的，我用它们的差值做判断显然不合适，于是又改进了下，得到最高值后，再从其右边找最低值（它不一定是所有低值中的最低值），解决了目前能想到问题，最终版本如下：<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code24203);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code24203>using System;<br/>using System.Collections.Generic;<br/><br/>public class GoldPriceAnalyzer<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;#region 内部实体<br/>&nbsp;&nbsp;&nbsp;&nbsp;private class PullbackInterval<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public decimal High { get; set; }<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public decimal Low { get; set; }<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public int HighIndex { get; set; }<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;private class ReboundInterval<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public decimal Low { get; set; }<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public decimal High { get; set; }<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public int LowIndex { get; set; }<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;#endregion<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;#region IsGoldPriceSharpRise 方法组<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// 判断金价是否急涨（数组版）<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;prices&#34;&gt;金价数组，按时间从旧到新排列&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;sharpRiseThreshold&#34;&gt;急涨阈值&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;maxPullbackTolerance&#34;&gt;反向下跌容忍阈值&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;returns&gt;是否急涨&lt;/returns&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;public static bool IsGoldPriceSharpRise(decimal[] prices, decimal sharpRiseThreshold, decimal maxPullbackTolerance)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (prices == null)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new ArgumentNullException(&#34;prices&#34;, &#34;金价数组不能为null&#34;);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (prices.Length &lt; 2)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal latestPrice = prices[prices.Length - 1];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int i = prices.Length - 2;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;PullbackInterval&gt; pullbacks = new List&lt;PullbackInterval&gt;();<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (i &gt;= 0)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal riseAmount = latestPrice - prices[i];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (riseAmount &gt;= sharpRiseThreshold)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return FinalValidateSharpRise(pullbacks, maxPullbackTolerance);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (prices[i] &gt; prices[i + 1])<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int pullbackEndIndex = i + 1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i--;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (i &gt;= 0 &amp;&amp; prices[i] &gt;= prices[i + 1])<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i--;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int pullbackStartIndex = i + 1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal pullbackHigh = prices[pullbackStartIndex];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal pullbackLow = prices[pullbackEndIndex];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal totalPullback = pullbackHigh - pullbackLow;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (totalPullback &gt;= maxPullbackTolerance)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pullbacks.Add(new PullbackInterval<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;High = pullbackHigh,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Low = pullbackLow,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HighIndex = pullbackStartIndex<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i--;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// 判断金价是否急涨（List版重载）<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;prices&#34;&gt;金价数组，按时间从旧到新排列&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;sharpRiseThreshold&#34;&gt;急涨阈值&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;maxPullbackTolerance&#34;&gt;反向下跌容忍阈值&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;returns&gt;&lt;/returns&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;public static bool IsGoldPriceSharpRise(List&lt;decimal&gt; prices, decimal sharpRiseThreshold, decimal maxPullbackTolerance)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (prices == null)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new ArgumentNullException(&#34;prices&#34;, &#34;金价列表不能为null&#34;);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return IsGoldPriceSharpRise(prices.ToArray(), sharpRiseThreshold, maxPullbackTolerance);<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;#endregion<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;#region IsGoldPriceSharpDro&#112; 方法组<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// 判断金价是否急跌（数组版）<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;prices&#34;&gt;金价数组，按时间从旧到新排列&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;sharpDro&#112;Threshold&#34;&gt;急跌阈值&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;maxReboundTolerance&#34;&gt;反向上涨容忍阈值&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;returns&gt;是否急跌&lt;/returns&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;public static bool IsGoldPriceSharpDro&#112;(decimal[] prices, decimal sharpDro&#112;Threshold, decimal maxReboundTolerance)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (prices == null)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new ArgumentNullException(&#34;prices&#34;, &#34;金价数组不能为null&#34;);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (prices.Length &lt; 2)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal latestPrice = prices[prices.Length - 1];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int i = prices.Length - 2;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;ReboundInterval&gt; rebounds = new List&lt;ReboundInterval&gt;();<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (i &gt;= 0)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal dro&#112;Amount = prices[i] - latestPrice;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (dro&#112;Amount &gt;= sharpDro&#112;Threshold)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return FinalValidateSharpDro&#112;(rebounds, maxReboundTolerance);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (prices[i] &lt; prices[i + 1])<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int reboundEndIndex = i + 1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i--;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (i &gt;= 0 &amp;&amp; prices[i] &lt;= prices[i + 1])<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i--;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int reboundStartIndex = i + 1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal reboundLow = prices[reboundStartIndex];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal reboundHigh = prices[reboundEndIndex];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal totalRebound = reboundHigh - reboundLow;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (totalRebound &gt;= maxReboundTolerance)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rebounds.Add(new ReboundInterval<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Low = reboundLow,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;High = reboundHigh,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LowIndex = reboundStartIndex<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i--;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// 判断金价是否急跌（List版重载）<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;prices&#34;&gt;金价数组，按时间从旧到新排列&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;sharpDro&#112;Threshold&#34;&gt;急跌阈值&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;maxReboundTolerance&#34;&gt;反向上涨容忍阈值&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;returns&gt;&lt;/returns&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;public static bool IsGoldPriceSharpDro&#112;(List&lt;decimal&gt; prices, decimal sharpDro&#112;Threshold, decimal maxReboundTolerance)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (prices == null)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new ArgumentNullException(&#34;prices&#34;, &#34;金价列表不能为null&#34;);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return IsGoldPriceSharpDro&#112;(prices.ToArray(), sharpDro&#112;Threshold, maxReboundTolerance);<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;#endregion<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;#region 内部验证方法<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// 急涨最终验证逻辑<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;pullbacks&#34;&gt;&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;maxTolerance&#34;&gt;&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;returns&gt;&lt;/returns&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;private static bool FinalValidateSharpRise(List&lt;PullbackInterval&gt; pullbacks, decimal maxTolerance)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (pullbacks.Count == 0)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PullbackInterval maxHighInterval = pullbacks[0];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach (PullbackInterval interval in pullbacks)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (interval.High &gt; maxHighInterval.High)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxHighInterval = interval;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal minLowAfterMaxHigh = maxHighInterval.Low;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach (PullbackInterval interval in pullbacks)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (interval.HighIndex &gt; maxHighInterval.HighIndex)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (interval.Low &lt; minLowAfterMaxHigh)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;minLowAfterMaxHigh = interval.Low;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal totalMaxPullback = maxHighInterval.High - minLowAfterMaxHigh;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return totalMaxPullback &lt; maxTolerance;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// 急跌最终验证逻辑（与急涨完全对称）<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;rebounds&#34;&gt;&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;maxTolerance&#34;&gt;&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;returns&gt;&lt;/returns&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;private static bool FinalValidateSharpDro&#112;(List&lt;ReboundInterval&gt; rebounds, decimal maxTolerance)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (rebounds.Count == 0)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ReboundInterval minLowInterval = rebounds[0];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach (ReboundInterval interval in rebounds)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (interval.Low &lt; minLowInterval.Low)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;minLowInterval = interval;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal maxHighAfterMinLow = minLowInterval.High;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach (ReboundInterval interval in rebounds)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (interval.LowIndex &gt; minLowInterval.LowIndex)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (interval.High &gt; maxHighAfterMinLow)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxHighAfterMinLow = interval.High;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decimal totalMaxRebound = maxHighAfterMinLow - minLowInterval.Low;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return totalMaxRebound &lt; maxTolerance;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;#endregion<br/>}</div></div><br/><strong>后记</strong><br/><br/>AI编程可以大大提高效率，但建议人工审核下，AI也会出错：<br/><br/><img width="640" height="174" src="http://www.mzwu.com/pic/202605/013.jpg" border="0" alt=""/><br/><br/><img width="640" height="218" src="http://www.mzwu.com/pic/202605/014.jpg" border="0" alt=""/><br/><br/>或者让AI审核AI，我把代码发给了DeepSeek：<br/><br/><img width="640" height="508" src="http://www.mzwu.com/pic/202605/015.jpg" border="0" alt=""/>]]></description>
		</item>
		
			<item>
			<link>http://www.mzwu.com/article.asp?id=5226</link>
			<title><![CDATA[别再乱加 try-catch 了！7 个异常处理策略，让你的程序再也不崩溃]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Tue,12 May 2026 20:46:46 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=5226</guid>
		<description><![CDATA[<img width="640" height="368" src="http://www.mzwu.com/pic/202605/008.jpg" border="0" alt=""/><br/><br/>写代码最头疼的事之一，就是处理各种莫名其妙的错误。很多人要么图省事，整个程序套一个大 try-catch，一出错全崩；要么走另一个极端，每一行代码都加一个 try-catch，结果一个地方错了，后面跟着报一堆连锁错误，越修越乱。今天我们从一个简单的例子开始，由浅入深讲透 7 个工业界最实用的异常处理策略。学会这些，你写的程序会比别人的健壮 10 倍。<br/>假设你写了一个简单的计算程序，用户输入四个数字 a、b、c、d，程序做三件事：<br/><br/><div class="UBBPanel quotePanel"><div class="UBBTitle"><img src="http://www.mzwu.com/images/quote.gif" style="margin:0px 2px -3px 0px" alt="引用内容"/> 引用内容</div><div class="UBBContent">a + b = e<br/>e + 2 = f<br/>c + d = g</div></div><br/>一开始你可能这么写：<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code46368);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code46368>// 坑1：全局大try-catch<br/>try<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;int e = a + b;<br/>&nbsp;&nbsp;&nbsp;&nbsp;int f = e + 2;<br/>&nbsp;&nbsp;&nbsp;&nbsp;int g = c + d;<br/>}<br/>catch<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;计算出错了！&#34;);<br/>}</div></div><br/>结果发现，只要 a+b 输错了（比如输了个字母），整个程序直接退出，连本来能正常算的 c+d 也跑不了。然后你又改成这样：<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code27805);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code27805>// 坑2：每行一个try-catch<br/>int e, f, g;<br/><br/>try<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;e = a + b;<br/>}<br/>catch<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;a+b 出错了！&#34;);<br/>}<br/><br/>try<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;f = e + 2; // e 没赋值成功，这里继续报错<br/>}<br/>catch<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;e+2 出错了！&#34;);<br/>}<br/><br/>try<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;g = c + d;<br/>}<br/>catch<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;c+d 出错了！&#34;);<br/>}</div></div><br/>更糟了！a+b 出错后，e 不存在，e+2 那行必然又报一个错，一个错误变成两个，日志里全是没用的垃圾信息。这时候你想到了一个绝妙的办法：把有依赖关系的步骤放一起，没依赖的分开：<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code10051);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code10051>// 正确的做法<br/>int e, f, g;<br/><br/>// 第一组：有依赖关系的步骤放一起<br/>try<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;e = a + b;<br/>&nbsp;&nbsp;&nbsp;&nbsp;f = e + 2;<br/>}<br/>catch<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;f 值计算出错！&#34;);<br/>}<br/><br/>// 第二组：独立无依赖，单独捕获<br/>try<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;g = c + d;<br/>}<br/>catch<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;g 值计算出错！&#34;);<br/>}</div></div><br/>完美！a+b 出错只会影响 f 的计算，g 照样能正常出来。这就是我们今天要讲的第一个，也是最基础最重要的异常处理策略。<br/><br/><strong>策略 1：依赖任务组隔离式 —— 把错误关在小房间里</strong><br/><br/>这是所有异常处理的基石，核心思想就一句话：谁和谁有关系，就把他们关在同一个房间里；没关系的，就分开关。<br/><span style="color:Brown">关键设计要点</span><br/>● 有依赖关系的步骤（a+b 和 e+2，后者必须等前者算完），必须放在同一个 try-catch 里。一个错了，整个房间的门就关上，后面的步骤不再执行。<br/>● 没有任何关系的步骤（算 f 和算 g），必须放在不同的 try-catch 里。一个房间着火了，不会烧到另一个房间。<br/>我们把这样一个 &#34;房间&#34; 叫做一个任务组。每个任务组是一个最小的错误隔离单元，组内错误终止本组，组间错误互不影响。<br/>✅适用场景：所有程序，不管大小，第一步都应该先做这个。这是从 &#34;写能跑的代码&#34; 到 &#34;写健壮的代码&#34; 的第一道门槛。<br/><br/><strong>策略 2：重试模式 —— 给错误一次改过自新的机会</strong><br/><br/>依赖任务组隔离解决了 &#34;错误乱跑&#34; 的问题，但还有一个问题：很多错误其实是暂时的。<br/>比如你写了一个程序，需要从网上拉取数据然后计算。有时候网络抖了一下，请求失败了，其实等 1 秒钟再试一次就好了。如果直接标记任务失败，就太可惜了。<br/>这就是重试模式：对于那些 &#34;可能自己好&#34; 的错误，不要立刻放弃，自动重试几次。<br/><span style="color:Brown">关键设计要点</span><br/>● 只重试 &#34;瞬时错误&#34;：网络超时、连接失败、服务器临时 503 这些。参数错误、权限不足这种重试 100 次也没用的，绝对不要重试。<br/>● 重试次数不要太多：2-3 次足够了，多了会拖慢系统。<br/>● 重试间隔要递增：第一次等 1 秒，第二次等 2 秒，第三次等 4 秒，避免大家同时重试把服务器压垮。<br/>✅适用场景：所有涉及网络调用、数据库查询、文件读写的地方，都应该加上重试。生产环境里 80% 的错误都是这种瞬时故障。<br/><br/><strong>策略 3：降级模式 —— 丢车保帅，保证核心能用</strong><br/><br/>有些任务就算失败了，天也塌不下来。<br/>比如你做一个电商网站，商品详情页有 &#34;商品价格&#34; 和 &#34;猜你喜欢&#34; 两个部分。如果 &#34;猜你喜欢&#34; 的服务挂了，难道要让整个商品页都打不开吗？当然不行。<br/>这时候就用降级模式：非核心任务失败时，不返回错误，而是返回一个预设的默认值，保证核心功能正常运行。&#34;猜你喜欢&#34; 挂了，就显示 &#34;暂无推荐&#34;；统计计数失败了，就记个 0，不影响用户下单；头像加载失败了，就显示一个默认头像。<br/><span style="color:Brown">关键设计要点</span><br/>● 一定要分清楚核心和非核心。核心功能绝对不能降级，比如支付、下单。<br/>● 降级结果要安全，不能返回会导致后续逻辑崩溃的值。<br/>✅适用场景：所有非核心的辅助功能，都可以设计降级策略。用户可能根本没注意到某个小功能没了，但如果整个页面崩了，他一定会走。<br/><br/><strong>策略 4：舱壁模式 —— 别让一个慢任务拖垮整个系统</strong><br/><br/>前面三个策略都是隔离 &#34;错误&#34;，但还有一种更隐蔽的杀手：慢任务。<br/>比如你有一个程序，同时跑 10 个任务组。其中一个任务组陷入了死循环，或者调用了一个特别慢的接口，占满了所有 CPU 和线程。结果其他 9 个正常的任务组也得不到资源，跟着一起卡死。<br/>这就像轮船的水密隔舱，如果没有隔舱，一个地方漏水，整条船都会沉。舱壁模式就是给每个任务组分配独立的资源，一个任务组炸了，只会用光自己的资源，不会影响别人。<br/>这时候就用舱壁模式：别让一个慢任务拖垮整个系统。原来 10 个任务共用 100 个线程，现在给每个任务分 10 个线程。就算一个任务把自己的 10 个线程全占满了，还有 90 个线程给其他 9 个任务用。<br/>✅适用场景：多任务并发执行的系统，特别是包含不可信第三方调用的系统。<br/><br/><strong>策略 5：熔断器模式 —— 及时止损，防止雪崩</strong><br/><br/>想象一下，你调用的一个第三方服务彻底挂了。这时候如果还有源源不断的请求过来，每个请求都要等 30 秒才超时，很快你的服务器的所有线程都会被这些等待的请求占满，导致你的整个服务也挂了。这就是雪崩效应：一个服务的故障，层层传导，最终导致整个系统崩溃。<br/>熔断器模式就是解决这个问题的，它就像家里的保险丝：<br/>● 正常情况：保险丝闭合，电流正常通过<br/>● 故障情况：当失败次数超过阈值，保险丝断开，直接切断电流<br/>● 恢复情况：过一段时间，保险丝尝试半开，放少量电流过去试试，如果好了就重新闭合<br/>放到程序里就是：当某个任务组的失败率超过 50%，就暂时停止执行这个任务组，直接返回降级结果。等过几分钟，再尝试几次，如果服务恢复了，就继续正常执行。<br/>✅适用场景：高并发系统中，所有依赖外部服务的地方。这是防止系统雪崩的最后一道防线。<br/><br/><strong>策略 6：补偿事务模式 —— 做错了，就想办法改回来</strong><br/><br/>前面的策略都是 &#34;出错了怎么办&#34;，但还有一种更复杂的情况：一个业务流程需要多个步骤依次完成，前几个成功了，后面的失败了。<br/>比如下单流程：扣减库存 → 创建订单 → 扣减余额。如果扣减库存和创建订单都成功了，扣减余额失败了怎么办？总不能让用户没付钱就拿到货吧。<br/>这时候就需要补偿事务模式：把每个步骤都配上一个 &#34;撤销操作&#34;。如果后面的步骤失败了，就依次执行前面步骤的撤销操作，把系统恢复到原来的状态。<br/>● 扣减库存的撤销操作：增加库存<br/>● 创建订单的撤销操作：取消订单<br/>✅适用场景：跨多个服务、多个数据库的业务流程，比如订单、支付、转账。<br/><br/><strong>策略 7：冗余容错模式 —— 鸡蛋不要放在一个篮子里</strong><br/><br/>最后这个策略，已经超出了单台机器代码的范畴，是系统级别的容错。<br/>前面所有的策略，都解决不了一个问题：服务器宕机了。不管你代码写得多好，机器突然断电了，程序还是跑不了。<br/>这时候就需要冗余容错模式：多准备几台机器，同时跑一样的程序。一台挂了，其他的还能继续工作。<br/>● 主备模式：一台主机器干活，一台备机器待命，主的挂了备的顶上<br/>● 集群模式：多台机器一起干活，通过负载均衡分发请求<br/>● 多活模式：多个城市的数据中心同时提供服务，一个城市地震了，其他城市还能用<br/>✅适用场景：对可用性要求极高的系统，比如银行、电商、微信、支付宝。<br/><br/><strong>总结</strong><br/><br/>没有最好的策略，只有最合适的。根据不同的场景，从简单到复杂叠加就好：<br/><br/><img src="http://www.mzwu.com/pic/202605/009.jpg" border="0" alt=""/><br/><br/>很多新手觉得异常处理是 &#34;边角料&#34;，是写完核心逻辑后随便加的东西。但实际上，一个程序 90% 的代码，都是在处理各种异常情况。<br/>真正的好代码，不是永远不出错的代码，而是出错了能精准控制影响范围、能自己恢复、能快速定位问题的代码。<br/>从今天开始，扔掉你的全局大 try-catch，也不要再每行代码都加 try-catch。先从划分依赖任务组开始，一步一步把这些策略用起来，你会发现你的程序会变得越来越稳。<br/><br/><strong>相关链接</strong><br/><br/>[1].与豆包互动原文：<a target="_blank" href="http://www.mzwu.com//pic/202605/try-catch.pdf" rel="external">https://www.mzwu.com/doc/try-catch.pdf</a>]]></description>
		</item>
		
			<item>
			<link>http://www.mzwu.com/article.asp?id=5209</link>
			<title><![CDATA[豆包和千问等大模型客户端删除聊天记录对上下文影响测试]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Fri,10 Apr 2026 01:07:53 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=5209</guid>
		<description><![CDATA[今天忽然萌生一个疑问：在豆包、千问等大模型客户端的对话中，删除部分聊天记录后，这些内容是否仍会被纳入上下文？于是当即动手，对多款 APP 进行了实测。<br/><div class="UBBPanel quotePanel"><div class="UBBTitle"><img src="http://www.mzwu.com/images/quote.gif" style="margin:0px 2px -3px 0px" alt="引用内容"/> 引用内容</div><div class="UBBContent"><i>【测试步骤】：先问1+1等于多少？再问2+2等于多少？然后查看当前对话上下文，接着删除2+2等于多少的聊天记录，再次查看当前对话上下文。</i></div></div><br/><strong>一、豆包APP</strong><br/><br/><img width="640" height="710" src="http://www.mzwu.com/pic/202604/015.jpg" border="0" alt=""/><br/><br/><i>Tips：豆包官方助手和智能体有个开启新话题功能，它不会删除当前对话聊天记录，但上下文会被清空，这和创建新对话不同。</i><br/><br/><strong>二、千问APP</strong><br/><br/><img width="640" height="710" src="http://www.mzwu.com/pic/202604/017.jpg" border="0" alt=""/><br/><br/><strong>结论</strong>：DeepSeek、Kimi、智谱清言和讯飞星火不支持删除聊天记录，豆包和千问删除部分聊天记录时，这些记录在上下文中也会同步删除。]]></description>
		</item>
		
			<item>
			<link>http://www.mzwu.com/article.asp?id=5205</link>
			<title><![CDATA[SQLite 时区坑：datetime (&#39;now&#39;) UTC 时差引发的数据查询 BUG 修复]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Fri,03 Apr 2026 21:26:37 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=5205</guid>
		<description><![CDATA[豆包帮忙写了一段C#代码，功能是查询SQLite最近两小时的数据，代码如下：<br/><br/><img src="http://www.mzwu.com/pic/202604/004.jpg" border="0" alt=""/><br/><br/>当前21点，却搜出了上午11点的数据，10个小时，将SQL语句复制到数据库中执行：<br/><br/><img src="http://www.mzwu.com/pic/202604/005.jpg" border="0" alt=""/><br/><br/>也是一样的，那么问题可能在datetime(&#39;now&#39;)上了，单独执行看下：<br/><br/><img src="http://www.mzwu.com/pic/202604/006.jpg" border="0" alt=""/><br/><br/>果然，datetime(&#39;now&#39;)是UTC时间，跟北京时间差了八个小时，改下SQL语句，问题解决：<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code36754);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code36754><i>Sel&#101;ct id, price, cr&#101;ate_time <br/>&nbsp;&nbsp;&nbsp;&nbsp;FROM tablename<br/>&nbsp;&nbsp;&nbsp;&nbsp;Wh&#101;re cr&#101;ate_time &gt;= datetime(&#39;now&#39;, <span style="color:red">&#39;localtime&#39;,</span> &#39;-2 hours&#39;) <br/>&nbsp;&nbsp;&nbsp;&nbsp;o&#114;DER BY cr&#101;ate_time ASC</i></div></div>]]></description>
		</item>
		
			<item>
			<link>http://www.mzwu.com/article.asp?id=5023</link>
			<title><![CDATA[C#声明List和Dictionary直接初始化示例]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Fri,09 Dec 2022 10:36:03 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=5023</guid>
		<description><![CDATA[<img src="http://www.mzwu.com/pic/202212/006.jpg" border="0" alt=""/><br/><br/><strong>1、List直接初始化示例</strong><br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code30839);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code30839>List&lt;string&gt; lst = new List&lt;string&gt;() { &#34;www&#34;, &#34;mzwu&#34;, &#34;com&#34; };<br/>Console.WriteLine(lst[0]);</div></div><br/><strong>2、Dictionary直接初始化示例</strong><br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code97727);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code97727>Dictionary&lt;string, string&gt; dit = new Dictionary&lt;string, string&gt;() { { &#34;name&#34;, &#34;Jack&#34; }, { &#34;age&#34;, &#34;30&#34; } };<br/>Console.WriteLine(dit[&#34;name&#34;]);</div></div>]]></description>
		</item>
		
			<item>
			<link>http://www.mzwu.com/article.asp?id=4758</link>
			<title><![CDATA[锟斤拷等常见文本乱码产生原因对照表]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Sun,07 Feb 2021 10:53:44 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=4758</guid>
		<description><![CDATA[<img width="630" height="555" src="http://www.mzwu.com/pic/202102/002.jpg" border="0" alt=""/>]]></description>
		</item>
		
			<item>
			<link>http://www.mzwu.com/article.asp?id=4729</link>
			<title><![CDATA[C#将图片音频等文件转成Base64字符串示例]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Sat,31 Oct 2020 12:24:12 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=4729</guid>
		<description><![CDATA[<div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code97063);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code97063>class Program<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;static void Main(string[] args)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.Write(&#34;文件地址：&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string file = Console.ReadLine();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;转换结果：{0}&#34;, FileToBase64String(file));<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.ReadLine();<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;static string FileToBase64String(string file)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string result = string.Empty;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;using (FileStream stream = new FileStream(file, FileMode.Open))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] bt = new byte[stream.Length];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stream.Read(bt, 0, bt.Length);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = Convert.ToBase64String(bt);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch { }<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return result;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>}</div></div><br/><strong>HTML5使用示例</strong><br/><br/>图片：<br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code72496);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code72496>&lt;img src=&#34;data:image/png;base64,转换的Base64字符串&#34;/&gt;</div></div><br/>音频：<br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code46197);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code46197>&lt;audio src=&#34;data:audio/wav;base64,转换的Base64字符串 /&gt;</div></div>]]></description>
		</item>
		
			<item>
			<link>http://www.mzwu.com/article.asp?id=4672</link>
			<title><![CDATA[C#大图片压缩算法]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Sat,13 Jun 2020 23:32:43 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=4672</guid>
		<description><![CDATA[<div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code73609);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code73609>using System.Drawing;<br/>using System.Drawing.Imaging;<br/>using System.IO;<br/><br/>public class ImageHelper<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// GetEncoderInfo<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;mimeType&#34;&gt;&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;returns&gt;&lt;/returns&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;private static ImageCodecInfo GetEncoderInfo(string mimeType)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i = 0; i &lt; encoders.Length; ++i)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (encoders[i].MimeType == mimeType)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return encoders[i];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return null;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// 图片压缩(降低质量以减小文件的大小)<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;srcBitmap&#34;&gt;传入的Bitmap对象&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;destStream&#34;&gt;压缩后的Stream对象&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;level&#34;&gt;压缩等级，0-100&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;private static void Compress(Bitmap srcBitmap, Stream destStream, long level)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ImageCodecInfo myImageCodecInfo;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Encoder myEncoder;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EncoderParameter myEncoderParameter;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EncoderParameters myEncoderParameters;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Get an ImageCodecInfo object that represents the JPEG codec.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myImageCodecInfo = GetEncoderInfo(&#34;image/jpeg&#34;);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Cr&#101;ate an Encoder object based on the GUID<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// for the Quality parameter category.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myEncoder = Encoder.Quality;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Cr&#101;ate an EncoderParameters object.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// An EncoderParameters object has an array of EncoderParameter<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// objects. In this case, there is only one<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// EncoderParameter object in the array.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myEncoderParameters = new EncoderParameters(1);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Save the bitmap as a JPEG file with 给定的 quality level<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myEncoderParameter = new EncoderParameter(myEncoder, level);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myEncoderParameters.Param[0] = myEncoderParameter;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;srcBitmap.Save(destStream, myImageCodecInfo, myEncoderParameters);<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// 图片压缩(降低质量以减小文件的大小)<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;srcFile&#34;&gt;&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;destFile&#34;&gt;&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;level&#34;&gt;&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;public static void Compress(string srcFile, string destFile, long level)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;using (Image image = Image.FromFile(srcFile))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;using (Bitmap bitmap = new Bitmap(image))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;using (FileStream destStream = new FileStream(destFile, FileMode.Cr&#101;ate))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compress(bitmap, destStream, level);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>}</div></div><br/>调用示例:<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code16593);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code16593>ImageHelper.Compress(@&#34;C:\mzwu_com.jpg&#34;, @&#34;C:\mzwu_net.jpg&#34;, 50L);</div></div>]]></description>
		</item>
		
			<item>
			<link>http://www.mzwu.com/article.asp?id=4617</link>
			<title><![CDATA[软件破解与防破解的那些事[转]]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Sat,18 Apr 2020 13:46:38 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=4617</guid>
		<description><![CDATA[首先我们要明确一点:<br/><br/><strong>理论上不存在无法破解的软件，但也并不是说破解软件比开发容易一万倍，<br/>防破解的目的不是要做一个无法破解的软件，而是让破解软件的成本远大于购买软件的成本！</strong><br/><br/>现在笔者简略表演几个有代表性的软件破解，当然，要看懂下面的内容，需要一点点C语言的编程基础。<br/><br/>我们先来一个最最简单的软件破解，假设我们写了一个软件，它的注册手段代码如下：<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code40756);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code40756>#include &#34;stdio.h&#34;<br/>#include &#34;string.h&#34;<br/>int main()<br/>{<br/>&#160;&#160;&#160;&#160;char Key[32];<br/>&#160;&#160;&#160;&#160;printf(&#34;请输入注册码:&#34;);<br/>&#160;&#160;&#160;&#160;gets(Key);<br/>&#160;&#160;&#160;&#160;if (strcmp(Key,&#34;abc123456&#34;)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册失败&#34;);<br/>}</div></div><br/>把他编译成exe，运行一下<br/><br/><img width="630" height="500" src="http://www.mzwu.com/pic/202004/126.gif" border="0" alt=""/><br/><br/>要破解怎么办呢?超简单的，你把这个程序后缀改成txt然后打开，搜索注册码。然后翻一翻key就找到了：<br/><br/><img width="630" height="500" src="http://www.mzwu.com/pic/202004/127.gif" border="0" alt=""/><br/><br/>别笑，就算是今天，仍然有一大堆软件采用这种软件保护机制，不过这类软件要不大多不怎么值钱比如xx管理系统，计算器之类的，要不就是软件作者别有用心防君子不防小人。你可能会问了，问题出在那了呢，这类保护机制的问题是，目前大部分的编译器都会将字符串常量直接存储在可执行文件结构中，所以你要是硬编码key，那么上面这种破解方法几乎是屡试不爽甚至不需要什么逆向破解知识就能搞定。<br/><br/>那么，让我们进入防破解V2.0时代，为了与时俱进，我们稍微把上面的代码改一下：<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code68268);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code68268>#include &#34;stdio.h&#34;<br/>#include &#34;string.h&#34;<br/>#include &#34;windows.h&#34;<br/>#include &#34;math.h&#34;<br/><br/>int main()<br/>{<br/>&#160;&#160;&#160;&#160;char iKey[32];<br/>&#160;&#160;&#160;&#160;char Key[32];<br/>&#160;&#160;&#160;&#160;char ID[32];<br/>&#160;&#160;&#160;&#160;int iID=0xabc1d3f;<br/>&#160;&#160;&#160;&#160;sprintf(Key,&#34;%x&#34;,iID*8+123456);<br/>&#160;&#160;&#160;&#160;printf(&#34;你的机器码是%x\n&#34;,iID);<br/>&#160;&#160;&#160;&#160;printf(&#34;请输入注册码:&#34;);<br/>&#160;&#160;&#160;&#160;gets(iKey);<br/>&#160;&#160;&#160;&#160;if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MessageBoxA(0,&#34;注册成功&#34;,&#34;&#34;,MB_OK);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MessageBoxA(0,&#34;注册失败&#34;,&#34;&#34;,MB_OK);<br/>}</div></div><br/><img src="http://www.mzwu.com/pic/202004/128.jpg" border="0" alt=""/><br/><br/>现在&#34;TXT&#34;破解法已经不顶用了，你看，key找不到了：<br/><br/><img src="http://www.mzwu.com/pic/202004/129.jpg" border="0" alt=""/><br/><br/>怎么样，这种保护手段是不是熟悉的味道熟悉的配方，这个机器码可以从网卡MAC，CPU型号，内存大小等等等等去生成，当然，key的算法也可以拉上MD5，SHA等等等等手段来弄而不是简简单单的乘一个8再加上123456，总之从机器码到注册码的算法你能玩出花。<br/><br/>但，这又有什么卵用呢，打开ollydbg，对MessageBoxA下断点(也就是弹窗的函数)：<br/><br/><img width="630" height="437" src="http://www.mzwu.com/pic/202004/130.jpg" border="0" alt=""/><br/><br/>然后输入一个错误的注册码，命中断点，很快，我们来到了判断注册码是否正确的逻辑处理代码：<br/><br/><img width="630" height="371" src="http://www.mzwu.com/pic/202004/131.jpg" border="0" alt=""/><br/><br/>你猜猜，要是我们把这个判断注册码是否正确的代码给它删了)(nop指令填充)会怎么样：<br/><br/><img width="630" height="342" src="http://www.mzwu.com/pic/202004/132.jpg" border="0" alt=""/><br/><br/>你会发现，握草，不管我输入什么，都是注册成功：<br/><br/><img src="http://www.mzwu.com/pic/202004/133.jpg" border="0" alt=""/><br/><br/>那么问题出在哪了呢，你发现，万恶之源都始于那个MessageBox函数，正是这个函数，让我们顺藤摸瓜找到了注册码判断代码，时至今日，仍然有非常非常大的一部分软件使用着这个二三十年前就在用的保护手段，每年死于MessageBox被破解的软件，围起来可以绕地球三圈。也就是这个保护机制，成就了所谓软件发布后十分钟就被破解的悲惨结局。<br/><br/><img src="http://www.mzwu.com/pic/202004/134.jpg" border="0" alt=""/><br/><br/>这个时候，你痛定思痛，mmp，有内鬼，既然MessageBox不好用，那我不用就是了，于是你把代码改成下面这样：<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code32615);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code32615>#include &#34;stdio.h&#34;<br/>#include &#34;string.h&#34;<br/>#include &#34;windows.h&#34;<br/>#include &#34;math.h&#34;<br/><br/>int main()<br/>{<br/>&#160;&#160;&#160;&#160;char iKey[32];<br/>&#160;&#160;&#160;&#160;char Key[32];<br/>&#160;&#160;&#160;&#160;char ID[32];<br/>&#160;&#160;&#160;&#160;int iID=0xabc1d3f;<br/>&#160;&#160;&#160;&#160;sprintf(Key,&#34;%x&#34;,iID*8+123456);<br/>&#160;&#160;&#160;&#160;printf(&#34;你的机器码是%x\n&#34;,iID);<br/>&#160;&#160;&#160;&#160;printf(&#34;请输入注册码:&#34;);<br/>&#160;&#160;&#160;&#160;gets(iKey);<br/>&#160;&#160;&#160;&#160;if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>}</div></div><br/>你看，啧。只要你注册码没输对，我直接把软件退出(或者跳到别的地方)，看你怎么办。<br/><br/>可惜，内鬼年年有，&#34;注册成功&#34;几个字还是出卖了你，打开ollydbg，查找字符串参考，然后双击：<br/><br/><img width="630" height="456" src="http://www.mzwu.com/pic/202004/135.jpg" border="0" alt=""/><br/><br/><img width="630" height="371" src="http://www.mzwu.com/pic/202004/136.jpg" border="0" alt=""/><br/><br/>哦豁，完蛋，换汤不换药，还是给逮住了。<br/><br/>你察觉到这样一个地方判断注册码实在不靠谱，所以，你改变了策略，把检查注册码的代码复制了n遍，或者逐字符检查注册码的准确性，还有人将注册成功等字样进行加密或混淆，等到要用的时候再取出来：<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code66132);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code66132>#include &#34;stdio.h&#34;<br/>#include &#34;string.h&#34;<br/>#include &#34;windows.h&#34;<br/>#include &#34;math.h&#34;<br/><br/>int main()<br/>{<br/>&#160;&#160;&#160;&#160;char iKey[32];<br/>&#160;&#160;&#160;&#160;char Key[32];<br/>&#160;&#160;&#160;&#160;char ID[32];<br/>&#160;&#160;&#160;&#160;int iID=0xabc1d3f;<br/>&#160;&#160;&#160;&#160;sprintf(Key,&#34;%x&#34;,iID*8+123456);<br/>&#160;&#160;&#160;&#160;printf(&#34;你的机器码是%x\n&#34;,iID);<br/>&#160;&#160;&#160;&#160;printf(&#34;请输入注册码:&#34;);<br/>&#160;&#160;&#160;&#160;gets(iKey);<br/>&#160;&#160;&#160;&#160;if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>}</div></div><br/>你放心，不管你复制多少次，要找出来都是时间问题，吃枣是会被破解的。同时只要你要用到明文字符串你迟早还是要解密的，这种手段类似于加upx压缩壳，只需要等待数据解压完成，所有的东西又都是明文的了。因此比较聪明的做法是，要用时解密，用完后马上把明文抹掉，这样说不定能拖延更长的时间。但这仍然也是时间问题。<br/><br/>你开始发现，与其揪出内鬼，不如主动出击，也就是我们著名的与其解决问题不如解决提出问题的人，终于，你开始对调试器下手了，然后你成功进化到防破解V2.5时代。<br/><br/>这个时候，不得不介绍一个老掉牙的但非常有名的函数：<br/><br/>IsDebugPresent<br/><br/>你可能有点懵，这个函数是干啥子用的?，简单来说，当我们破解一个程序的时候，大部分情况下我们会打开一个叫调试器的东西来对软件进行反编译分析，诶，重点就在这，IsDebugPresent这个函数，就能检测我们的程序有没有被一个调试器附加，你想啊，正常情况我们用软件谁会吃饱撑着附加一个调试器来用，你要是用调试器附加我，你肯定就是想干坏事。<br/><br/>于是，你开始把代码写成这样:<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code13804);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code13804>#include &#34;stdio.h&#34;<br/>#include &#34;string.h&#34;<br/>#include &#34;windows.h&#34;<br/>#include &#34;math.h&#34;<br/><br/>int main()<br/>{<br/>&#160;&#160;&#160;&#160;char iKey[32];<br/>&#160;&#160;&#160;&#160;char Key[32];<br/>&#160;&#160;&#160;&#160;char ID[32];<br/>&#160;&#160;&#160;&#160;int iID=0xabc1d3f;<br/>&#160;&#160;&#160;&#160;if (IsDebuggerPresent())<br/>&#160;&#160;&#160;&#160;{<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MessageBoxA(NULL,&#34;小样,就你还破解我的程序,回家喝奶去吧&#34;,&#34;&#34;,MB_OK);<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;return 0;<br/>&#160;&#160;&#160;&#160;}<br/>&#160;&#160;&#160;&#160;sprintf(Key,&#34;%x&#34;,iID*8+123456);<br/>&#160;&#160;&#160;&#160;printf(&#34;你的机器码是%x\n&#34;,iID);<br/>&#160;&#160;&#160;&#160;printf(&#34;请输入注册码:&#34;);<br/>&#160;&#160;&#160;&#160;gets(iKey);<br/>&#160;&#160;&#160;&#160;if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>}</div></div><br/>于是，当下次再ollydbg加载调试你的程序的时候，就会出现下面的情景：<br/><br/><img width="630" height="407" src="http://www.mzwu.com/pic/202004/137.jpg" border="0" alt=""/><br/><br/>曾经很长一段时间(包括现在)，很多软件或加密壳都会检查是否有调试器正在调试自己，比如tls段会在加载时被执行，如果检查到自己正在被人调试破解，就会设置一个tag让程序跑到没啥用的地方去或者直接退出重新，也有利用变形的PE头让调试器无法加载，总之手段很多。<br/><br/>可惜这还是没什么卵用，比如IsDebugPresent可以通过修改FS寄存器的标志位来让它彻底哑火，同样的手段包括但不限于检查int 3软中断，Raw Call，Query PEB，检查Debug Privilege和父进程等等等等，都有绕过的方式。<br/><br/><img src="http://www.mzwu.com/pic/202004/138.jpg" border="0" alt=""/><br/><br/>暗桩嘛，只要你插，一个一个拔总是拔的完的。<br/><br/>好了，还有啥法子不，放心道高一尺魔高一丈，现在我们来到了现在最流行的，防破解V3.0 VMP时代，<br/><br/>先澄清一下，这里的VMP并不是VMP壳，它全程叫Virtual Machine Protection，简单来说，为啥我们破解软件那么轻车熟路，还不是因为x86 x64 arm的那堆汇编指令集我们太熟悉了呗。要是我们自己发明一套指令集，然后用这个指令集写程序并运行在我们自己的虚拟机上，那么，破解者一进来，看到的不就是一脸懵逼了么<br/><br/>可惜的是，VM的运行机制决定了它可能造成几十倍乃至几百倍的性能损失，所以，VMP必须用于保护那种关键且不是性能瓶颈的代码，否者你的软件跑起来就会像：<br/><br/><img src="http://www.mzwu.com/pic/202004/139.jpg" border="0" alt=""/><br/><br/>那么，VMP保护机制是完美的么，当然不是，VMP说白了，也只能做到延长分析时间，你要是把VMP做的足够复杂，足够让一个Cracker醉生梦死了，但是如果这个时间足够久，你的软件足够的值钱让人有欲望来破解， 他们仍然可以充分地分析你VM机的运行机制，当你的VM机运行机制被摸清了，软件就离沦陷不远了。<br/><br/>不过你可以放心，分析VM机执行机理，可比自己写VM机要头疼多了，毕竟一个是你需要通过代码来揣测别人的思路，而另一个本身是自己的思路转为代码，因此基于这点可以说:<br/><br/>破解软件比制作软件简单，在很多情况下，不存在的!<br/><br/>你可能会问了，为什么现在市面上那么多软件，那么多游戏，购买了那么多听起来那么牛逼的保护软件，结果还是被破解了。而且刚发出来一天就被破解了。<br/><br/>其实很大的问题就出在这个商业保护软件(比如保护壳)上，因为这类保护壳大多都会被卖给一大票的软件开发商，有一句话叫树大招风，就像现在流行的VMP保护机制，之所以能保护，是因为其运行机理破解者不明确，如果你这个软件就给自己用，而且你这软件还不怎么值钱，除非大佬空虚寂寞冷，不然谁会有那闲工夫去分析你的虚拟机是怎么跑的，但商业保护壳不同，不论其采用什么样的保护机制，只要分析过一遍搞清楚了，几乎所有使用这类保护机制的软件都会沦陷，而且在灰色产业上。这种破解甚至还颇有利可图，只要这个保护机制不更新，一次投入，长期回报。于是只有说在第一次分析时会花上很长的时间，之后就都只是玩套路了。<br/><br/>因此，购买商业保护壳，其实其保护效果并没有想象中的那么强，很可能在灰色产业中形同虚设，甚至一个具有反逆向基础的码农自己写的说不定还更有效果。当然一个软件是被破解概率高不高，仍然是我之前提到的那句话:防破解不是让软件无法破解，而是让破解软件的成本远大于购买软件的成本。<br/><br/>毕竟你说你一个软件拿来开源都没人爱用，你还整天琢磨着怎么才不会被破解，寒掺不老铁。<br/><br/>那么你会开始问了，有没有更给力点的防破解技术?好像之前说的说来说去，无非就是拖延时间，诶，这个我们要摆正心态，不论是加密还是破解，其实说白了最终就是拖延时间，你看那些加密算法，依据其数学理论，如果要破解，它的计算量就算你把全世界的计算机加起来一块算，也够你算三个世界末日了。<br/><br/>不过别担心，更给力的方法还是有的，你想啊，为什么我们之前说了那么多软件都被破解了，最最关键的一个原因，是我们能搞到代码，即使这个代码已经是经过编译后的一堆汇编指令，但只要我们有这堆代码，迟早我们还是能搞懂这个程序是怎么回事的，然后我们就可以对症下药干坏事。<br/><br/>这就像给你有一包面粉，而程序就是一个面包机，你把面粉塞进面包机做出了面包，有天你好奇啊，这面包机咋整咋整就出来一块面包了呢，你就动手把面包机拆了，然后你就知道面包机是怎么回事了。<br/><br/>所以有没有办法不让用户知道我们的代码是什么样的呢，就像你把面粉交给了面包师傅做面包，这个面包是怎么做的，你就只能指望看面包师傅有没有这个心情告诉你了。<br/><br/>为此，有请早期一个相当流行且普遍的游戏防破解工具(物理)<br/><br/><img src="http://www.mzwu.com/pic/202004/140.jpg" border="0" alt=""/><br/><br/>你现在可能表情是一脸问号，但我没和你开玩笑，在2000年时代，大部分的游戏运行在光盘CD中，但盗版也容易啊，把光盘里的数据一复制下来，然后就可以复制出一万张盗版光碟，所以游戏厂商们就想办法，想来想去就想到了榔头。<br/><br/>其操作方法很简单，拿榔头和钉子，在光盘上钉几条刮痕出来，造成人工的坏道，然后再将数据烧录到正确的扇区中，这样下来虽然程序还是可以正确运行，但是当光头读盘读到这个坏道的时候，就会读不过去，于是你会发现打开光盘后，没有关键的文件，这样你就没办法将游戏或者说程序拷贝出来了，同时还会对坏道的位置做一个标记，游戏运行时也会检查这个标记，那么想要盗版你就也得拿起榔头在光盘同样的位置上砸出同样的刮痕出来，当然，这几乎是不可能的。<br/><br/>当年这个技术当年又叫防盗环技术，但不管它的名字叫的多高大上，本质上就和榔头钉钉子如出一辙是同样的东西，可惜虚拟光驱出现后，同样有办法复刻光盘的一切数据(包括坏道)，所以，这个技术拿到今天来看并没有什么卵用。不过这仍然给了我们足够的启发。<br/><br/>现在让我们进入防破解V3.x时代，之所以不叫V4.0是因为这类技术很早就有并且比VMP保护流行的时间还早的多，而且它可能是最近接理论上不可破解的防破解手段。<br/><br/>我们先聊的是加密狗或者又叫Ukey保护，就是运行软件你需要插入一个U盘一样的东西到电脑上，实际上这个Ukey是一个微型电脑，软件的一些关键的算法和代码，都在这个UKey的芯片里，当我们PC上的软件运行后，当我们需要执行这类关键算法时，我们会向这个Ukey传递数据，然后UKey将结果计算出来，返回给PC的软件上，这样就避免了用户直接能够逆向取得关键的算法代码，破解也就无从谈起了。这也就是为什么到了今天，Ukey保护仍然非常的流行。<br/><br/>可惜，UKey保护仍然有诸多的限制，首先就是带着一个Ukey贼麻烦，万一UKey丢了补办是一个麻烦事，运行软件插Ukey也是个神烦的事情，同时，UKey的性能决定了它可能不能执行一些过于消耗性能和内存空间的代码，数据交互也因带宽和通讯延迟会造成性能损失，所以它和VMP保护机制一样，同样不是一个省油的灯，同时开发人员的水平不到位，该保护的代码没保护，保护来没啥用的代码塞了一堆，也会给Cracker带来机会，而且只要你的软件够值钱，你是不是太瞧不起我华强北了：<br/><br/><img src="http://www.mzwu.com/pic/202004/141.jpg" border="0" alt=""/><br/><br/>把Ukey拆开来，使用某种&#34;药水&#34;剥开外层找到内部的芯片并接上已经熔断的&#34;读引脚&#34;(有些芯片连这步都省了，直接热风枪一吹接板读ROM) 然后再把芯片的代码给读出来。<br/><br/>于是，UKey保护也宣布沦陷。<br/><br/>你发现，只要是把实体的东西交到用户的手上，迟早会出问题，所以，这个Ukey保护现在大部分情况下变成了带数字证书的网络验证模式，这类的关键代码从Ukey转移到了服务器上，数据交互通过网络来做。其实这种保护机制和Ukey保护原理是一样的并没有什么本质的区别，但同样处于网络带宽也延迟的考虑，同样具有一定的性能损失和设计缺陷。<br/>需要重点提及的是，这类网络保护的手段必须专门设计以保护程序中的一系列关键&#34;功能&#34;代码而不是&#34;防破解&#34;代码(比如代码解密，注册验证)，因为后者几乎没啥卵用仍然能够将&#34;防破解&#34;的代码清除或Dump解密代码或伪造本地服务器实现破解。<br/><br/>所以你指望一堆什么x盾，x宝一键能一劳永逸一键保护程序，程序必须经过专业码农而不是彩笔专门的设计才能起到其应有的保护效果。<br/><br/>但现实情况是，处于用户离线运行和性能延迟瓶颈的考虑，这种网络保护设计的往往都有很大的缺陷，因此，并不是说这东西不好，而是理想很丰满现实很骨干，实在无能为力啊。<br/><br/>原文链接：<a href="https://www.toutiao.com/a6815476340142113283/" target="_blank" rel="external">https://www.toutiao.com/a6815476340142113283/</a>]]></description>
		</item>
		
</channel>
</rss>
