2012-06-09 2 views
18

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

В Portable Library я создал класс DataReader, который должен вернуть мне поток в файл содержимого. Однако с приведенным ниже кодом я постоянно возвращаюсь 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); 
    } 
} 

ответ

0

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

здесь образец автоматической генерации свойства для Dat файлов ресурсов

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

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

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

Я пытаюсь прочитать файл с наращиванием действий, установленных в содержание. – Martin

-1

Вы должны использовать метод 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)); 
+2

Статический класс приложения недоступен из библиотеки классов. – Martin

2

Добавьте свой файл в переносимый ресурс и установите действие сборки на Встраиваемый ресурс. Например, файлы 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 будет работать).

+0

'Assembly.GetExecutingAssembly()' недоступен в PCL (по крайней мере, при настройке на современные платформы). –

+0

@AndrewArnott вы уверены? Поддерживается PCL под 4.5: http://msdn.microsoft.com/en-us/library/system.reflection.assembly.getexecutingassembly%28v=vs.110%29.aspx Этот код также работает на .NET 4, 4.5 и Silverlight (через PCL). –

+0

Я предполагаю, что он недоступен, когда целевой Win8 + Net45 + WP80 –

2

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

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

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

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

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

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

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

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

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

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

+1

Думаю, я не уверен, что с этим ответом. Это может быть блестящая диссертация или вообще ничего, что мне нужно. Возможно, я мог бы сделать это проще - у меня есть приложение WP8, WinRT и PCL. В приложении есть множество видео, аудио, изображений и xml-файлов, которые необходимо периодически использовать приложениям RT/WP8. Около 700 МБ. Почему бы не поместить их в PCL? Я спрашиваю себя? Но будет ли DLL для PCL действительно теперь 700 МБ, если я их внедрю?Мне нужна эта DLL все время для других вещей. Что делать? Добавить как Build Action = Content сохраняет их из PCL до доступа. К сожалению, больше нет места для ввода ... –

+0

Проблема в том, что вы хотите, чтобы ваш PCL выполнял то, что не должно быть сделано PCL, доступ к файлам не переносится на разных платформах, поэтому, если вы помечаете свои файлы как Контент, вы нужно обращаться к ним как к любому другому файлу, обходным путем является их внедрение, но при этом раздувает вашу DLL и может свернуть любое приложение, использующее вашу dll, вот что Ганс пытается вам рассказать. – Rafael

8

От 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, Phone 8 приложений. Вам нужно будет использовать специальный код платформы, чтобы открыть файл и получить поток. Затем вы можете передать поток в PCL.

Если вы построили его с помощью действия по созданию контента, XML не находится внутри библиотеки DLL. Он находится в файловой системе, и нет возможности получить его изнутри PCL. Вот почему все ответы задают действие сборки Встраиваемый ресурс. Он помещает файл в 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 для простоты.

+0

Это интересно. Я знаком с такой инъекцией. Но вот проблема: мне не нужно ни приложение WinRT, ни WP8, чтобы вызвать PCL и получить ресурс. Мне нужен сам PCL для доступа к ресурсу «Build Action = Content», который находится внутри себя. Как только он его получит, он что-то сделает с ним (например, заполнить свойство в модели представления). –

+1

@ToddMain, я вроде как увлекся в примере, но это был всего лишь пример. PCL - это DLL. Это означает, что вы все равно вызываете его из нелегального кода. После того, как вы ввели реализацию интерфейса, PCL может внутренне загружать файлы и делать с ними все, что захочет. –

+0

@ToddMain, вы поняли это? –

31

Ваш путь неправильный. Вы используете косые черты, но во вложенных именах ресурса манифеста косые черты были преобразованы в периоды во время сборки. Также в зависимости от ваших целевых платформ 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"); 
+0

+1 для 'GetTypeInfo' –

+0

Это определенно работает, по-прежнему желаю, чтобы он содержал способ делать что-то, работая, хотя –

+0

Что такое AnyTypeInYourAssembly? Никто не объясняет, что это за вариант. Даже на документах Xamarin. – Dpedrinha

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

Объясните свой код. Просто поставить код недостаточно. –

+0

Что такое PegHelper? Никто не объясняет, что это за вариант. Даже на документах Xamarin. – Dpedrinha

0

Прежде всего, получить сборку, как это (DataLoader есть класс в сборке PCL):

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

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

Тогда вы можете получить ваши 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)); 

Дня кодирование :)

Смежные вопросы