You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中char存储时sizeof、BaseStream.Position、FileStream.Length数值矛盾疑问

问题解答

测试代码

string file = @"G:\test.dat";
int  num = 12;
char c = 'w';
FileStream fsSave = new FileStream(file, FileMode.Create);
BinaryWriter bwSave = new BinaryWriter(fsSave);
Console.WriteLine("Start position:" + bwSave.BaseStream.Position);
//bwSave.Write((int)num);
bwSave.Write((char)c);
Console.WriteLine("End position:" + bwSave.BaseStream.Position);
bwSave.Flush();
bwSave.Close();
fsSave.Close();
FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
Console.WriteLine("char:"+sizeof(char));
Console.WriteLine("int:" + sizeof(int));
Console.WriteLine("fs.Length:" + fs.Length);
Console.ReadLine();
br.Close();
fs.Close();

你观察到的数值矛盾本质是CLR中char类型的内存占用和BinaryWriter序列化字符时的编码输出长度是两个完全独立的概念,二者没有必然关联,具体原因如下:

1. C# char类型的实际内存占用

C#的char是值类型,用于表示一个UTF-16编码的Unicode字符,在内存中固定占用2字节,因此sizeof(char)返回2是完全正确的,该值是char类型的固有属性,不受其他业务逻辑影响。

2. BinaryWriter写char仅输出1字节的原因

BinaryWriter.Write(char)方法默认采用UTF-8编码对字符做序列化后写入流:

  • 本次测试使用的字符'w'属于ASCII字符集范围,UTF-8编码下刚好只占1字节,因此写入后文件长度为1、流位置差值为1
  • 如果写入中文等超出ASCII范围的字符,序列化后的长度可能为2、3甚至4字节,完全由UTF-8编码规则决定,和char本身的2字节内存占用无关

3. int类型三者数值一致的原因

BinaryWriter.Write(int)方法是直接将Int32的4字节原始二进制数据写入流,没有经过文本编码转换,所以序列化后的长度和int类型本身的内存占用完全一致,因此三个数值相等。

对齐测试结果的方法

如果想要让BinaryWriter写入char时输出和内存占用一致的2字节UTF-16编码,只需要在构造BinaryWriter时显式指定编码为Unicode即可:

// 构造时指定使用UTF-16编码序列化字符
BinaryWriter bwSave = new BinaryWriter(fsSave, Encoding.Unicode);

修改后再运行测试,流位置差值、文件长度都会变为2,和sizeof(char)的返回值完全匹配。

内容的提问来源于stack exchange,提问作者wpumain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 07:15:06