惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

TaoSecurity Blog
TaoSecurity Blog
博客园 - 司徒正美
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 【当耐特】
M
MIT News - Artificial intelligence
罗磊的独立博客
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Stack Overflow Blog
Stack Overflow Blog
The GitHub Blog
The GitHub Blog
Google DeepMind News
Google DeepMind News
Security Archives - TechRepublic
Security Archives - TechRepublic
宝玉的分享
宝玉的分享
N
News and Events Feed by Topic
The Hacker News
The Hacker News
Google DeepMind News
Google DeepMind News
C
CERT Recently Published Vulnerability Notes
F
Full Disclosure
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
S
Security @ Cisco Blogs
H
Hacker News: Front Page
L
LangChain Blog
Microsoft Security Blog
Microsoft Security Blog
Y
Y Combinator Blog
B
Blog RSS Feed
H
Heimdal Security Blog
Google Online Security Blog
Google Online Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 三生石上(FineUI控件)
V2EX - 技术
V2EX - 技术
V
Vulnerabilities – Threatpost
Help Net Security
Help Net Security
Hacker News - Newest:
Hacker News - Newest: "LLM"
T
Tailwind CSS Blog
W
WeLiveSecurity
T
Tenable Blog
D
DataBreaches.Net
Martin Fowler
Martin Fowler
Cyberwarzone
Cyberwarzone
Cisco Talos Blog
Cisco Talos Blog
S
Secure Thoughts
O
OpenAI News
L
LINUX DO - 热门话题
Vercel News
Vercel News
阮一峰的网络日志
阮一峰的网络日志
Jina AI
Jina AI
J
Java Code Geeks
Know Your Adversary
Know Your Adversary
IT之家
IT之家
Latest news
Latest news
Cloudbric
Cloudbric

博客园 - VipSoft

MinerU - 将非结构化文档(PDF、图片、Office 文件等)转换为机器可读的 Markdown 和 JSON LangChain 入门 服务端部署-FastAPI LangChain 入门 LangSmith LangChain 入门 实战 - 食谱推荐 LangChain 入门 Memory 会话记忆 LangChain 入门 Tools 工具 LangChain 入门 Tools 工具 LangChain 入门 Prompts 提示词 LangChain 入门 Message 消息 LangChain 入门 Model 的初始化和调用 LangChain 入门 Agent 的基本运行机制 AI 0基础学习,名词解析 LangChain 和 LangGraph AI大模型知识体系 Dify — Workflow - 数据可视化 Dify — 连接MySQL配置 Dify — Chatflow - 数据库智能查询 Dify — Chatflow - 文档知识库 Dify — Agent 智能体 高安全券码、注册码生成 Dify — 文本生成应用 Dify — 聊天助手 -- 知识库 Windows 下 Docker 安装 Dify Ollama — 命令 Ollama — 为什么能够运行不同的模型 Ollama — 接口 Qwen — 自定义模型文件 Ollama Qwen — 安装测试 Ollama Windows 安装 & 指定安装目录 跟着AI学AI - 诊断结论信息抽取 - 批量处理脚本 跟着AI学AI - 诊断结论信息抽取 - 模型压缩与部署 跟着AI学AI - 诊断结论信息抽取 - 模型评估与调试 跟着AI学AI - 诊断结论信息抽取 - 模型训练 轻型民用无人驾驶航空器安全操控理论考试培训材料 FreeRedis Helper Windbg w3wp.DMP 内存分析 跟着AI学AI - 诊断结论信息抽取 - 数据增强 QQ 录屏软件 Java - 加权随机算法 - 示例 Java - 加权随机算法--Demo Java LoadBalanceUtil 负载均衡、轮询加权 SpringBoot 集成 IP2Region 获取IP地域信息 Windows 服务器和虚拟主机,创建.开头的文件夹 .well-known 跟着AI学AI - 诊断结论信息抽取 - 数据格式转换BERT训练格式 跟着AI学AI - 诊断结论信息抽取 - LabelStudio 标注 -- 结论标注 跟着AI学AI - 诊断结论信息抽取 - 学习路径 跟着AI学AI - UV 安装 数据标注工具 Label-Studio `VIRTUAL_ENV=venv` does not match the project environment 跟着AI学AI - 学习路径 - 命名实体识别(NER)和信息抽取(IE) 跟着AI学AI - 需要购买显卡吗? Vue ref reactive Vue - el-table 嵌套表 Spring `@Scheduled` 中这些参数的区别、组合和应用场景 Python 找出同步日志中的重复数据 Python - UV PyCharm 不能识别 .venv 的环境
C# 无BOM的UTF-8编码
VipSoft · 2026-01-14 · via 博客园 - VipSoft

你发现了一个很常见的编码问题。System.Text.Encoding.GetEncoding("utf-8") 默认情况下会使用带有BOM(Byte Order Mark,字节顺序标记)的UTF-8编码。BOM在某些场景下会导致问题,比如命令行显示乱码。

问题分析

  1. UTF-8 vs UTF-8-BOM:

    • UTF-8: 纯UTF-8,不包含BOM
    • UTF-8-BOM: UTF-8 with BOM,在文件开头有EF BB BF三个字节作为标记
  2. 命令行显示乱码的原因:

    • Windows命令行(cmd)默认使用GBK编码
    • 当UTF-8-BOM文件在命令行显示时,BOM字符会被显示为乱码"锘"
    • 后续内容也可能因为编码不匹配而显示乱码

解决方案

以下是修改后的WriteLog方法,解决编码问题:

方案1:使用无BOM的UTF-8编码(推荐)

private void WriteLog(string fileName, string msg)
{
    System.IO.FileStream fst = null;
    System.IO.StreamWriter swt = null;
    try
    {
        string time = System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        string savePath = ConfigurationManager.AppSettings["FileTempPath"];
        string filePath = Path.Combine(savePath, fileName);
        
        // 确保目录存在
        string directory = Path.GetDirectoryName(filePath);
        if (!Directory.Exists(directory))
        {
            Directory.CreateDirectory(directory);
        }
        
        // 使用无BOM的UTF-8编码
        var utf8WithoutBom = new System.Text.UTF8Encoding(false);
        
        // 方法1:使用StreamWriter构造函数
        fst = new System.IO.FileStream(filePath, System.IO.FileMode.Append);
        swt = new System.IO.StreamWriter(fst, utf8WithoutBom);
        
        // 方法2:或者使用File.AppendText(更简洁)
        // using (swt = System.IO.File.AppendText(filePath))
        // {
        //     swt.WriteLine(time + " | " + msg.ToString());
        // }
        
        swt.WriteLine(time + " | " + msg);
    }
    catch (Exception ex)
    {
        logger.Error(ex, ex.Message);
    }
    finally
    {
        if (swt != null)
        {
            swt.Close();
        }
        if (fst != null)
        {
            fst.Close();
        }
    }
}

方案2:使用File.AppendText(自动处理编码)

private void WriteLog(string fileName, string msg)
{
    try
    {
        string time = System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        string savePath = ConfigurationManager.AppSettings["FileTempPath"];
        string filePath = Path.Combine(savePath, fileName);
        
        // 确保目录存在
        string directory = Path.GetDirectoryName(filePath);
        if (!Directory.Exists(directory))
        {
            Directory.CreateDirectory(directory);
        }
        
        // 使用File.AppendText(默认无BOM的UTF-8)
        using (var sw = System.IO.File.AppendText(filePath))
        {
            sw.WriteLine(time + " | " + msg);
        }
    }
    catch (Exception ex)
    {
        logger.Error(ex, ex.Message);
    }
}

方案3:更完整的版本(支持编码选择)

private void WriteLog(string fileName, string msg, bool useUtf8Bom = false)
{
    try
    {
        string time = System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        string savePath = ConfigurationManager.AppSettings["FileTempPath"];
        string filePath = Path.Combine(savePath, fileName);
        
        // 确保目录存在
        string directory = Path.GetDirectoryName(filePath);
        if (!Directory.Exists(directory))
        {
            Directory.CreateDirectory(directory);
        }
        
        string content = time + " | " + msg + Environment.NewLine;
        
        // 根据参数选择编码
        System.Text.Encoding encoding;
        if (useUtf8Bom)
        {
            encoding = System.Text.Encoding.UTF8; // 带BOM
        }
        else
        {
            encoding = new System.Text.UTF8Encoding(false); // 不带BOM
        }
        
        // 追加写入文件
        System.IO.File.AppendAllText(filePath, content, encoding);
    }
    catch (Exception ex)
    {
        logger.Error(ex, ex.Message);
    }
}

关键修改说明

  1. 使用new UTF8Encoding(false):

    // false 表示不包含BOM
    var utf8WithoutBom = new System.Text.UTF8Encoding(false);
    
  2. 使用File.AppendText:

    • 这个方法默认使用无BOM的UTF-8编码
    • 代码更简洁,自动处理资源释放
  3. 使用File.AppendAllText:

    • 一次性完成写入操作
    • 可以指定编码格式
  4. 改进路径处理:

    • 使用Path.Combine代替字符串拼接
    • 使用Path.GetDirectoryName获取目录路径

测试验证

你可以创建一个测试方法来验证编码:

private void TestEncoding()
{
    string testFile = "test_log.txt";
    string testMsg = "测试中文内容";
    
    // 写入测试日志
    WriteLog(testFile, testMsg);
    
    // 读取并检查文件编码
    string filePath = Path.Combine(
        ConfigurationManager.AppSettings["FileTempPath"], 
        testFile);
    
    if (File.Exists(filePath))
    {
        byte[] bytes = File.ReadAllBytes(filePath);
        if (bytes.Length >= 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF)
        {
            Console.WriteLine("文件包含BOM(UTF-8-BOM)");
        }
        else
        {
            Console.WriteLine("文件不包含BOM(纯UTF-8)");
        }
    }
}

对于命令行的建议

如果需要在命令行正确显示UTF-8文件,可以:

  1. 修改命令行编码:

    chcp 65001
    

    这会将命令行编码改为UTF-8

  2. 使用支持UTF-8的终端:

    • Windows Terminal
    • PowerShell Core
    • Git Bash
  3. 在代码中显式指定编码(如果需要在命令行显示):

    // 如果需要兼容命令行显示,可以使用GBK编码
    var gbkEncoding = System.Text.Encoding.GetEncoding("GBK");
    using (var sw = new StreamWriter(filePath, true, gbkEncoding))
    {
        sw.WriteLine(time + " | " + msg);
    }
    

建议使用方案2File.AppendText),因为它最简单且自动处理了无BOM的UTF-8编码问题。