提取带有特殊字符的嵌入式资源

14

我在获取嵌入资源的流时遇到问题。大多数在线示例显示的路径可以直接通过更改路径中的斜杠为点来翻译源路径(MyFolder/MyFile.ext变为MyNamespace.MyFolder.MyFile.ext)。但是,当文件夹名称包含点并且使用了特殊字符时,手动获取资源名称将无法正常工作。我正在尝试查找一个函数,可以将路径转换为资源名称,因为在编译时Visual Studio会对其进行重命名。

这些名称来自解决方案...

  1. Content/jQuery.UI-1.8.2/jQuery.UI.css
  2. Scripts/jQuery-1.5.2/jQuery.js
  3. Scripts/jQuery.jPlayer-2.0.0/jQuery.jPlayer.js
  4. Scripts/jQuery.UI-1.8.2/jQuery.UI.js

... 在资源中被更改为如下名称...

  1. Content.jQuery.UI_1._8._2.jQuery.UI.css
  2. Scripts.jQuery_1._5._2.jQuery.js
  3. Scripts.jQuery.jPlayer_2._0._0.jQuery.jPlayer.js
  4. Scripts.jQuery.UI_1._8._12.jQuery.UI.js

斜杠被转换为点。但是,当文件夹名称中使用点时,第一个点显然被视为扩展名,其余点被更改为带有下划线前缀的形式。虽然这个逻辑不适用于jQuery.js文件,可能是因为'扩展名'是单个数字?这里有一个函数可以处理到目前为止我遇到的问题,但无法处理jQuery.js路径。

    protected String _GetResourceName( String[] zSegments )
    {
        String zResource = String.Empty;

        for ( int i = 0; i < zSegments.Length; i++ )
        {
            if ( i != ( zSegments.Length - 1 ))
            {
                int iPos = zSegments[i].IndexOf( '.' );

                if ( iPos != -1 )
                {
                    zSegments[i] = zSegments[i].Substring( 0, iPos + 1 )
                                 + zSegments[i].Substring( iPos + 1 ).Replace( ".", "._" );
                }
            }

            zResource += zSegments[i].Replace( '/', '.' ).Replace( '-', '_' );
        }

        return String.Concat( _zAssemblyName, zResource );
    }
有没有一个函数可以帮我更改名称?它是什么?或者在哪里可以找到所有规则,以便我可以编写自己的函数?感谢您可能能够提供的任何帮助。

有没有一个函数可以帮我更改名称?它是什么?或者在哪里可以找到所有规则,以便我可以编写自己的函数?感谢您可能能够提供的任何帮助。

4个回答

12

这个回答有些晚了,但既然它是谷歌搜索结果的第一个,我想我还是分享一下我的发现!

你可以强制编译器按照你所想要的名称来命名嵌入式资源;从一开始就解决了这个问题……你只需要编辑你的 csproj 文件,这和使用通配符一样简单!以下是我所做的:

<EmbeddedResource Include="$(SolutionDir)\somefolder\**">
  <Link>somefolder\%(RecursiveDir)%(Filename)%(Extension)</Link>
  <LogicalName>somefolder:\%(RecursiveDir)%(Filename)%(Extension)</LogicalName>
</EmbeddedResource>
在这种情况下,我告诉Visual Studio,我想将“某个文件夹”中的所有文件作为嵌入式资源导入。同时,我希望它们在VS解决方案资源管理器中显示为“某个文件夹”下的文件(这是链接标记)。最后,在编译它们时,我希望它们的名称与它们在我的磁盘上具有相同的名称和地址,只有“somefolder:\”前缀不同。最后一部分是实现魔法的关键。

设置:在Visual Studio中编辑CSPROJ文件时,答案的XML代码将被追加/添加,而不是替换现有的XML <EmbeddedResource>。用法:一个名为“World”的项目,其中包含一个名为“Media”的文件夹,其中包含一个名为“Vector.svg”的svg文件,需要将XML代码中的三个条目“somefolder”替换为“Media”。然后在CS代码中,您可以使用以下代码获取流:Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("World.Media.Vector.svg") - SourceSeeker

5
这是我想出的解决问题的方法。虽然有点 hack,但似乎符合当前规范,我仍然开放接受更好的方法。该函数期望处理来自 Uri 的一个段(在处理网络请求时为 LocalPath)。以下是示例调用。
    protected String _GetResourceName( String[] zSegments )
    {
        // Initialize the resource string to return.
        String zResource = String.Empty;

        // Initialize the variables for the dot- and find position.
        int iDotPos, iFindPos;

        // Loop through the segments of the provided Uri.
        for ( int i = 0; i < zSegments.Length; i++ )
        {
            // Find the first occurrence of the dot character.
            iDotPos = zSegments[i].IndexOf( '.' );

            // Check if this segment is a folder segment.
            if ( i < zSegments.Length - 1 )
            {
                // A dash in a folder segment will cause each following dot occurrence to be appended with an underscore.
                if (( iFindPos = zSegments[i].IndexOf( '-' )) != -1 && iDotPos != -1 )
                {
                    zSegments[i] = zSegments[i].Substring( 0, iFindPos + 1 ) + zSegments[i].Substring( iFindPos + 1 ).Replace( ".", "._" );
                }

                // A dash is replaced with an underscore when no underscores are in the name or a dot occurrence is before it.
                //if (( iFindPos = zSegments[i].IndexOf( '_' )) == -1 || ( iDotPos >= 0 && iDotPos < iFindPos ))
                {
                    zSegments[i] = zSegments[i].Replace( '-', '_' );
                }
            }

            // Each slash is replaced by a dot.
            zResource += zSegments[i].Replace( '/', '.' );
        }

        // Return the assembly name with the resource name.
        return String.Concat( _zAssemblyName, zResource );
    }

Example call..

    var testResourceName = _GetResourceName( new String[] {
        "/",
        "Scripts/",
        "jQuery.UI-1.8.12/",
        "jQuery-_.UI.js"
    });

1

Roel,

嗯...这是一个hack,但我想它应该可以工作。只需在包含资源的每个目录中定义一个空的“Marker”类,然后获取其类型的FullName,从末尾删除类名,就可以得到解码路径。

string path = (new MarkerClass()).GetType().FullName.Replace(".MarkerClass", "");

我相信有一种“更好”的方法...需要更多的代码行;而这个方法的优点是当Microsoft改变东西时,他们会维护它;-)

干杯。Keith。


感谢您的快速回复,Keith。我找不到所提到的类,尽管它似乎在“Microsoft.Dss.Services.AssemblyEmbeddedResourceService”中(本地没有)。这通常也意味着mono没有对其进行实现,这是我不能忽视的事情。也许还有其他方法? - Deathspike
我再次强调:在每个包含资源的目录中定义一个空的“标记”类。我只是随意起了一个名字叫“MarkerClass”。我曾经进行过一些谷歌搜索,因为必须有更好的方法,最终找到了这个小宝石:https://dev59.com/HHVD5IYBdhLWcg3wTJrF ... 希望这对你有用。 - corlettk
你不能在带有点的命名空间中定义类(这正是我需要的信息,嵌入式资源名称是如何编码的?)。一旦名称正确,我就可以像您提供的链接参考那样简单地使用GetManifestResourceStream。 - Deathspike
我不知道在路径中包含点的目录中不能定义类... 我猜你被困在试图弄清楚微软规则以便自己编码路径的过程中。唉。 - corlettk

0
这里也是一个晚回答,我在自己尝试之前进行了谷歌搜索,最终不得不这样做。
以下是我想出的解决方案:
    public string ProcessFolderDash(string path)
    {
        int dotCount = path.Split('/').Length - 1; // Gets the count of slashes
        int dotCountLoop = 1; // Placeholder

        string[] absolutepath = path.Split('/');
        for (int i = 0; i < absolutepath.Length; i++)
        {
            if (dotCountLoop <= dotCount) // check to see if its a file
            {
                absolutepath[i] = absolutepath[i].Replace("-", "_");
            }

            dotCountLoop++;
        }

        return String.Join("/", absolutepath);
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接