问题:路径含 ( ) & % ! ^ @ 等字符时报"文件路径包含不允许的命令行特殊字符",
(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 错误且警告集与基线逐条相同。
60 lines
2.2 KiB
C#
60 lines
2.2 KiB
C#
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);
|
||
}
|
||
}
|
||
}
|