Files
AohDrllTools/AnsiFileReader.cs
Mr.Xia b75439cff4 fix: 修复含特殊字符路径的钻带文件读取失败 — 移除 cmd /c type,改为 AnsiFileReader 直接文件IO
问题:路径含 ( ) & % ! ^ @ 等字符时报"文件路径包含不允许的命令行特殊字符",
(D2-f)、(1) 这类正常业务文件名直接命中。

根因:读取统一入口把路径拼进命令行(cmd.exe /d /c type "..."),为"防炸"在 03d9b8b
引入 ForbiddenPathChars 黑名单——并非业务需求,是实现的自我约束。
实测:真正会坏的只有 %VAR%(必坏) 与延迟展开开启时的 !VAR!,而 ( ) & ^ @ 空格在
双引号内均正常;且 type 是字节透传,这层 cmd 对当初的编码问题毫无帮助。

改动:
- 新增 AnsiFileReader.cs:FileStream + StreamReader(默认 936 解码 + BOM 探测,
  与旧 StreamReader 解码路径逐字符等价),不经命令行
- 删除 CommandTypeFileReader.cs 及其 ForbiddenPathChars 字符校验
- 路径只保留"非空"与"文件存在"校验;IO 异常包装为
  InvalidOperationException("读取文件失败:{路径}({原因})")并保留 InnerException
- 15 处调用点同步改名;更新 CLAUDE.md 与 Docs 说明

验证:14 个 demo_drl 样例新旧实现字符串/行数逐字符一致;含特殊字符路径(含 %TEMP% 字面
路径,旧实现 rc=1)可读可解析;UTF-8/UTF-16 BOM 结果与旧实现一致;
dotnet build -p:Platform=x86 0 错误且警告集与基线逐条相同。
2026-09-20 11:30:04 +08:00

60 lines
2.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.IO;
using System.Text;
namespace DrillTools
{
/// <summary>
/// 钻带/参数文件统一读取入口。
/// 默认按 ANSI/GB2312(code page 936) 解码,等价于历史 `cmd type` 实现的字节透传语义,
/// 但不经过命令行,因此路径中的特殊字符(如 `(` `)` `&` `%` `!` `^` `@` 空格)不会影响读取。
/// </summary>
internal static class AnsiFileReader
{
private const int Gb2312CodePage = 936;
public static string ReadAllText(string filePath)
{
return ReadAllText(filePath, CreateAnsiEncoding());
}
public static string ReadAllText(string filePath, Encoding encoding)
{
string normalizedPath = ValidateAndNormalizePath(filePath);
try
{
using var stream = new FileStream(normalizedPath, FileMode.Open, FileAccess.Read, FileShare.Read);
// detectEncodingFromByteOrderMarks: true 与历史实现保持一致:
// 原先经 Process.StandardOutput(StreamReader) 解码,默认会探测 BOM,
// 因此带 UTF-8/UTF-16 BOM 的文件解码结果保持不变。
using var reader = new StreamReader(stream, encoding, detectEncodingFromByteOrderMarks: true);
return reader.ReadToEnd();
}
catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException)
{
throw new InvalidOperationException($"读取文件失败:{normalizedPath}({ex.Message})", ex);
}
}
private static string ValidateAndNormalizePath(string filePath)
{
if (string.IsNullOrWhiteSpace(filePath))
throw new ArgumentException("文件路径不能为空", nameof(filePath));
string normalizedPath = Path.GetFullPath(filePath);
if (!File.Exists(normalizedPath))
throw new FileNotFoundException($"文件不存在:{normalizedPath}", normalizedPath);
return normalizedPath;
}
private static Encoding CreateAnsiEncoding()
{
return Encoding.GetEncoding(Gb2312CodePage);
}
}
}