如何读取嵌入式资源文本文件


693

如何使用读取嵌入式资源(文本文件)StreamReader并将其作为字符串返回?我当前的脚本使用Windows窗体和文本框,允许用户在未嵌入的文本文件中查找和替换文本。

private void button1_Click(object sender, EventArgs e)
{
    StringCollection strValuesToSearch = new StringCollection();
    strValuesToSearch.Add("Apple");
    string stringToReplace;
    stringToReplace = textBox1.Text;

    StreamReader FileReader = new StreamReader(@"C:\MyFile.txt");
    string FileContents;
    FileContents = FileReader.ReadToEnd();
    FileReader.Close();
    foreach (string s in strValuesToSearch)
    {
        if (FileContents.Contains(s))
            FileContents = FileContents.Replace(s, stringToReplace);
    }
    StreamWriter FileWriter = new StreamWriter(@"MyFile.txt");
    FileWriter.Write(FileContents);
    FileWriter.Close();
}

Answers:


1194

您可以使用Assembly.GetManifestResourceStream方法

  1. 添加以下用法

    using System.IO;
    using System.Reflection;
  2. 设置相关文件的属性:带值的
    参数Build ActionEmbedded Resource

  3. 使用以下代码

var assembly = Assembly.GetExecutingAssembly();
var resourceName = "MyCompany.MyProduct.MyFile.txt";

using (Stream stream = assembly.GetManifestResourceStream(resourceName))
using (StreamReader reader = new StreamReader(stream))
{
    string result = reader.ReadToEnd();
}

resourceName是嵌入在中的资源之一的名称assembly。例如,如果您将一个名为的文本文件嵌入"MyFile.txt"具有默认名称空间的项目的根目录中"MyCompany.MyProduct"resourceName则为"MyCompany.MyProduct.MyFile.txt"。您可以使用Assembly.GetManifestResourceNamesMethod获得程序集中所有资源的列表。


毫不费吹灰之力地resourceName只从文件名获取(通过传递名称空间的东西):

string resourceName = assembly.GetManifestResourceNames()
  .Single(str => str.EndsWith("YourFileName.txt"));

一个完整的例子:

public string ReadResource(string name)
{
    // Determine path
    var assembly = Assembly.GetExecutingAssembly();
    string resourcePath = name;
    // Format: "{Namespace}.{Folder}.{filename}.{Extension}"
    if (!name.StartsWith(nameof(SignificantDrawerCompiler)))
    {
        resourcePath = assembly.GetManifestResourceNames()
            .Single(str => str.EndsWith(name));
    }

    using (Stream stream = assembly.GetManifestResourceStream(resourcePath))
    using (StreamReader reader = new StreamReader(stream))
    {
        return reader.ReadToEnd();
    }
}

5
@ Me.Close:看一下Environment.SpecialFolder获取桌面文件夹。您需要记住,资源将根据其在项目中的路径进行命名空间,因此其名称可能不是just file1.txt
adrianbanks

15
@的自变量GetManifestResourceStream需要@adrian指示的路径。如果可以帮助任何人,则该路径类似于@SimpleCoder在示例中显示的内容:MyNamespace.Filename.Ext。我以前曾尝试过,MyNamespace.Resources.Filename.Ext但是结果为空。
耶尔顿2007年

61
如果您的资源不是直接位于项目根目录中,而是位于某些子文件夹中,请不要忘记将该文件夹名称也放入resourceName中(例如,“ MyProjectNameSpace.MyProjectSubFolder.FileName.FileExtention”)
Sasha 2013年

19
值得一提的是,必须将资源“构建操作”设置为“嵌入资源”
Illidan 2015年

7
此处未涵盖的重要一点。如果将文件另存为其他编码类型以应对奇数字符(在我的情况下为UTF8),则在读取流时可能会得到一个空文件。通过在流读取器的构造函数中指定编码类型来解决此问题:using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
Kinetic 2015年

139

您可以使用两种单独的方法将文件添加为资源。

访问文件所需的C#代码不同,这取决于首先添加文件所使用的方法。

方法1:添加现有文件,将属性设置为 Embedded Resource

将文件添加到您的项目,然后将类型设置为Embedded Resource

注意:如果使用此方法添加文件,则可以GetManifestResourceStream用来访问它(请参阅@dtb中的答案)。

在此处输入图片说明

方法2:将文件添加到 Resources.resx

打开Resources.resx文件,使用下拉框添加文件,设置Access Modifierpublic

注意:如果使用此方法添加文件,则可以Properties.Resources用来访问它(请参阅@Night Walker的回答)。

在此处输入图片说明


5
第三种方法是将文件添加到项目,然后将“复制到输出目录”设置为“真”。编译时,文件被复制到输出目录中,您可以使用常规方法读取文件。示例:要在WPF应用中显示图像。
康坦戈

因此,将构建操作设置为Resource不会使您将项目作为资源读出吗?您必须使用EmbeddedResource或添加到Resources.resx文件?
马斯洛

3
@Maslow将构建动作设置为“资源”会创建一个链接的资源,而将构建动作设置为“嵌入资源”会将该资源编译到输出程序集中。术语“链接资源”是“将文件在编译时复制到输出目录中”的幻想术语(然后您可以使用任何常规方法在运行时读取文件)。有关这两种类型之间的区别的更多信息,请参见msdn.microsoft.com/en-us/library/7k989cfy(v=vs.90).aspx上的“添加和编辑资源(Visual C#)” 。
Contango 2015年

如果你想用资源这种方式,而是动态的,而不是只是这个: Properties.Resources.Your_resource_name 这样写: Properties.Resources.ResourceManager.GetObject("Your_resource_name")
Lkor

86

基本上,您用于System.Reflection获取对当前程序集的引用。然后,您使用GetManifestResourceStream()

例如,在我发布的页面中:

注意:需要添加using System.Reflection;此功能才能正常工作

   Assembly _assembly;
   StreamReader _textStreamReader;

   try
   {
      _assembly = Assembly.GetExecutingAssembly();
      _textStreamReader = new StreamReader(_assembly.GetManifestResourceStream("MyNamespace.MyTextFile.txt"));
   }
   catch
   {
      MessageBox.Show("Error accessing resources!");
   }

32
+1对于namespace作为资源名称的一部分包括在内
Kirk Broadhurst,

41
var auxList= System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames(); 当您想了解确切的资源名称时,此方法可能非常有用。(摘自问题stackoverflow.com/questions/27757/…)–
奥斯卡·弗利

69

在Visual Studio中,您可以通过Project属性(在本示例中为“ Analytics”)的“资源”选项卡直接嵌入对文件资源的访问。 Visual Studio屏幕快照-“资源”选项卡

然后可以通过字节数组访问生成的文件

byte[] jsonSecrets = GoogleAnalyticsExtractor.Properties.Resources.client_secrets_reporter;

如果您需要将其作为流,那么(来自https://stackoverflow.com/a/4736185/432976

Stream stream = new MemoryStream(jsonSecrets)

11
您还可以将其与文本文件一起使用,在这种情况下,您将拥有:string jsonSecrets = YourNameSpace.Properties.Resources.YourFileName;
ouflak

30

将文件添加到资源时,应选择其访问修饰符作为公共属性,而不可以进行如下操作。

byte[] clistAsByteArray = Properties.Resources.CLIST01;

CLIST01是嵌入式文件的名称。

实际上,您可以转到resources.Designer.cs并查看getter的名称。


5
您能再解释一下吗?当我右键单击->解决方案资源管理器中文件的属性,然后将其设置Action为时Incorporated ressource,我Access Modifiers在属性面板中没有任何字段。另外,我没有一个Propersites.Resources类,The name 'Properties' does not exist in the current context编译您的代码时出现错误。
苏珊·杜彭(SuzanneDupéron)2013年

2
仅当您将文件嵌入时,这才起作用Resources.resx。有关将文件嵌入到项目中的不同方法,请参见我的回答。
Contango 2014年

13

添加例如Testfile.sql项目菜单->属性->资源->添加现有文件

    string queryFromResourceFile = Properties.Resources.Testfile.ToString();

在此处输入图片说明


2
它将返回byte [],对于文本文件,使用`Encoding.UTF8.GetString(Properties.Resources.Testfile)`
MikeTheCoder

12

我知道这是一个旧线程,但这对我有用:

  1. 将文本文件添加到项目资源
  2. 如上图所示,将访问修饰符设置为public
  3. 阅读这样的文字:

    textBox1 = new TextBox();
    textBox1.Text = Properties.Resources.SomeText;

我添加到资源中的文本:“ SomeText.txt”


8

您还可以使用@dtb答案的简化版本:

public string GetEmbeddedResource(string ns, string res)
{
    using (var reader = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream(string.Format("{0}.{1}", ns, res))))
    {
        return reader.ReadToEnd();
    }
}

你确定吗?根据此此链接,它看起来像我.... stackoverflow.com/questions/1065168/...
Timmerz

8

我刚刚了解到的是,您的文件不允许带有“。”。文件名中的(点)。

一个 ”。”  文件名中的内容不好。

Templates.plainEmailBodyTemplate-en.txt->有效!!!
Templates.plainEmailBodyTemplate.en.txt->无法通过GetManifestResourceStream()工作

可能是因为框架对名称空间和文件名感到困惑...


3
抱歉。错了 点工作。(至少它对我有用,NET4.5)我不知道为什么会有这个错误。
菲利克斯·基尔

是的,它们可以工作,但它们充当目录分隔符。Templates.plainEmailBodyTemplate.en.txt将查找“ \ Templates \ plainEmailBodyTemplate \ en.txt”资源
Peter Gfader 2015年

不,我尝试过。GetManifestResourceStream可以访问文件名中包含多个点的嵌入式资源。(NET4.5)
费利克斯·凯尔

1
我在.NET 4.5中遇到了同样的问题。名称中带有点的文件甚至都没有添加到资源集合中。assembly.GetManifestResourceNames()方法向我返回空列表。后来我发现问题仅在于语言代码。ca.abcd.sk.crt未添加到资源,而ca.abcd.crt被添加没有问题。
a.farkas2508

1
到2020年仍然正确。为此,我感到非常疯狂。
ZeRemz

8

通过您的全部力量,我使用此帮助程序类以通用方式从任何程序集和任何名称空间中读取资源。

public class ResourceReader
{
    public static IEnumerable<string> FindEmbededResources<TAssembly>(Func<string, bool> predicate)
    {
        if (predicate == null) throw new ArgumentNullException(nameof(predicate));

        return
            GetEmbededResourceNames<TAssembly>()
                .Where(predicate)
                .Select(name => ReadEmbededResource(typeof(TAssembly), name))
                .Where(x => !string.IsNullOrEmpty(x));
    }

    public static IEnumerable<string> GetEmbededResourceNames<TAssembly>()
    {
        var assembly = Assembly.GetAssembly(typeof(TAssembly));
        return assembly.GetManifestResourceNames();
    }

    public static string ReadEmbededResource<TAssembly, TNamespace>(string name)
    {
        if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));
        return ReadEmbededResource(typeof(TAssembly), typeof(TNamespace), name);
    }

    public static string ReadEmbededResource(Type assemblyType, Type namespaceType, string name)
    {
        if (assemblyType == null) throw new ArgumentNullException(nameof(assemblyType));
        if (namespaceType == null) throw new ArgumentNullException(nameof(namespaceType));
        if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));

        return ReadEmbededResource(assemblyType, $"{namespaceType.Namespace}.{name}");
    }

    public static string ReadEmbededResource(Type assemblyType, string name)
    {
        if (assemblyType == null) throw new ArgumentNullException(nameof(assemblyType));
        if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));

        var assembly = Assembly.GetAssembly(assemblyType);
        using (var resourceStream = assembly.GetManifestResourceStream(name))
        {
            if (resourceStream == null) return null;
            using (var streamReader = new StreamReader(resourceStream))
            {
                return streamReader.ReadToEnd();
            }
        }
    }
}

3
船长星球加一个:P
Alok

4

我阅读了嵌入式资源文本文件的用法:

    /// <summary>
    /// Converts to generic list a byte array
    /// </summary>
    /// <param name="content">byte array (embedded resource)</param>
    /// <returns>generic list of strings</returns>
    private List<string> GetLines(byte[] content)
    {
        string s = Encoding.Default.GetString(content, 0, content.Length - 1);
        return new List<string>(s.Split(new[] { Environment.NewLine }, StringSplitOptions.None));
    }

样品:

var template = GetLines(Properties.Resources.LasTemplate /* resource name */);

template.ForEach(ln =>
{
    Debug.WriteLine(ln);
});

3

我知道这很旧,但是我只想指出NETMF(.Net MicroFramework),您可以轻松地做到这一点:

string response = Resources.GetString(Resources.StringResources.MyFileName);

由于NETMF没有GetManifestResourceStream


3

阅读完所有解决方案后,请点击此处。这是我解决的方法:

// How to embedded a "Text file" inside of a C# project
//   and read it as a resource from c# code:
//
// (1) Add Text File to Project.  example: 'myfile.txt'
//
// (2) Change Text File Properties:
//      Build-action: EmbeddedResource
//      Logical-name: myfile.txt      
//          (note only 1 dot permitted in filename)
//
// (3) from c# get the string for the entire embedded file as follows:
//
//     string myfile = GetEmbeddedResourceFile("myfile.txt");

public static string GetEmbeddedResourceFile(string filename) {
    var a = System.Reflection.Assembly.GetExecutingAssembly();
    using (var s = a.GetManifestResourceStream(filename))
    using (var r = new System.IO.StreamReader(s))
    {
        string result = r.ReadToEnd();
        return result;
    }
    return "";      
}

3

答案很简单,如果直接从resources.resx添加文件,则只需执行此操作。

string textInResourceFile = fileNameSpace.Properties.Resources.fileName;

使用该行代码,可以直接从文件中读取文件中的文本并将其放入字符串变量中。


2

我很烦恼,您必须始终在字符串中包含名称空间和文件夹。我想简化对嵌入式资源的访问。这就是为什么我写了这个小班。随时使用和改进!

用法:

using(Stream stream = EmbeddedResources.ExecutingResources.GetStream("filename.txt"))
{
 //...
}

类:

public class EmbeddedResources
{
    private static readonly Lazy<EmbeddedResources> _callingResources = new Lazy<EmbeddedResources>(() => new EmbeddedResources(Assembly.GetCallingAssembly()));

    private static readonly Lazy<EmbeddedResources> _entryResources = new Lazy<EmbeddedResources>(() => new EmbeddedResources(Assembly.GetEntryAssembly()));

    private static readonly Lazy<EmbeddedResources> _executingResources = new Lazy<EmbeddedResources>(() => new EmbeddedResources(Assembly.GetExecutingAssembly()));

    private readonly Assembly _assembly;

    private readonly string[] _resources;

    public EmbeddedResources(Assembly assembly)
    {
        _assembly = assembly;
        _resources = assembly.GetManifestResourceNames();
    }

    public static EmbeddedResources CallingResources => _callingResources.Value;

    public static EmbeddedResources EntryResources => _entryResources.Value;

    public static EmbeddedResources ExecutingResources => _executingResources.Value;

    public Stream GetStream(string resName) => _assembly.GetManifestResourceStream(_resources.Single(s => s.Contains(resName)));

}

1
那么超级简单的解决方案呢:var resName = assembly.GetManifestResourceNames()。Where(i => i.EndsWith(fileName))。FirstOrDefault(); 如果将整个目录都放在汇编中,将无法正常工作,但否则只能是一行;)
哈里

@哈里确保您可以做到这一点。这与我的答案有何关系?您是否要改进GetStream方法?那你如何处理歧义呢?
菲利克斯·凯尔

1
@Estevez使用系统;使用System.IO; 使用System.Linq; 使用System.Reflection;
菲利克斯·基尔

2
由于某些原因,将类放置在另一个项目中后无法正常工作。调用和执行程序集均引用此类的程序集,而不是实际执行测试的程序集。没有静态和惰性初始化都很好。
Curly Brace

1
@CurlyBrace谢谢。懒惰的评估是此答案中的一个真正缺陷,因为调用和执行程序集会根据上下文而变化。在每次访问时都需要解决它们。
菲利克斯·基尔

2

某些VS .NET项目类型不会自动生成.NET(.resx)文件。以下步骤将资源文件添加到您的项目:

  1. 右键单击项目节点,然后选择“添加/新建项目”,滚动到“资源文件”。在名称框中,选择一个适当的名称,例如资源,然后单击按钮添加。
  2. 资源文件Resources.resx已添加到项目中,并且可以在解决方案资源管理器中视为节点。
  3. 实际上,创建了两个文件,还有一个自动生成的C#类Resources.Designer.cs。不要编辑它,它是由VS维护的。该文件包含名为的类Resources

现在,您可以将文本文件添加为资源,例如xml文件:

  1. 双击Resources.resx。选择添加资源>添加现有文件,然后滚动到要包含的文件。将默认值“内部”保留为“访问修改”。
  2. 图标代表新的资源项目。如果选中,属性窗格将显示其属性。对于xml文件,在“编码”属性下选择“ Unicode(UTF-8)–代码页65001”,而不是默认的本地代码页。对于其他文本文件,请选择此文件的正确编码,例如代码页1252。
  3. 对于xml文件之类的文本文件,该类Resources具有一个string以包含的文件命名的类型的属性。如果文件名为例如RibbonManifest.xml,则该属性应具有名称RibbonManifest。您可以在代码文件Resources.Designer.cs中找到确切的名称。
  4. 与其他任何字符串属性一样,使用字符串属性,例如:string xml = Resources.RibbonManifest。一般形式为ResourceFileName.IncludedTextFileName。不要使用,ResourceManager.GetString因为string属性的get-function已经做到了。

1
public class AssemblyTextFileReader
{
    private readonly Assembly _assembly;

    public AssemblyTextFileReader(Assembly assembly)
    {
        _assembly = assembly ?? throw new ArgumentNullException(nameof(assembly));
    }

    public async Task<string> ReadFileAsync(string fileName)
    {
        var resourceName = _assembly.GetManifestResourceName(fileName);

        using (var stream = _assembly.GetManifestResourceStream(resourceName))
        {
            using (var reader = new StreamReader(stream))
            {
                return await reader.ReadToEndAsync();
            }
        }
    }
}

public static class AssemblyExtensions
{
    public static string GetManifestResourceName(this Assembly assembly, string fileName)
    {
        string name = assembly.GetManifestResourceNames().SingleOrDefault(n => n.EndsWith(fileName, StringComparison.InvariantCultureIgnoreCase));

        if (string.IsNullOrEmpty(name))
        {
            throw new FileNotFoundException($"Embedded file '{fileName}' could not be found in assembly '{assembly.FullName}'.", fileName);
        }

        return name;
    }
}

0

这是一个类,您可能会发现从当前类读取嵌入式资源文件非常方便Assembly

using System.IO;
using System.Linq;
using System.Text;
using static System.IO.Path;
using static System.Reflection.Assembly;

public static class EmbeddedResourceUtils
{
    public static string ReadFromResourceFile(string endingFileName)
    {
        var assembly = GetExecutingAssembly();
        var manifestResourceNames = assembly.GetManifestResourceNames();

        foreach (var resourceName in manifestResourceNames)
        {
            var fileNameFromResourceName = _GetFileNameFromResourceName(resourceName);
            if (!fileNameFromResourceName.EndsWith(endingFileName))
            {
                continue;
            }

            using (var manifestResourceStream = assembly.GetManifestResourceStream(resourceName))
            {
                if (manifestResourceStream == null)
                {
                    continue;
                }

                using (var streamReader = new StreamReader(manifestResourceStream))
                {
                    return streamReader.ReadToEnd();
                }
            }
        }

        return null;
    }

    // https://stackoverflow.com/a/32176198/3764804
    private static string _GetFileNameFromResourceName(string resourceName)
    {
        var stringBuilder = new StringBuilder();
        var escapeDot = false;
        var haveExtension = false;

        for (var resourceNameIndex = resourceName.Length - 1;
            resourceNameIndex >= 0;
            resourceNameIndex--)
        {
            if (resourceName[resourceNameIndex] == '_')
            {
                escapeDot = true;
                continue;
            }

            if (resourceName[resourceNameIndex] == '.')
            {
                if (!escapeDot)
                {
                    if (haveExtension)
                    {
                        stringBuilder.Append('\\');
                        continue;
                    }

                    haveExtension = true;
                }
            }
            else
            {
                escapeDot = false;
            }

            stringBuilder.Append(resourceName[resourceNameIndex]);
        }

        var fileName = GetDirectoryName(stringBuilder.ToString());
        return fileName == null ? null : new string(fileName.Reverse().ToArray());
    }
}

0

对于所有很快想要Winforms中的硬编码文件文本的人;

  1. 在解决方案资源管理器>资源>添加文件中右键单击您的应用程序。
  2. 单击它,然后在属性选项卡中将“ FileType”设置为“ Text”。
  3. 在程序中只需Resources.<name of resource>.toString();读取文件即可。

我不建议将此作为最佳实践或其他任何方法,但是它可以快速运行并且可以完成所需的工作。


0

对于使用VB.Net的用户

Imports System.IO
Imports System.Reflection

Dim reader As StreamReader
Dim ass As Assembly = Assembly.GetExecutingAssembly()
Dim sFileName = "MyApplicationName.JavaScript.js" 
Dim reader = New StreamReader(ass.GetManifestResourceStream(sFileName))
Dim sScriptText = reader.ReadToEnd()
reader.Close()

MyApplicationName我的应用程序的名称空间在哪里。它不是程序集名称。此名称在项目的属性(“应用程序”选项卡)中定义。

如果找不到正确的资源名称,则可以使用GetManifestResourceNames()函数

Dim resourceName() As String = ass.GetManifestResourceNames()

要么

Dim sName As String 
    = ass.GetManifestResourceNames()
        .Single(Function(x) x.EndsWith("JavaScript.js"))

要么

Dim sNameList 
    = ass.GetManifestResourceNames()
        .Where(Function(x As String) x.EndsWith(".js"))

-1

阅读表单加载事件中的嵌入式TXT文件。

动态设置变量。

string f1 = "AppName.File1.Ext";
string f2 = "AppName.File2.Ext";
string f3 = "AppName.File3.Ext";

呼叫尝试接球。

try 
{
     IncludeText(f1,f2,f3); 
     /// Pass the Resources Dynamically 
     /// through the call stack.
}

catch (Exception Ex)
{
     MessageBox.Show(Ex.Message);  
     /// Error for if the Stream is Null.
}

为IncludeText()创建空对象,Visual Studio为您完成此操作。单击灯泡以自动生成代码块。

将以下内容放入生成的代码块中

资源1

var assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(file1))
using (StreamReader reader = new StreamReader(stream))
{
string result1 = reader.ReadToEnd();
richTextBox1.AppendText(result1 + Environment.NewLine + Environment.NewLine );
}

资源2

var assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(file2))
using (StreamReader reader = new StreamReader(stream))
{
string result2 = reader.ReadToEnd();
richTextBox1.AppendText(
result2 + Environment.NewLine + 
Environment.NewLine );
}

资源3

var assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(file3))

using (StreamReader reader = new StreamReader(stream))
{
    string result3 = reader.ReadToEnd();
    richTextBox1.AppendText(result3);
}

如果您希望将返回的变量发送到其他地方,只需调用另一个函数并...

using (StreamReader reader = new StreamReader(stream))
{
    string result3 = reader.ReadToEnd();
    ///richTextBox1.AppendText(result3);
    string extVar = result3;

    /// another try catch here.

   try {

   SendVariableToLocation(extVar)
   {
         //// Put Code Here.
   }

       }

  catch (Exception ex)
  {
    Messagebox.Show(ex.Message);
  }

}

这是通过一种在单个富文本框中组合多个txt文件并读取其嵌入数据的方法实现的。这是我对代码示例的预期效果。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.