Как читать встроенный ресурсный текстовый файл
Как прочитать встроенный ресурс (текстовый файл), используя 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
Метод:
Добавьте следующие слова
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
Метод
Нет ничего сложнее проницательного, чтобы получить 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 вы можете напрямую встроить доступ к файловому ресурсу через вкладку "Ресурсы" свойств проекта (в данном примере "Аналитика").
Полученный файл затем может быть доступен как байтовый массив
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();
Я знаю, что это старая тема, но вот что у меня сработало:
- добавить текстовый файл к ресурсам проекта
- установите модификатор доступа public, как показано выше Andrew Hill
прочитайте текст так:
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) автоматически. Следующие шаги добавляют файл ресурсов в ваш проект:
- Щелкните правой кнопкой мыши узел проекта и выберите "Добавить / новый элемент", затем перейдите к "Файл ресурсов". В поле "Имя" выберите подходящее имя, например "Ресурсы", и нажмите кнопку "Добавить".
- Файл ресурсов Resources.resx добавляется к проекту и может отображаться как узел в обозревателе решений.
- Собственно создается два файла, есть еще автоматически сгенерированный C# класс Resources.Designer.cs. Не редактируйте его, он поддерживается VS. Файл содержит класс с именем
Resources
.
Теперь вы можете добавить в качестве ресурса текстовый файл, например xml-файл:
- Дважды щелкните Resources.resx. Выберите Добавить ресурс> Добавить существующий файл и прокрутите до файла, который хотите включить. Оставьте значение по умолчанию Internal для Access Modify.
- Значок представляет новый элемент ресурса. Если этот параметр выбран, на панели свойств отображаются его свойства. Для файлов xml в свойстве Кодировка выберите Unicode (UTF-8) - Кодовая страница 65001 вместо локальной кодовой страницы по умолчанию. Для других текстовых файлов выберите правильную кодировку этого файла, например кодовую страницу 1252.
- Для текстовых файлов, таких как файлы xml, класс
Resources
имеет свойство типаstring
названный в честь включенного файла. Если имя файла, например, RibbonManifest.xml, то свойство должно иметь имяRibbonManifest
. Вы найдете точное имя в кодовом файле Resources.Designer.cs. - Используйте свойство строки, как и любое другое свойство строки, например:
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;
- Щелкните приложение правой кнопкой мыши в проводнике решений> Ресурсы> Добавить файл.
- Щелкните по нему и на вкладке свойств установите для параметра "Тип файла" значение "Текст".
- В вашей программе просто сделайте
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);
}
}
Это было достигнуто благодаря методу объединения нескольких текстовых файлов и чтения их встроенных данных в одном расширенном текстовом поле. который был моим желаемым эффектом с этим образцом Кодекса.