目标:读取嵌入项目中的文件资源。
工具: VS2019 community
有时候,我们需要使用定义的标准模板文件作为基准,对程序进行相应的设置,但是模板文件如果作为明文文件放置在应用程序的路径下,可能会被外边界的其它因素修改。这时候就需要把文件作为资源嵌入到项目的应用程序,或者dll库中。这里介绍使用内嵌入应用程序的方法。
把项目文件资源嵌入应用程序中,有2中方法可以实现:
一。把项目使用的资源文件统一放置在一个自定义文件夹中
- 把项目使用的资源文件统一放置在一个自定义文件夹中,并设置为嵌入资源。如下图
黄色框内是新建的一个文件夹,名称为InsertedFiles,然后我们添加一个文件,名称为system.ini。把文件的生成操作设置为“嵌入的资源”,如红色框内所示。
我们后续读取该文件时,需要使用的路径为:项目名称.文件夹.文件名称。比如这里的项目名称是MacroProgram,则我们要读取的文件具体路径就是:MacroProgram.InsertedFiles.system.ini - 读取文件的C#代码如下:
/// <summary>
/// 从项目嵌入的资源中读取指定的资源文件。
/// </summary>
/// <param name="filename">指定的资源文件名称</param>
/// <returns>返回的资源文件流</returns>
public Stream GetResource(string filename)
{
filename = "InsertedFiles.system.ini";
//获得正在运行类所在的名称空间
string _namespace = MethodBase.GetCurrentMethod().DeclaringType.Namespace;
//获得当前运行的Assembly 方法1
Assembly _assembly = Assembly.GetExecutingAssembly();
//获得当前运行的Assembly 方法2
Assembly _assembly1 = this.GetType().Assembly;
//读取assembly的名称
_namespace = _assembly.GetName().Name;
//根据名称空间和文件名生成资源名称
string resourceName = _namespace+"." + filename;
Debug.Print(_namespace +":"+resourceName);
//根据资源名称从Assembly中获取此资源的Stream
Stream istr = _assembly.GetManifestResourceStream(resourceName);
#if DEBUG
if (istr is null) Debug.Print(resourceName+" is NULL");
else Debug.Print(resourceName +" is OK");
#endif
#if DEBUG
// Enumerate the assembly's manifest resources
foreach (string resourceName1 in _assembly.GetManifestResourceNames())
{
Debug.Print(resourceName1);
istr = _assembly.GetManifestResourceStream(resourceName1);
if (istr is null) Debug.Print(resourceName1 +" is not found");
else Debug.Print(resourceName1+" is Found");
}
#endif
return istr;
}
- 运行后得到的输出如下:参见红色框内结果:
第一个红框是读取的结果输出,第二个是读取当前项目中所有资源的结果,说明我们嵌入到 项目中的文件在整体资源中。
二。把资源文件嵌入到项目的资源中。
(暂时发布,明天继续)
continue:
这是最省事的方法,没有之一。因为微软已经帮忙做好了很多准备。在项目属性的资源里面添加对应得文件资源后,就可以直接使用Properties.Resources进行资源调用了;当然,也可以是用内嵌的ResourceManager来调用资源文件。参见下图:
我们插入图片About.gif后,会得到1框的资源列表,这个资源不管是嵌入的资源,还是其它模式的资源,都可以使用Properties.Resources.About来进行调用,此时注意,这是按照资源属性来调用资源的,没有文件的扩展名。其实这个调用微软已经进行后台处理了,参见下段代码:
/// <summary>
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>
public static System.Drawing.Bitmap About {
get {
object obj = ResourceManager.GetObject("About", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
这段代码是系统自动生成的,也展示了如何进行调用。也就是说,若想定义自己的调用方法,则可以使用这个ResourceManager.GetObject的方法来调用任何内置的资源,而不使用Properties.Resources进行固定调用。ResourceManager的实例化,微软也已经帮忙内置处理完毕,参见红框2的自动生成代码,也摘录如下:
/// <summary>
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MacroProgram.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
然后我们就可以使用这个ResourceManager 进行自己的资源调用,再也不担心资源被他人修改了。这里贴上一个调用代码,只要求实现功能,不求精简:
/// <summary>
/// 从项目嵌入的项目属性资源中读取指定的资源文件。eg: About.gif
/// </summary>
/// <param name="filenameOnly">指定的资源文件名称,不带扩展名</param>
/// <returns>返回的资源对象</returns>
public Object GetPropertiesResources(string filenameOnly)
{
//filename = "Resources.About.gif";
//获得正在运行类所在的名称空间
string _namespace = MethodBase.GetCurrentMethod().DeclaringType.Namespace;
//获得当前运行的Assembly 方法1
Assembly _assembly = Assembly.GetExecutingAssembly();
//获得当前运行的Assembly 方法2
Assembly _assembly1 = this.GetType().Assembly;
//读取assembly的名称
_namespace = _assembly.GetName().Name;
//根据名称空间和文件名生成资源名称
string resourceName = _namespace + "" + ".Properties.Resources";
Debug.Print(_namespace + ":" + resourceName);
//实例化资源管理类
ResourceManager resourceManager = new ResourceManager(resourceName, _assembly1);
//根据资源名获得资源对象
return resourceManager.GetObject(filenameOnly);
}
综上两种资源调用,本质是一样的,只是后者已经封装完毕,使用更加方便。
资源已经有了,后续如何流化,如何使用,就根据需要进行处理即可。
完毕。
向兢兢业业的小白同道致意!共勉