Ресурсные файлы что это

Обновлено: 05.07.2024

Каждое серьезное приложение с графическим пользовательским интерфейсом (и не только) использует файлы ресурсов. При этом у вас есть два варианта: либо подключать ресурсы по относительным путям файловой системы, либо поместить их прямо внутрь бинарного файла приложения или библиотеки. У каждого из этих подходов есть свои преимущества и недостатки.

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

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

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

Реклама

Создание файла с описанием ресурсов

Первым делом создайте файл с описанием тех ресурсов, которые собираетесь использовать. Он имеет следующий вид (назовем его res.qrc ):

В приведенном примере мы определили один префикс: /images . Его можно считать логическим каталогом ресурсов. Таких префиксов может быть сколько угодно. Например, если в вашем приложении есть звуковые эффекты, то вы можете добавить префикс /sounds . Для создания более глубокой иерархии используйте префиксы вида /some/long/prefix .

В тег <qresource> вложены определения файлов, относящихся к соответствующему префиксу. В примере включено единственное изображение logo.jpg , но вы можете указать столько файлов, сколько необходимо. Используйте относительные пути к файлам, беря в качестве каталога отсчета - тот, в котором находится qrc -файл.

Имеет смысл явным образом распределять ресурсы по подкаталогам в файловой системе проекта. Например, изображение logo.jpg поместите в images/ . Тогда запись приобретает вид:

В этом случае логический путь к файлу logo.jpg вновь имеет вид: /images/logo.jpg .

Для краткости можно использовать псевдонимы следующим образом:

Файл доступен по логическому пути /myprefix/logo.jpg .

Затем нужно привязать заполненный qrc -файл к проекту. Для этого добавьте в ваш pro -файл строку вида:

В примере выше qrc -файл расположен на одном уровне с pro -файлом. Если вы применяете более сложную схему размещения файлов, то воспользуйтесь относительным путем.

Обратите внимание, что в QtCreator предусмотрен довольно удобный GUI-интерфейс для работы с файлами ресурсов. Чтобы создать новый qrc -файл, щелкните в контекстном меню для нужного проекта на пункт Add New. . В появившемся диалоговом окне перейдите в группу Qt и выберите Qt Resource file . После успешного создания файла ресурсов в панели проекта вы увидите новую группу Resources , появившуюся рядом с Headers и Sources . Открыв qrc -файл вы попадете в редактор ресурсов, который вполне интуитивно позволяет выполнить те же самые действия, которые мы выполняли вручную.

Реклама

Использование ресурсов в приложении

Итак, qrc -файл готов и подключен к проекту. Осталось только воспользоваться преимуществами от его использования. И сделать это совсем не сложно:

Ключевым здесь является способ обращения к изображению (или любому другому файлу) из ресурсов. Путь строится следующим образом: сначала ставится двоеточие : , затем префикс /images , который мы сами выбрали, и наконец путь к файлу (или псевдоним) logo.jpg . В остальном все то же самое, что и при работе с обычными файлами, предназначенными только для чтения.

Заключение

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

Большинству создателей игр рано или поздно хочется упаковать сотни (а порой и тысячи) файлов, используемых игрой, в один (или несколько) компактных ресурсных файлов.

Если вдруг вы об этом не задумывались, то вот ссылка на тему.

Я сам занимаюсь этой темой уже достаточно давно и есть кое-какие наработки, но на данном этапе хочется расширить свой кругозор и узнать мнения других разработчиков. Интересуют такие вопросы:

1) Какое решение вы используете в своем проекте: самописное, zlib, что-либо иное?
2) Почему вы выбрали именно это решение?
3) Что вам нравится в вашем решении? Что не нравится, но лень переделывать? Чего вам не хватает, но опять таки лень дописывать?

Заранее благодарен за ответы.

Я вот прочитал "ссылку на тему" и хочу прокомментировать выпады автора на счет Valve.
Во первых, совершенно очевидно, что автор никогда в жизни не держал в руках коробку с лицензионной игрой от Valve и тем более никогда такую игру не устанавливал. Потому как лицензионная игра состоит не из 40000 тысяч файлов, а из нескольких огромных архивов *.gcf, объединяемых движком в виртуальную файловую систему. Но даже не это главное. Суть же в том, что даже пиратская версия, собранная из тех-же *.gcf, только распакованных (и файлов там действительно дофига) по скорости загрузки уровня ничем не уступает лицензионной версии, а может даже загружается быстрее. Так что профит от всей этой затеи разве что в простоте/скорости установки и, как видится мне, в оптимизации доступа к файлам в случае медленных носителей (т.е. например на приставках).

dw3105
> 1) Какое решение вы используете в своем проекте: самописное, zlib, что-либо
> иное?
zlib - это архивация, и никак не связана с виртуальной файловой системой. (разве что косвенно, если в в эту систему встроен архиватор)

странно ты вопрос ставишь - всякое решение зависит от поставленных задача, если пытаться сделать нечто сферически-универсальное в вакууме, то выйдет как минимум FAT32 =))

в приведенной статье не нашел примера с тестом производительности. кроме того что автор брызгает слюной и кричит что все вокруг идиоты ничего в его записях умного нету. в указанной статье наехал на VALVe, стоить перейти на следующую страницу ( снизу стрелка ) и тутже он обсерает Intel Nvidia Autodesk и другие крупные компании. Читать противно когда ничего не достигший человек обсерат успешные компании (как минимум это говорит о том, что сам он в жизни ничего не сделал нормального, а продуктами указанных компаний пользуется весь мир, их их имена знает каждый. ) жалко, что там нету комментариев к статьям, а тоб я пожелал автору захлебнуться в совем дерьме. (прошу прощения за столь резкие высказывания)

Зы а еще автор статьи - boostофил

и по теме - какая все-таки задача?
у меня например обновление программы происходит через интернет, довольно регулярно. делать один большой файл - это ИМХО глупость в таком случае. придется качать много данных из за какой-нибудь мелкой текстурки. либо писать сложноую навороченную виртуаьлную файловую систему, но тогда точно надо выяснить - есть ли от этого хоть какойто толк.

Kloun
> жалко, что там нету комментариев к статьям

Kloun
> странно ты вопрос ставишь - всякое решение зависит от поставленных задача, если
> пытаться сделать нечто сферически-универсальное в вакууме, то выйдет как
> минимум FAT32 =))
Вот я и хочу грамотно поставить задачу, для начала. Как FAT32/NTFS/. нет смысла делать, т.к. чтение физического файла осуществляется средствами системы, поэтому на долю разработчика виртуальной ФС остается реализация сравнительно малой части фич реальной ФС.

> Зы а еще автор статьи - boostофил
Звучит как оскорбление. Обычно такое отношение к boost'у характерно для приверженцев NIH.

> Звучит как оскорбление. Обычно такое отношение к boost'у характерно для
> приверженцев NIH.
Везде есть границы разумного. а он прямо бредит этим бустом.

dw3105
> Вот я и хочу грамотно поставить задачу, для начала
для начала тогда надо определиться "зачем". какие задачи\проблемы должна решать ВФС?

Много мелких файлов в игре - ето чревато неефективной загрузкой, из-за множества file open операций и в основном невозможностью все прочитать одним махом, прямо бинарнъм куском в память.
К обновлению по сети ето отношение не имеет, ибо ресурснъе файлъ маленькие и действительно лучше обновлять их цельно бинарнъм паком. Или группами паков, если уж ето так неефективно.
Объчно же люди обновляют не по 1-2 файлику, а прямо релизят патч, которъй или потом перегружает часть файлов оригинальной игръ юзая перегрузку файловой системъ движка, или делает разпаковку ресурсов игръ, подмена, пакует опять (WoW).

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

Kloun
> для начала тогда надо определиться "зачем". какие задачи\проблемы должна решать
> ВФС?
Любые (в пределах разумного) с которыми может столкнуться среднестатистический программист Петя, если пожелает хранить кучу файлов в одном ресурсном файле. При этом иметь максимально простой интерфейс и быть платформенно/языково-независимой.

BUzer
> А у нас из движка сейчас буст выпиливается нафиг, так как он сильно увеличивает
> время компиляции и размер бинарников.
. и заменяется на свои родные велосипеды?
> Знаю, автор тех статей порекомендовал-бы нам купить новые компы.
И был бы прав.

dw3105
> среднестатистический программист Петя
Он об паках вообще не должен знать, в принципе. Т.е. оптимизировать игру с точки зрения загрузки так или иначе будет не он.

dw3105
Не надо про буст холиварить, достаточно посмотреть на то, насколько он юзается в професиональнъй gamedev проектах - т.е. почти нисколько.

dw3105
> Если вдруг вы об этом не задумывались, то вот ссылка на тему.
По поводу статьи. КГ/АМ, хотя в некоторых моментах автор все-же прав. Но его стиль изложения. Я б во-первых, никогда не взял бы на работу человека с таким стилем мыслей, а во-вторых, очень хотел-бы глянуть на список реальных продуктов, выпущенных с его участием. Что-то мне подсказывает, что список-то невелик.

Теперь по сути:
dw3105
> 1) Какое решение вы используете в своем проекте: самописное, zlib, что-либо
> иное?
Юзаем самописный менеджер, который работает как с обычными файлами, так и с большими "компаундами" из файлов, причем интерфейсы, видимые снаружи, не требуют указания, где данные лежат - в файле или в компаунде. Внутри компаунда - примитивненькая файловая система - в начале - TOC, далее - просто сложены данные в непаковоном виде. Допускаются (для удобства) "фолдеры" внутри компаунда. Все достаточно просто и прозрачно.
dw3105
> 2) Почему вы выбрали именно это решение?
Основных резона было 2 - во-первых, доставать данные из одного здорового файла банально быстрее, нежели из сотни маленьких, т.к операции открытия/закрытия файлов далеко небесплатны, а в случае, если данные лежат на CD/DVD/BD, еще и сики медленные. Во-вторых - удобнее инсталлить продукт - проще скопировать 1 здоровый файл, нежели 100 маленьких. И опять-же, если инсталлиться с диска - быстрее. Кроме того, есть еще такое себе квази-параноидальный резон - в здоровом файле НЕМНОЖКО менее удобно колупаться, а значит, некоторое количество любопытствующих отсеется. Но это в наше время не суть, конечно, важно, потому что отдельно взятые файлы вряд-ли несут в себе какое-либо ноу хау, что б был смысл что-то специально прятать. Разве что текстуры. так не жалко, в принципе. =)
dw3105
> 3) Что вам нравится в вашем решении? Что не нравится, но лень переделывать?
> Чего вам не хватает, но опять таки лень дописывать?
Ну, у нас есть один момент - для компиляции компаунда нужно юзать самописную утилиту. Она, хоть и имеет более-менее вменяемый интерфейс, сплошь и рядом вызывает вопросы у художников. Хочется сделать все проще, но руки не доходят никак. =)
А чего не хватает. Плагина для FAR, что б работать с компаундами. Но до этого руки вряд-ли в ближайшее время дойдут

Все управляемые ресурсы, которые нужно редактировать, должны быть связанными ресурсами. Редакторы ресурсов Visual Studio не поддерживают редактирование внедренных ресурсов.

Термин файл ресурсов может ссылаться на несколько типов файлов, например:

файл описания ресурсов программы (RC);

файл шаблона ресурсов (RCT);

Отдельный ресурс, существующий как отдельный файл. Этот тип включает точечный рисунок, значок или файл курсора, на который ссылается RC-файл.

Файл заголовка, созданный средой разработки. Этот тип включает Resource.h , который называется из RC-файла.

Ресурсы, найденные в других типах файлов, таких как .exe, .dll и Res, называются ресурсами.

В проекте можно работать с файлами ресурсов и ресурсами . Можно также работать с теми, которые не являются частью текущего проекта или были созданы вне среды разработки Visual Studio. Например, администратор может сделать следующее:

Работать с вложенными и условно включенными файлами ресурсов.

Обновите существующие ресурсы или преобразуйте их в Visual C++.

Импортировать графические ресурсы в текущий файл ресурсов или экспортировать их из него.

Включать общие или доступные только для чтения идентификаторы (символы), которые нельзя изменить с помощью среды разработки.

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

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

Изменяемые ресурсы

Чтобы изменить содержащиеся в них ресурсы, можно открыть следующие типы файлов:

Имя файла Описание
.rc Файлы скриптов ресурсов
.rct Файлы шаблонов ресурсов
RES Файлы ресурсов
RESX Управляемые файлы ресурсов
EXE Исполняемые файлы
DLL Файлы библиотек динамической компоновки
.bmp, ICO, DIB, cur Точечные рисунки, значки, панели инструментов и файлы курсоров

при редактировании ресурсов среда Visual Studio работает с и влияет на следующие файлы:

Редакторы ресурсов не читают файлы RC или resource. h напрямую. Компилятор ресурсов компилирует их в APS файлы, используемые редакторами ресурсов. Этот файл представляет собой этап компиляции и содержит только символьные данные.

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

Если файл APS не синхронизирован с RC-файлом, RC-файл создается повторно. Например, при сохранении редактор ресурсов перезаписывает файл. RC и файл Resource. h. Любые изменения в ресурсах остаются включенными в RC-файл, но при перезаписании RC-файла комментарии всегда будут потеряны. Сведения о том, как сохранять комментарии, см. в разделе Включение ресурсов во время компиляции.

Ресурсы манифеста

В проектах классических приложений C++ Ресурсы манифеста представляют собой XML-файлы, описывающие зависимости, используемые приложением. например, в Visual Studio файл манифеста, созданный мастером MFC, определяет версию Windows общих библиотек управления, которые приложение должно использовать:

для приложения Windows XP или Windows Vista ресурс манифеста должен указывать самую последнюю версию Windows стандартных элементов управления для использования приложением. В приведенном выше примере используется версия 6.0.0.0 , которая поддерживает элемент управления Syslink.

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

чтобы просмотреть сведения о версии и типе, содержащиеся в ресурсе манифеста, откройте файл в средстве просмотра XML-файлов или Visual Studio текстовом редакторе. Если вы откроете ресурс манифеста из представления ресурсов, этот ресурс откроется в двоичном формате.

Открытие ресурса манифеста

откройте проект в Visual Studio и перейдите к обозреватель решений.

Разверните папку файлы ресурсов , а затем:

Чтобы открыть его в текстовом редакторе, дважды щелкните файл . manifest .

Чтобы открыть в другом редакторе, щелкните правой кнопкой мыши файл manifest и выберите команду Открыть с помощью. Укажите используемый редактор и нажмите кнопку Открыть.

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

Создание файлов ресурсов

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

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

Ниже показан пример создания простой таблицы строк:

Утилита Resgen.exe

Для создания из ***.txt файла ресурсов можно воспользоваться специальной утилитой генерации файлов ресурсов Resgen.exe. Например, ввод следующей команды:

приведет к созданию файла MyResources.resources. Сгенерированный этой утилитой файл ресурсов далее можно либо добавить в сборку как внешний файл, либо вставить в сборку DLL или ЕХЕ. Утилита Resgen также поддерживает возможность создания файлов ресурсов в формате XML с расширением .resX. Применяется она очень просто:

Выполнение этой команды приведет к созданию XML-файла ресурсов по имени MyResources.resX.

Утилита Resgen поддерживает строго типизированные ресурсы. Строго типизированный ресурс представляется в виде класса, который получает доступ к ресурсам. Для создания такого класса в утилите Resgen предусмотрена опция /str:

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

Класс ResourceWriter

Вместо использования для создания файлов ресурсов утилиты Resgen можно написать специальную, позволяющую это делать программу. Класс ResourceWriter из пространства имен System.Resources служит для создания бинарных файлов ресурсов, а класс ResXResourceWriter — для создания файлов ресурсов на базе XML. Оба эти класса поддерживают возможность добавления изображений и любых других сериализуемых объектов. В случае применения класса ResXResourceWriter потребуется сослаться на сборку System.Windows.Forms.

В следующем примере кода демонстрируется создание объекта ResXResourceWriter по имени rw в файле Demo.resx. После создания экземпляра с помощью метода AddResource() класса ResXResourceWriter можно приступать к добавлению набора ресурсов общим объемом до 2 Гбайт. Первый аргумент в AddResource() позволяет указывать имя ресурса, а второй — значение. Ресурс изображения можно добавлять за счет применения экземпляра класса Image. Чтобы можно было использовать класс Image, необходимо сослаться на сборку System.Drawing, а также добавить директиву using для открытия пространства имен System.Drawing.

Здесь объект Image создается за счет открытия файла logo.jpg, поэтому потребуется либо скопировать этот файл изображения в каталог исполняемой программы, либо указать полный путь к нему в аргументе метода ImageToFile(). Оператор using указывает, что ресурс изображения должен автоматически уничтожаться в конце блока using.

Далее в объект ResXResourceWriter добавляются простые строковые ресурсы. В конце метод Close() класса ResXResourceWriter автоматически вызывает ResXResourceWriter.Generate() для осуществления записи ресурсов в файл Demo.resx:

Запуск этой небольшой программы приведет к созданию файла ресурсов Demo.resx с изображением logo.jpg внутри.

Использование файлов ресурсов

Добавьте в этот проект созданный ранее файл ресурсов Demo.resx, открыв в окне Solution Explorer контекстное меню и выбрав в нем пункт Add --> Add Existing Item (Добавить --> Добавить существующий элемент). По умолчанию для свойства Build Action (Действие при компоновке) этого ресурса будет установлено значение Embedded Resource (Встраиваемый ресурс), указывающее, что этот ресурс должен встраиваться в выходную сборку.

Далее в параметрах проекта (за счет выбора Application --> Assembly information (Приложение --> Информация о сборке)) следует установить в качестве значения параметра Neutral Language (Нейтральный язык) основной язык:

Установка нейтрального языка

Изменение значения этого параметра приведет к добавлению в файл assemblyinfо.cs атрибута [NeutralResourceLanguageAttribute], как показано ниже:

Установка значения для данного атрибута улучшит производительность ResourceManager, поскольку позволит ему быстрее отыскивать ресурсы для en-US, а также использовать их в качестве варианта по умолчанию. В этом атрибуте можно также указать место размещения используемого по умолчанию ресурса за счет применения второго параметра в конструкторе. С помощью перечисления UltimateResourceFallbackLocation можно указать, что он должен размещаться в главной сборке (значение MainAssembly) или же в подчиненной (значение Satellite).

После компоновки проекта можно просмотреть сгенерированную сборку утилитой ildasm и увидеть в манифесте атрибут, .mresource. Атрибут .mresource объявляет имя для ресурса в сборке. Если .mresource объявлен public (как в данном примере), это означает, что ресурс может экспортироваться из сборки и использоваться в классах других сборок. Если же .mresource объявлен private, это значит, что ресурс экспортироваться не может и доступен только в пределах данной сборки.

Для получения доступа к встроенному ресурсу используется класс ResourceManager, который находится в пространстве имен System.Resources. Конструктору этого класса в качестве аргумента можно передать имя сборки, в которой содержатся ресурсы.

В рассматриваемом примере ресурсы встроены в исполняемую сборку, поэтому во втором аргументе конструктору должен быть передан результат выполнения метода Assembly.GetExecutingAssembly(). В первом аргументе передается корневое имя ресурсов, состоящее из названия пространства имен и имени файла ресурсов, но без расширения resources. Как было показано ранее, это имя можно отобразить с помощью утилиты ildasm и просто удалить из него расширение resources. Имя можно также получить и программно с применением метода GetManifestResourceNames() класса System.Reflection.Assembly:

Для создания строго типизированного ресурса в редакторе управляемых ресурсов (Managed Resources Editor) можно изменить значение параметра Access Modifier (Модификатор доступа) с No Code Generation (Не генерировать никакой код) на Public (Общедоступный) или Internal (Внутренний). В случае установки значения Public генерируемый класс снабжается модификатором доступа public и тогда к нему возможен доступ из других сборок. При установке значения Internal генерируемый класс получает модификатор доступа internal и доступ к нему может осуществляться только изнутри сборки, в которой он находится.

Пространство имен System.Resources

Давайте кратко пройдемся по всем классам, которые содержатся в пространстве имен System.Resources и позволяют работать с ресурсами.

Класс ResourceManager

Может использоваться для получения ресурсов, относящихся к текущей культуре, из сборок или файлов ресурсов. С помощью ResourceManager можно получать сразу целый набор ресурсов для определенной культуры в виде экземпляра ResourceSet.

Класс ResourceSet

Позволяет представлять набор ресурсов для определенной культуры. При создании экземпляр ResourceSet он производит перечисление по классу, реализуя интерфейс IResourceReader, и сохраняет все ресурсы в HashTable.

Интерфейс IResourceReader

Используется в ResourceSet для перечисления ресурсов. Класс ResourceReader реализует этот интерфейс.

Класс ResourceWriter

Применяется для создания файла ресурсов и реализует интерфейс IResourceWriter.

Классы ResXResourceSet, ResXResourceReader и ResXResourceWriter

Похожи на классы ResourceSet, ResourceReader и ResourceWriter, но служат для создания не бинарного файла ресурсов, а не XML-файла .resx. Вместо того чтобы встраивать ресурс в XML-файл, они позволяют добавлять на него ссылку с помощью ResXFileRef.

Пространство имен System.Resources.Tools

Содержит класс StronglyTypedResourceBuilder, который можно использовать для создания класса из ресурса.

Читайте также: