Подтвердить что ты не робот

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

У меня есть портативная библиотека, которую я использую для приложения Windows Phone. В той же самой Portable Library у меня есть несколько файлов содержимого (Build Action = Content).

Я создал класс DataReader в Portable Library, который должен вернуть мне поток в файл содержимого. Однако с приведенным ниже кодом я последовательно возвращаюсь null из GetManifestResourceStream. Что я делаю неправильно?

public class DataReader
{
    public static Stream GetStream(string code)
    {
        string path = string.Format("./data/code-{0}.dat", code);
        return Assembly.GetExecutingAssembly().GetManifestResourceStream(path);
    }
}
4b9b3361

Ответ 1

Ваш путь неправильный. Вы используете косые черты, но во вложенных именах ресурса манифеста косые черты были преобразованы в периоды во время сборки. Кроме того, в зависимости от ваших целевых платформ PCL вы даже не можете позвонить Assembly.GetExecutingAssembly().

Вот что вы можете сделать:

var assembly = typeof(AnyTypeInYourAssembly).GetTypeInfo().Assembly;

// Use this help aid to figure out what the actual manifest resource name is.
string[] resources = assembly.GetManifestResourceNames();

// Once you figure out the name, pass it in as the argument here.
Stream stream = assembly.GetManifestResourceStream("Some.Path.AndFileName.Ext");

Ответ 2

От http://social.msdn.microsoft.com/Forums/windowsapps/en-US/386eb3b2-e98e-4bbc-985f-fc143db6ee36/read-local-file-in-portable-library#386eb3b2-e98e-4bbc-985f-fc143db6ee36

Доступ к файлам не может осуществляться портативно между приложениями Windows Store и Windows Телефон 8 приложений. Вам нужно будет использовать специальный код платформы, чтобы открыть файл и получить поток. Затем вы можете передать поток в PCL.

Если вы создаете его с помощью действия сборки контента, XML не находится внутри DLL. Это в файловой системе, и нет способа получить ее изнутри PCL. Вот почему все ответы задают действие сборки Embedded Resource. Он помещает файл внутри MyPCL.DLL\Path\To\Content.xml.

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

Solution Explorer, Properties, and Windows Explorer

Поэтому мы можем просто разместить интерфейс для чтения файла в нашем PCL. При запуске нашего непереносимого кода мы вводим реализацию в PCL.

namespace TestPCLContent
{
    public interface IContentProvider
    {
        string LoadContent(string relativePath);
    }
}

namespace TestPCLContent
{
    public class TestPCLContent
    {
        private IContentProvider _ContentProvider;
        public IContentProvider ContentProvider
        {
            get
            {
                return _ContentProvider;
            }
            set
            {
                _ContentProvider = value;
            }
        }

        public string GetContent()
        {
            return _ContentProvider.LoadContent(@"Content\buildcontent.xml");
        }
    }
}

Теперь, когда PCL определен выше, мы можем создать реализацию интерфейса в непереносимом коде (ниже):

namespace WPFBuildContentTest
{
    class ContentProviderImplementation : IContentProvider
    {
        private static Assembly _CurrentAssembly;

        private Assembly CurrentAssembly
        {
            get
            {
                if (_CurrentAssembly == null)
                {
                    _CurrentAssembly = System.Reflection.Assembly.GetExecutingAssembly();
                }

                return _CurrentAssembly;
            }
        }

        public string LoadContent(string relativePath)
        {
            string localXMLUrl = Path.Combine(Path.GetDirectoryName(CurrentAssembly.GetName().CodeBase), relativePath);
            return File.ReadAllText(new Uri(localXMLUrl).LocalPath);
        }
    }
}

При запуске приложения мы добавляем реализацию и демонстрируем загрузочное содержимое.

namespace WPFBuildContentTest
{
    //App entrance point. In this case, a WPF Window
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            ContentProviderImplementation cpi = new ContentProviderImplementation();

            TestPCLContent.TestPCLContent tpc = new TestPCLContent.TestPCLContent();
            tpc.ContentProvider = cpi; //injection

            string content = tpc.GetContent(); //loading
        }
    }
}

EDIT: Я сохранил это строки вместо Streams для простоты.

Ответ 3

Добавьте свой файл в переносимый ресурс и установите действие сборки для Embedded Resource. Например, файлы GB.png, US.png в папке CountryFlags.

Добавьте функцию геттера с кодом, подобным этому (здесь это специфично для нашего изображения с земным флагом).

public class CountryFlags {
    public static Stream GetFlagStream(string countryIsoCode2ch)
    {
        var flagname = "Full.DLL.Name.CountryFlags.{0}.png";
        var rs = Assembly.GetExecutingAssembly().GetManifestResourceStream(
                   string.Format(flagname, countryIsoCode2ch));

        return rs;
    }
}

Здесь Full.DLL.Name является частью созданной переносной библиотеки, которая до расширения .dll. (Примечание: Anything.Resources.dll - это плохое имя для библиотеки, потому что оно игнорируется Visual Studio по крайней мере при генерации XAP и т.д., Вместо этого, например, Anything.PortableResource.dll будет работать).

Ответ 4

Просто ответьте на запрос на подачу. Во-первых, использование Build Action = Content фактически не влияет на сборку. Это свойство элемента проекта, которое может считывать другие инструменты. Например, построитель установки использует его, чтобы выяснить, что файл должен быть включен в программу установки и развернут на пользовательскую машину.

Использование Build Action = Embedded Resource, как указано в вышеприведенном вопросе, - это надзор над OP. Это фактически инструктирует MSBuild вставлять файл в качестве ресурса в манифест сборки, используя Assembly.GetManifestResourceStream() извлекает его во время выполнения.

Но из комментария к баунти довольно ясно, что вы тоже этого не хотите. Резерв должен просто скопировать файл на целевой компьютер. Где он будет сидеть терпеливо, пока вам это не понадобится. Примечательно, что это означает, что не каким-либо образом изменяет размер пакета, который пользователь загружает из Хранилища. Он занимает такое же пространство, будь то внутри сборки или отдельный файл в пакете.

Так поцарапайте это как способ продвижения вперед.

Это действительно имеет значение во время выполнения, вся сборка попадает в виртуальную память при загрузке. Таким образом, сборка с ресурсом займет больше места виртуальной памяти. Но слово "виртуальный" очень важно, он требует очень мало ресурсов телефона. Всего несколько байтов в таблицах отображения страниц для каждого 4096 байт в ресурсе. Вы не начинаете платить за виртуальную память, пока не получите доступ к ней. В этот момент операционная система телефона должна фактически превратить ее из виртуальной в физическую память. Или, другими словами, загрузите байты ресурса в ОЗУ. Это не отличается от загрузки файла, он также загружается в ОЗУ при его открытии.

Так поцарапайте это как способ продвижения вперед.

У нас заканчиваются веские причины, чтобы на самом деле это сделать, Microsoft, безусловно, выбрала метод по умолчанию для обработки ресурсов в качестве лучшей практики. Это. Но иногда вам приходится разворачивать контент как файл, просто потому, что он слишком велик. Тот, который нажимает 2 гигабайта или более, потребляя всю виртуальную память в 32-разрядной операционной системе, поэтому не может быть сопоставлен с VM. Программа просто не сможет запускаться. Это не та программа, на которой пользователь телефона будет очень рад.

Затем вам нужно сосредоточиться на фазе сборки упаковки решения, что является последним шагом при создании телефонного приложения. Тот, где все проекты в решении были скомпилированы, и создается один и тот же файл, который был загружен в Магазин и загружен пользователем.

И да, там проблема, MSBuild недостаточно умен, чтобы увидеть библиотеку PCL с использованием ресурса. Действие сборки = Содержимое должно быть достаточно хорошим, как и для установщика, но это не работает. Он будет обрабатывать только DLL, а не ресурс. Было сделано предположение, что вы вложите его, лучшее решение.

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

Ответ 5

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

Вот пример свойства автогенерации для ресурсов dat файлов

   internal static byte[] MyDatFile {
        get {
            object obj = ResourceManager.GetObject("MyDatFile", resourceCulture);
            return ((byte[])(obj));
        }

вы можете прочитать файл dat как

    System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding();
    var str = enc.GetString(Resource1.MyDatFile);

Ответ 6

var assembly = typeof(PegHelper).GetTypeInfo().Assembly;
using (var stream = assembly.GetManifestResourceStream("Parsers.Peg.SelfDef.xml"))
using (var reader = new StreamReader(stream))
{
    string xmlText = reader.ReadToEnd();
    return XDocument.Parse(xmlText);
}

Ответ 7

Прежде всего, извлеките свою сборку следующим образом (DataLoader является классом в вашей сборке PCL):

var assembly = typeof(DataLoader).GetTypeInfo().Assembly;

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

Затем вы можете получить свой ressource следующим образом:

string resourceNam= "to be filled";
var assembly = typeof(DataLoader).GetTypeInfo().Assembly;
var compressedStream = assembly.GetManifestResourceStream(resourceName));

Например, если у меня есть файл logo.png в папке "Активы/Логотипы" в сборке "TvShowTracker.Helpers", я буду использовать этот код:

string resourceNam= "TvShowTracker.Helpers.Assets.Logos.logo.png";
var assembly = typeof(DataLoader).GetTypeInfo().Assembly;
var compressedStream = assembly.GetManifestResourceStream(resourceName));

Счастливое кодирование:)

Ответ 8

Вам нужно использовать метод Application.GetResourceStream вместо использования потока GetManifestResource

Ссылка: http://msdn.microsoft.com/en-us/library/ms596994%28v=vs.95%29.aspx

var albumArtPlaceholder =  
    Application.GetResourceStream( 
        new Uri("Images/artwork.placeholder.png", UriKind.Relative));