C#中需将文件“生成操作”设为Embedded Resource才能嵌入EXE,资源名由默认命名空间+文件夹路径+文件名组成,运行时用GetManifestResourceStream()配合完整资源名读取字节流。
在C#项目中设置文件为“嵌入的资源”
Visual Studio默认不会把普通文件打包进EXE,必须显式标记为Embedded Resource。右键文件 → “属性” → 将“生成操作”改为Embedded Resource。注意:路径中的文件夹结构会变成命名空间的一部分,比如Assets\icon.png在MyApp项目里,完整资源名是MyApp.Assets.icon.png。
常见错误:忘记改“生成操作”,仍用Content或None——编译后文件不会进入程序集,Assembly.GetExecutingAssembly().GetManifestResourceNames()也查不到。
- 确保文件“复制到输出目录”设为
Do not copy(否则会多出一个外部副本) - 若文件名含空格或特殊字符,资源名会自动转义(如
my file.txt→my_file.txt),建议用下划线或驼峰避免歧义 - 多个同名文件放在不同子目录时,资源名唯一,不会冲突
运行时读取嵌入资源的字节流
嵌入资源本质是编译进程序集的只读字节块,不能直接当文件路径使用。要用Assembly.GetExecutingAssembly().GetManifestResourceStream()打开,传入**完整资源名称**(区分大小写)。
示例代码:
var assembly = Assembly.GetExecutingAssembly();
string resourceName = "MyApp.Assets.config.json";
using var stream = assembly.GetManifestResourceStream(resourceName);
if (stream == null)
throw new InvalidOperationException($"Resource '{resourceName}' not found. Available: {string.Join(", ", assembly.GetManifestResourceNames())}");
using var reader = new StreamReader(stream);
string content = reader.ReadToEnd();
容易踩的坑:
-
GetManifestResourceStream()返回null时,别假设路径错——先打印GetManifestResourceNames()确认实际注册名 - 资源名不支持通配符,也不能用
../向上跳级 - 流读完即关闭,不可重复读取;需多次使用请先
ToArray()缓存字节
处理二进制资源(图片、字体、音频等)
图片、字体这类资源必须以原始字节方式加载,不能走StreamReader。典型场景如从嵌入资源创建Bitmap或Font: