Как читать встроенный ресурсный текстовый файл

Как прочитать встроенный ресурс (текстовый файл), используя 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();
}

24 ответа

Решение

Вы можете использовать Assembly.GetManifestResourceStream Метод:

  1. Добавьте следующие слова

    using System.IO;
    using System.Reflection;
    
  2. Установить свойство соответствующего файла:
    параметр Build Action со значением Embedded 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.GetManifestResourceNames Метод


Нет ничего сложнее проницательного, чтобы получить resourceName только из имени файла (путем передачи содержимого пространства имен):

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

Вы можете добавить файл в качестве ресурса, используя два отдельных метода.

Код C#, необходимый для доступа к файлу, отличается, в зависимости от метода, использованного для добавления файла.

Способ 1: добавить существующий файл, установить свойство Embedded Resource

Добавьте файл в свой проект, затем установите тип Embedded Resource,

ПРИМЕЧАНИЕ. Если вы добавите файл с помощью этого метода, вы можете использовать GetManifestResourceStream чтобы получить к нему доступ (см. ответ от @dtb).

Способ 2: Добавить файл в Resources.resx

Откройте Resources.resx файл, используйте раскрывающийся список, чтобы добавить файл, установите Access Modifier в public,

ПРИМЕЧАНИЕ. Если вы добавите файл с помощью этого метода, вы можете использовать Properties.Resources чтобы получить к нему доступ (см. ответ от @Night Walker).

Взгляните на эту страницу: http://support.microsoft.com/kb/319292

В основном вы используете 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!");
   }

В Visual Studio вы можете напрямую встроить доступ к файловому ресурсу через вкладку "Ресурсы" свойств проекта (в данном примере "Аналитика"). Снимок экрана Visual Studio - вкладка

Полученный файл затем может быть доступен как байтовый массив

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

Если вам это нужно в качестве потока, то (из /questions/47033740/kak-preobrazovat-struct-systembyte-byte-v-obekt-systemiostream-v-c/47033752#47033752)

Stream stream = new MemoryStream(jsonSecrets)

Когда вы добавили файл к ресурсам, вы должны выбрать его модификаторы доступа как общедоступные, чем сделать что-то вроде следующего.

byte[] clistAsByteArray = Properties.Resources.CLIST01;

CLIST01 - это имя внедренного файла.

На самом деле вы можете перейти к resources.Designer.cs и посмотреть, как называется геттер.

Добавив, например, Testfile.sql Меню проекта -> Свойства -> Ресурсы -> Добавить существующий файл

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

Я знаю, что это старая тема, но вот что у меня сработало:

  1. добавить текстовый файл к ресурсам проекта
  2. установите модификатор доступа public, как показано выше Andrew Hill
  3. прочитайте текст так:

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

Текст, который я добавил к ресурсам: "SomeText.txt"

Что-то, что я узнал только сейчас, - то, что вашему файлу не разрешено иметь "." (точка) в имени файла.

в имени файла нет ничего хорошего

Templates.plainEmailBodyTemplate-en.txt -> Работает!!!
Templates.plainEmailBodyTemplate.en.txt -> не работает через GetManifestResourceStream()

Вероятно, потому что структура запутывается по пространствам имен против имени файла...

Вы также можете использовать эту упрощенную версию ответа @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();
    }
}

Несмотря на все ваши возможности, я использую этот вспомогательный класс для чтения ресурсов из любой сборки и из любого пространства имен в общем виде.

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();
            }
        }
    }
}

Я знаю, что это старый, но я просто хотел указать на NETMF (.Net MicroFramework), вы можете легко сделать это:

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

Поскольку NETMF не имеет GetManifestResourceStream

Некоторые типы проектов VS .NET не создают файл.NET (.resx) автоматически. Следующие шаги добавляют файл ресурсов в ваш проект:

  1. Щелкните правой кнопкой мыши узел проекта и выберите "Добавить / новый элемент", затем перейдите к "Файл ресурсов". В поле "Имя" выберите подходящее имя, например "Ресурсы", и нажмите кнопку "Добавить".
  2. Файл ресурсов Resources.resx добавляется к проекту и может отображаться как узел в обозревателе решений.
  3. Собственно создается два файла, есть еще автоматически сгенерированный C# класс Resources.Designer.cs. Не редактируйте его, он поддерживается VS. Файл содержит класс с именемResources.

Теперь вы можете добавить в качестве ресурса текстовый файл, например xml-файл:

  1. Дважды щелкните Resources.resx. Выберите Добавить ресурс> Добавить существующий файл и прокрутите до файла, который хотите включить. Оставьте значение по умолчанию Internal для Access Modify.
  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 поскольку функция получения строкового свойства уже сделала это.

После прочтения всех решений, размещенных здесь. Вот как я это решил:

// 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 "";      
}

Я прочитал использование встроенного текстового файла ресурса:

    /// <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);
});

Это класс, который может оказаться очень удобным для чтения встроенных файлов ресурсов из текущего 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://stackru.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());
    }
}

Меня раздражало, что вы всегда должны включать пространство имен и папку в строку. Я хотел упростить доступ к встроенным ресурсам. Вот почему я написал этот маленький класс. Не стесняйтесь использовать и улучшать!

Использование:

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)));

}

Ответ довольно прост, просто сделайте это, если вы добавили файл непосредственно из resources.resx.

string textInResourceFile = fileNameSpace.Properties.Resources.fileName;

С этой строкой кода текст из файла непосредственно читается из файла и помещается в строковую переменную.

Как указывает SonarCloud, лучше сделать:

      public class Example
{
    public static void Main()
    { 
        // Compliant: type of the current class
        Assembly assembly = typeof(Example).Assembly; 
        Console.WriteLine("Assembly name: {0}", assem.FullName);

        // Non-compliant
        Assembly assembly = Assembly.GetExecutingAssembly();
        Console.WriteLine("Assembly name: {0}", assem.FullName);
    }
}
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;
    }
}

Я хотел читать встроенный ресурс как массив байтов (без какой-либо конкретной кодировки), и в итоге я использовал MemoryStream что делает это очень просто:

using var resStream = assembly.GetManifestResourceStream(GetType(), "file.txt");
var ms = new MemoryStream();
await resStream .CopyToAsync(ms);
var bytes = ms.ToArray();

Для всех, кому просто нужен текст жестко запрограммированного файла в winforms;

  1. Щелкните приложение правой кнопкой мыши в проводнике решений> Ресурсы> Добавить файл.
  2. Щелкните по нему и на вкладке свойств установите для параметра "Тип файла" значение "Текст".
  3. В вашей программе просто сделайте Resources.<name of resource>.toString(); прочитать файл.

Я бы не рекомендовал это как лучшую практику или что-то в этом роде, но он работает быстро и делает то, что нужно.

Большинство ответов здесь содержат базовое или полное пространство имен как константу или перебирают все ресурсы изGetManifestResourceNamesчтобы получить это. У меня есть гораздо более простое, но не идеальное решение:

      var ns = typeof(Form1).Namespace;
var filename = "MyFile.txt";
using (var s = Assembly.GetExecutingAssembly().GetManifestResourceStream($"{ns}.{filename}"))
using (var sr = new StreamReader(s))
{
    var text = sr.ReadToEnd();
}

// OR
var ns = this.GetType().Namespace;
var filename = "MyFile.txt";
using (var s = Assembly.GetExecutingAssembly().GetManifestResourceStream($"{ns}.{filename}"))
using (var sr = new StreamReader(s))
{
    var text = sr.ReadToEnd();
}

Конечно, файл должен быть помечен как «Встроенный ресурс».

Для пользователей, использующих 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"))

Прочитайте встроенный 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.
}

Создать Void для 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);
  }

}

Это было достигнуто благодаря методу объединения нескольких текстовых файлов и чтения их встроенных данных в одном расширенном текстовом поле. который был моим желаемым эффектом с этим образцом Кодекса.

Другие вопросы по тегам