none
“链接”资源和“嵌入”资源的区别? RRS feed

  • 问题

  • 各位大家好!

    VS中支持两种资源文件:编译时链接和嵌入resx文件。但是这两种最本质的区别是什么呢?我查阅了MSDN文档,文档叙说如下(摘选最重要部分)——

    链接资源作为文件存储在项目中;在编译期间,从这些文件中取得资源数据,并将其添加到应用程序的清单中。 应用程序的资源文件 (.resx) 只存储指向磁盘上的文件的相对路径或链接。
    对于嵌入资源,资源数据直接以二进制数据的文本表示形式存储在 .resx 文件中。 在任何一种情况下,资源数据都将编译到可执行文件中。

    给我感觉好像链接资源只是一个类似快捷方式一样的东西——理论上把资源拷贝到自动生成的Resources文件夹下面,然后指定相对路径就可以了。而嵌入的资源文件则直接“嵌入”了exe中,无需再指定相对或者绝对路径了……
    现在问题是:我做了一个实验证明之:

    1)我添加了一幅图片,其中把Koala.jpg的Persistance属性设置为”编译时链接“,然后在button事件中:

    private void button1_Click(object senderEventArgs e)
            {
                Assembly asm = Assembly.GetEntryAssembly();
                string s = asm.GetName().Name;
                Stream st = asm.GetManifestResourceStream(s + ".Resources.Koala.jpg");
                pictureBox1.Image = Image.FromStream(st);
            }

    以上代码可以成功运行(生成的exe在obj\Debug下)。同时我把exe移动到其它目录(比如从C移动到E中,其它文件没有拷贝,只移动exe,照样可以显示图片)。

    2)同步骤1,只是把Koala.jpg的Persistance属性设置为”嵌入resx中“,如法炮制,也可以运行。

    那么照例而言——实验1移动了exe,相对路径不存在了,为什么还可以运行呢?


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年2月27日 2:42
    版主

答案

全部回复

  • Hello

    上面有句很重要的话“在任何一种情况下,资源数据都将编译到可执行文件中。”

    这就说明无论在那种情况下,数据资源都已经被编译到EXE中,所以你无论那EXE放在哪里,它都能找到数据资源。就算你使用的是编译时链接,它运行的时候只会从自身的EXE文件中,而不是resx文件中找资源,这点可以从两种方式下产生的EXE文件的大小来判断,另外你也可以用.NET Reflector 把2种文件打开看看是不是它本身已经包含了JPG文件。


    它们之间的区别是假如其他的project也需要用到同一个JPG文件,那你直接把嵌入资源产生的resx文件COPY过去就可以了,因为那个resx已经包含了那个JPG,而如果你使用编译时链接的话,那RES里仅包含一个链接,所以是不行的。

    2012年2月27日 6:40
  • 非常感谢楼主,你的意思是:因为resx包含了二进制封装的jpg文件,所以只要拷贝到另外一个工程中,再引用即可;如果是地址嵌入的话,因为两个项目的地址不一样,造成相对路径的错误,因而也不一样,是吗?谢谢!

       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年2月27日 7:21
    版主
  • Hello

    上面有句很重要的话“在任何一种情况下,资源数据都将编译到可执行文件中。”

    这就说明无论在那种情况下,数据资源都已经被编译到EXE中,所以你无论那EXE放在哪里,它都能找到数据资源。就算你使用的是编译时链接,它运行的时候只会从自身的EXE文件中,而不是resx文件中找资源,这点可以从两种方式下产生的EXE文件的大小来判断,另外你也可以用.NET Reflector 把2种文件打开看看是不是它本身已经包含了JPG文件。


    它们之间的区别是假如其他的project也需要用到同一个JPG文件,那你直接把嵌入资源产生的resx文件COPY过去就可以了,因为那个resx已经包含了那个JPG,而如果你使用编译时链接的话,那RES里仅包含一个链接,所以是不行的。

    应该这样更正(请批示,谢谢!)

    Properties中“资源文件”无论是“连接时编译”或者是“嵌入resx编译”,都是针对resx文件的,并非针对exe自身。它们之间的区别是假如其他的project也需要用到同一个JPG文件,那你直接把嵌入资源产生的resx文件COPY过去就可以了,因为那个resx已经包含了那个JPG,而如果你使用编译时链接的话,那RES里仅包含一个链接,所以是不行的。


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年2月27日 7:26
    版主
  • 呵呵,这个我说错了,我记得把它删掉的,怎么还没删掉呢,以另外一个帖子为准http://social.msdn.microsoft.com/Forums/zh-CN/2212/thread/6cb5c3b2-937b-43d2-a012-525b4705e7ba
    2012年2月27日 8:10
  • 呵呵,这个我说错了,我记得把它删掉的,怎么还没删掉呢,以另外一个帖子为准
    不是,是我恢复了。我想请你看看我这样说可以吧?谢谢!

       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年2月27日 8:11
    版主
  • Hello Wei Dong,

    严格来说不能这么说,我刚才用IL DASM 重新查看了一下,无论Properties中“资源文件”无论是“连接时编译”或者是“嵌入resx编译 ,在exe的metaInfo中的“User Strings” 都会生成相应的元数据item,只不过string类型的资源,会直接把值嵌入到EXE中,而JPG的它只是在元数据中写入了一个ITEM,但真正的资源数据却没有写入。我用reflector可以证实string类型的资源被写入了,更加确信的方法可能要dump那个EXE。


    2012年2月27日 8:55
  • 我的意思是:

    使用Properties的资源文件,无论是“资源文件”或者“嵌入resx”,都只是对resource文件操作,并非针对exe;前者只是保存一个相对地址,后者把binary的真实内容写入到RESX中。

    可以吗?


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年2月27日 9:07
    版主
  • 可以这么说,具体的无论是嵌入 resx,还是string资源,都是在编译的时候嵌入exe.

    2012年2月27日 9:14
  • 如果是这样的话,那么我移动了exe,照例而言相对位置发生了改变,这个程序就无法找到Resources文件以及对应路径中的图片(位于Resources文件夹下),应该要报错的……可是为什么不报错呢?

    另外,你的技术很棒哦,可以告诉我你的QQ号码吗?请点击“QQ我”,谢谢!


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年2月27日 11:50
    版主
  • 当你设定其“编译属性”(BuildAction)为“Embeded Resources”,并且当你编译完了之后,相应的资源数据(如JPG)之类已经嵌入到了EXE中了,这个时候EXE运行已经跟Resources文件没有什么关系了,所以无论你怎么移动EXE,或者就算你生成了EXE后把Resources文件以及对应路径中的图片删除都是没有问题的。
    2012年2月28日 1:08
  • 如果我不是设定编译属性(BuildAction)而是Properties中设定“编译时链接”(仅仅是这个设置),移动exe似乎也可以正常工作的……

       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年2月28日 1:09
    版主
  • 不会吧,如果你不设定编译属性(BuildAction)为“嵌入资源”,那Stream st = asm.GetManifestResourceStream(s + ".Resources.Koala.jpg");都会返回NULL,更不要说移动exe了。

    2012年2月28日 1:54
  • 不会吧,如果你不设定编译属性(BuildAction)为“嵌入资源”,那Stream st = asm.GetManifestResourceStream(s + ".Resources.Koala.jpg");都会返回NULL,更不要说移动exe了。

    是的,如果不设置编译属性,用你上面的方法肯定是null;

    我的意思是:我使用Properties属性那个自动生成的Resource文件中的资源(resx)中的资源,不是手动设置BuildAction(BuildAction默认是None,保持原状);然后我无论是设置“编译时链接”或者是“嵌入resx”,我发现移动exe都照样可以正常读取,为什么呢?


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年2月28日 1:59
    版主
  • 在. resx资源文件无论是链接”资源和“嵌入”资源,都会把JPG文件嵌入到EXE中,不过只能通过ResourceManager来获取。详见 http://msdn.microsoft.com/zh-cn/library/ht9h2dk8.aspx (“在任何一种情况下,资源数据都将编译到可执行文件中。 ”)
    而在BuildAction中选择“嵌入”资源,则资源会被再次嵌入EXE(包括上面那个嵌入的,EXE中会有2个JPG图片),并且只能通过GetManifestResourceStream来获取,

    2012年2月28日 3:11
  • 哦,我明白了,Resx文件无论是哪种形式,都会被编译进入到exe中:

    1)连接时编译:当编译的时候,先读取Resource中相对路径的图片,然后转化成二进制形式,被一同编译进入了exe中。但是如果另外一个项目要使用这个Resource文件,因为Resource中只存储了一个相对地址(你不把这个相对地址的图片以及文件夹拷贝过来,在编译的时候因为无法找到真正对应的图片,可能导致编译错误)。

    2)嵌入编译:直接嵌入到exe和Resources中。因为Resource中直接嵌入了图片元数据,因此无需真正图片了,只要拷贝一个Resource文件加入项目,然后编译即可。

    3)至于BuildAction:也不管相对还是绝对路径,囫囵吞枣把这个pic文件一起编译进入了exe,体积明显增大了许多。


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年2月28日 3:15
    版主
  • 总结的不错:)

    2012年2月28日 3:37
  • 总结的不错:)

    请参考我写的博客,可以给一些意见或者纠错,这是我的理解,谢谢:http://www.cnblogs.com/serviceboynew(关于资源文件)。


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年2月28日 7:21
    版主