是否可以更改资源文件夹位置?

时间:2017-04-28 11:13:12

标签: c#

是否可以更改资源文件夹的位置?

项目通过访问资源路径中的文件来获取资源。

我已经尝试了几种解决方案(获取路径)但没有工作,因为位置/路径似乎会根据您是否正在调试而改变,以及您所使用的计算机。

这就是我想将其更改为静态位置的原因。

3 个答案:

答案 0 :(得分:0)

您应该确实考虑切换到嵌入式资源,正如一些评论所暗示的那样。这样可以更轻松地引用您的个人资源

但是,如果你不想这样做而如果你试图得到的路径相对于可执行文件是一致的那么你可以用这个方法来查找无论执行位置如何,都是路径。

假设资源文件夹位于同一目录中:

// Change @"Resources\" to match the relative path from the exe.
DirectoryInfo directory = new DirectoryInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory + @"Resources\"));`

AppDomain.CurrentDomain.BaseDirectory将返回exe的目录路径。 directory现在将保存资源文件夹的路径。

如果你的exe在C:\Program Files\MyAwesomeApp\路径中。然后directory将等于C:\Program Files\MyAwesomeApp\Resources

如果您的文件尚未写入exe的位置,请确保每个文件的Copy to Output Directory选项设置为Copy alwaysCopy if newer

答案 1 :(得分:0)

我不知道您的意思是什么资源:如果您指的是本地化资源:

在你的startup.cs中:

services.AddLocalization(options => options.ResourcesPath = "Resources");

将文件夹资源添加到项目的根目录。

如果您指的是其他不属于类/接口的资源。因此,您需要在应用程序中阅读和使用的文本文件之类的内容:

// Use depency injection to be able to use HostingEnvironnement
HostingEnvironnemnt.ContentRootPath + "\wwwroot\textfile.txt";

答案 2 :(得分:0)

正如其他人所说,切换到嵌入式资源是最好的选择。我做了一个混合解决方案。因为我项目的代码库中有很多都依赖于路径,所以我已经切换到使用嵌入式资源,但写了一个类来检索你要求的文件并将其复制到硬盘驱动器上的临时位置,并返回它的路径。

它也有点线程安全,并且在每次新程序启动时第一次调用该函数时清除temp文件夹。

请随意批评我的工作。

using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace blah
{
    //there could be a problem with VERY large files and running out of ram. if we end up having those,
    //switch to reading the resource stream and
    //appending the bytes to the file, instead of reading in full and writing in full.
    //-DOSLuke

    //instructions:

    //to add a resource:
    //add it like usual in the solution explorer
    //right click the newly added resource and click properties
    //under the 'build action' dropdown, select 'embedded resource'
    //then it is ready to be accessed.


    //to get a location on disk of a resource: ---this is what our program uses the most.
    //use ResourceHelper.GetResourceLocation("filename.extension");
    //for example:
    //ResourceHelper.GetResourceLocation("template.txt");


    //to obtain a raw resource stream for manipulation
    //ResourceHelper.GetResourceStream("template.txt");
    //this is the proper way of accessing resources


    //to get all the bytes from a resource via a resource stream:
    //ResourceHelper.ReadStreamFully(ResourceHelper.GetResourceStream("template.txt"));


    //what GetResourceLocation(string filename) is doing behind the scenes:
    //it starts by doing some possible cleaning of temp folder and some checking to make sure
    //the requested resource exists.
    //it gets or is given a resource stream (the proper way of accessing resources)
    //it gets all the bytes from the stream.
    //it saves all bytes into a file with the given filename that you are trying to access
    //it then returns the location of that temp file for you to use.
    //please note, that the file name doesnt matter, as long as the bytes in the file are exactly the same as the original resource file / embedded resource.
    //so basically it just copies the resource to a known location on disk and returns the location.

    class ResourceHelper
    {
        private static bool HasBeenCleanedOnce = false;
        private static object LockHolder = new object();

        public static string temppath = "temp_path_on_disk";

        public static string GetResourceLocation(string filename)
        {
            return GetResourceLocation(filename, GetResourceStream(filename));
        }

        public static string GetResourceLocation(string filename, Stream resourcestream)
        {
            lock (LockHolder) //this safely protects resources so only one thread (that locks with the locker object) can access the resource at a time
            {
                string place = temppath + filename;

                Directory.CreateDirectory(temppath);

                //it will only clean once close to the start of every program start
                if (!HasBeenCleanedOnce)
                {
                    foreach (string file in Directory.GetFiles(temppath))
                        File.Delete(file);

                    HasBeenCleanedOnce = true;
                }

                if (!File.Exists(place))
                    File.WriteAllBytes(place, ReadStreamFully(resourcestream));

                return place;
            }
        }

        //gets a resource and returns a stream that can read it
        public static Stream GetResourceStream(string file)
        {
            string resourceName = "your_solution_name.Resources." + file;

            string[] resources = Assembly.GetExecutingAssembly().GetManifestResourceNames();

            if (!resources.Contains(resourceName))
            {
                MessageBox.Show("Resource '" + file + "' could not be found at '" + resourceName 
                    + "'. Did you add the resource and set the resource to be embedded?" 
                    + Environment.NewLine + Environment.NewLine + "This will likely break after clicking 'ok'", "ERROR");
            }

            return Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
        }

        //reads a stream fully and returns a byte[] array of the contents
        public static byte[] ReadStreamFully(Stream input)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                input.CopyTo(ms);
                return ms.ToArray();
            }
        }
    }
}