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

561

Как прочитать встроенный ресурс (текстовый файл) с помощью StreamReader и вернуть его как строку? В моем текущем script используется форма и текстовое поле 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();
}
Теги:
streamreader
embedded-resource

15 ответов

968
Лучший ответ

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

  • Добавьте следующие данные

    using System.IO;
    using System.Reflection;
    
  • Установить свойство соответствующего файла:
    Параметр Build Action со значением Embedded Resource

  • Используйте следующий код

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.

  • 1
    Отлично, спасибо мужчина. У меня был второй вопрос, касающийся пути сохранения, как бы я указал его, чтобы он сохранил его на рабочем столе на любом компьютере, который, возможно, имел бы другую структуру каталогов?
  • 4
    @ Me.Close: посмотрите папку Environment.SpecialFolder чтобы получить папку на рабочем столе. Вы должны иметь в виду, что ресурс будет иметь пространство имен на основе его пути в проекте, поэтому его имя может быть не просто file1.txt .
Показать ещё 9 комментариев
114

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

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

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

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

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

Изображение 1036

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

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

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

Изображение 1037

  • 4
    Третий метод - добавить файл в проект, а затем установить «Копировать в выходной каталог» на «Истина». При компиляции файл копируется в выходной каталог, и вы можете прочитать файл обычным способом. Пример: в приложении WPF, когда вы хотите отобразить изображение.
  • 0
    поэтому установка действия по сборке для Resource не делает ничего, что позволяет считывать элемент как ресурс? Вы должны использовать EmbeddedResource или добавить в файл Resources.resx ?
Показать ещё 1 комментарий
80

Взгляните на эту страницу: 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!");
   }
  • 31
    +1 За включение namespace как части имени ресурса
  • 38
    var auxList= System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames(); Этот метод может быть очень полезен, когда вы хотите узнать точное имя ресурса. (Взято из вопроса stackoverflow.com/questions/27757/… )
65

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

После этого результирующий файл можно получить в виде байтового массива с помощью

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

Если вам нужно это как поток, то (из https://stackoverflow.com/questions/4736155/how-do-i-convert-byte-to-stream-in-c)

Stream stream = new MemoryStream(jsonSecrets)
  • 11
    Вы также можете использовать это с текстовым файлом, в этом случае у вас будет: string jsonSecrets = YourNameSpace.Properties.Resources.YourFileName;
26

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

byte[] clistAsByteArray = Properties.Resources.CLIST01;

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

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

  • 4
    Не могли бы вы объяснить это подробнее? Когда я щелкаю правой кнопкой мыши -> свойства файла в обозревателе решений, а затем устанавливаю Action для Incorporated ressource , у меня нет поля « Access Modifiers на панели свойств. Кроме того, у меня нет класса Propersites.Resources , я получаю The name 'Properties' does not exist in the current context ошибки при компиляции вашего кода.
  • 2
    Это будет работать, только если вы встраиваете файл в Resources.resx , см. Мой ответ о различных методах встраивания файлов в проект.
12

Я знаю, что это старый поток, но это то, что сработало для меня:

  • добавить текстовый файл в ресурсы проекта
  • установите общедоступный модификатор доступа, как показано выше Andrew Hill
  • прочитайте текст следующим образом:

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

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

7

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

Изображение 1039

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

Возможно, из-за того, что структура запуталась в пространствах имен vs filename...

  • 3
    Сожалею. Это не верно. Точки работают. (по крайней мере, это сработало для меня, NET4.5) Я не знаю, почему у вас была эта ошибка.
  • 0
    Да, они работают, но они действуют как разделитель каталогов. Templates.plainEmailBodyTemplate.en.txt будет искать ресурс "\ Templates \ plainEmailBodyTemplate \ en.txt"
Показать ещё 4 комментария
7

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

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

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

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

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();
            }
        }
    }
}
  • 0
    плюс один для капитана планеты: P
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

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

Применение:

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 (). Где (i => i.EndsWith (fileName)). FirstOrDefault (); Это не сработает, если вы поместите целые каталоги в сборку, но в остальном это всего лишь одна строка;)
  • 0
    @ Конечно, ты можешь это сделать. Как это соотносится с моим ответом? Вы хотите улучшить метод GetStream? И как вы справляетесь с неопределенностью тогда?
Показать ещё 5 комментариев
3

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

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

Так как NETMF не имеет GetManifestResourceStream

2

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

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

Чтение встроенного TXT файла в событии загрузки формы.

Динамически устанавливать переменные.

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

Вызов Try Catch.

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

}

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню