Каковы наилучшие методы хранения пользовательских предпочтений и настроек в приложениях Win32 Delphi?

Я хочу сохранить пользовательские настройки (цвета, включение / выключение панелей инструментов, ширину панели в пикселях) и настройки приложения (последние 10 файлов, каталог сохранения по умолчанию, открытый каталог по умолчанию) в моем приложении Delphi Win32. Как лучше всего это делать?


person Michael Riley - AKA Gunny    schedule 30.07.2011    source источник
comment
Реестр (хотя настройки не становятся большими двоичными объектами, конечно :)   -  person Premature Optimization    schedule 30.07.2011
comment
Реестр - отстой. Но файлы Ini в папке программных файлов тоже. Связанный вопрос с хорошей информацией: stackoverflow.com/questions/285277/   -  person Warren P    schedule 31.07.2011
comment
@warren, что плохого в реестре? Это одна из замечательных особенностей окон, которых нет в других системах. ИТ-администраторы большой корпорации любят реестр и ненавидят отсутствие чего-либо сопоставимого с Linux. ненавижу отсутствие чего-либо сопоставимого с Linux.   -  person David Heffernan    schedule 31.07.2011
comment
@warren - Вместо того, чтобы указывать на то, что отстой, и давать ссылки на статьи, в которых используются устаревшие методы Windows, как насчет того, чтобы рассказать нам, что вы делаете?   -  person Michael Riley - AKA Gunny    schedule 31.07.2011
comment
Я предпочитаю файлы INI в папке профиля пользователя. Я обнаружил, что приложения, использующие реестр, становится труднее поддерживать и понимать, труднее выполнять резервное копирование с сохранением состояния, труднее переносить на новый компьютер, оставаясь неповрежденным, труднее обновлять и труднее тестировать. Конфигурация приложения, основанная на чистой текстовой конфигурации (Ini или xml), превосходит ее в этой области, и отсутствие чего-либо вроде реестра на любой платформе, кроме Windows, на самом деле является самым большим недостатком реестра. Это неаккуратный windows-ism, который должен умереть.   -  person Warren P    schedule 01.08.2011


Ответы (5)


У вас есть два основных варианта:

  1. Сохраните настройки в файле под профилем пользователя. Если ваши настройки достаточно просты, то файлы INI работают нормально.
  2. Сохраните настройки в реестре под HKEY_CURRENT_USER, который также является частью профиля.

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

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

person David Heffernan    schedule 30.07.2011
comment
Лично я предпочитаю всегда писать портативное приложение и ничего не хранить в реестре. Delphi отлично подходит для создания приложений, не требующих настройки: копируйте и запускайте из любого места, где вы хотите ... Это, конечно, дело личного вкуса, но я видел, как обычно пользователи / клиенты думают об этой функции как о действительно приятной / отличительный. Что касается UAC и профиля, даже некоторые приложения теперь имеют тенденцию помещать исполняемый файл в пользовательские данные, например Гугл Хром. ;) - person Arnaud Bouchez; 30.07.2011
comment
@arnaud есть много разных вариантов, и разные решения лучше всего подходят для разных ситуаций. Мое приложение обычно работает в корпоративных настройках, поэтому реестр - хорошее решение. - person David Heffernan; 30.07.2011
comment
В дополнение к файлам INI вы также можете использовать формат JSON или XML, который может быть иерархическим, чтобы лучше отображать основную / подробную информацию или дерево предпочтений - я обнаружил, что предпочтения, организованные в виде дерева, могут иметь больше смысла, чем список . Список - это особый вид дерева, в то время как обратное неверно. Delphi 2010 обрабатывает как JSON, так и XML, и у вас есть множество сторонних библиотек. - person Arnaud Bouchez; 30.07.2011
comment
Насчет реестра - это дело вкуса и тоже зависит от ситуации. Мы оба согласны. - person Arnaud Bouchez; 30.07.2011
comment
@Arnaud: согласен. Программа, которая может быть установлена ​​с помощью простого XCOPY, должна быть предпочтительнее, ИМО. - Мне нравится Mac за это: на самом деле .app - это целый каталог в одном файле, и вы можете сразу его использовать. Все ресурсы - это просто файлы в каталоге. Вы можете писать в подкаталоги, как и в любой другой каталог файловой системы. Чтобы установить приложение, вы просто копируете его на свой жесткий диск, например в каталог приложений пользователя. - person Rudy Velthuis; 30.07.2011
comment
Иерархический, да. Непереносимый, скрытый и гигантский источник случайной сложности в Windows. Заставьте пользователей изменить вашу конфигурацию вашего приложения, и они могут вывести из строя свои системы. Реестр просто пухлый. Это то место, куда я бы положил вещи, если бы я был автором вредоносного ПО, пытающимся усложнить вам жизнь. - person Warren P; 26.05.2012

Как указывает @David, вы можете использовать реестр, файлы или, естественно, их комбинацию.

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

Например, моя программа AlgoSim может сохранять свои настройки в

C:\Users\Andreas Rejbrand\AppData\Roaming\Rejbrand\AlgoSim\2.0

папка. Это типичный пример. Вы получаете первую часть каталога, то есть

C:\Users\Andreas Rejbrand\AppData\Roaming

запросив у операционной системы папку с данными приложения для каждого пользователя. Вы можете использовать функцию SHGetKnownFolderPath, чтобы найти это . Используйте идентификатор папки FOLDERID_RoamingAppData. Если вам нужна поддержка более старых версий Windows, вы можете использовать SHGetFolderPath и используйте константу CSIDL_APPDATA.

Остальная часть пути обычно следует шаблону

Manufacturer Name\Product Name\Product Version

Какие файлы хранить? Что ж, самый простой способ - использовать устаревшие файлы INI, но вы также можете использовать XML, текстовые файлы в своем собственном формате или даже двоичные файлы собственной разработки.

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

HKEY_CURRENT_USER\Software\Rejbrand\AlgoSim\2.0

1 В этом случае операционная система достаточно умен, чтобы «эмулировать» папку Program Files для каждого пользователя. Хотя программа думает, что она читает и записывает в папку Program Files, на самом деле это чтение и запись в папку в части файловой системы текущего пользователя. Таким образом, старые и плохо работающие приложения продолжают работать даже в более новых версиях операционной системы Microsoft Windows, и, кроме того, они начинают поддерживать индивидуальные настройки для каждого пользователя, что им и следовало делать в первую очередь. Я действительно думаю, что это большой плюс для Microsoft, как я мог бы сказать раньше.

person Andreas Rejbrand    schedule 30.07.2011
comment
Почему вы так сосредоточены на данных приложений, не находящихся в роуминге? Настройки должны быть перемещены. - person Premature Optimization; 30.07.2011
comment
@Downvoter: Наверное, незнание. У меня нет опыта работы с корпоративными сетями и вычислениями. - person Andreas Rejbrand; 30.07.2011
comment
я не знаю, что именно вы там храните, но local app data относится к машинной части профиля пользователя, например: данные, которые могут быть воссозданы во время нормальной работы и не имеют смысла перемещаться с сетевым профилем. Что-то такое. - person Premature Optimization; 31.07.2011
comment
@Down ... - Что такое данные приложения без роуминга? - person Michael Riley - AKA Gunny; 31.07.2011
comment
@Andreas Если у вас нет веских причин для иного, вам следует сохранить настройки в перемещаемой части профиля пользователя. В противном случае настройки сотрудников hotdesking не будут следовать за ними от машины к машине. - person David Heffernan; 31.07.2011
comment
@Cape: возможно, огромные файлы кеша? - person Andreas Rejbrand; 31.07.2011
comment
@Cape Cod Gunny, вам следует задать отдельный вопрос, на данный момент мое самое сильное мнение - это реестр. Даже переносные извинения не убедят меня в обратном. ¿@Andreas Rejbrand, я думаю, что CSIDL достаточно, поскольку фактический путь зависит от хост-системы. - person Premature Optimization; 31.07.2011
comment
И спасибо вам обоим, Downvoter и @David, за то, что заставили меня узнать что-то новое. На самом деле, мне немного «стыдно», что я до сих пор не был «осведомлен о роуминге». Думаю, мне нужно немного переписать некоторые свои приложения ... - person Andreas Rejbrand; 31.07.2011

Файлы INI у меня всегда работают хорошо. Там TIniFile, так что вы можете легко читать / записывать файлы без особых усилий, вы можете назначать значения по умолчанию несуществующим значениям, а файл INI находится в удобочитаемом формате, чтобы пользователь мог посмотреть на него и отредактировать его, если он хочет.

Возможны и другие решения, такие как сохранение значений в реестре, но часто зависят от ОС и немного сложнее. Я бы использовал это, если пользователь не должен иметь возможность видеть / редактировать значения, но указанные вами настройки приложения не являются «секретом».

person schnaader    schedule 30.07.2011
comment
Когда вы используете ini-файлы или что-нибудь вне реестра, важно использовать правильную папку: папку, предпочтительно подпапку папки данных приложения, в профиле пользователя. Это важно, потому что таким образом вы будете совместимы с перемещаемыми профилями и UAC. - person Marjan Venema; 30.07.2011
comment
@Marjan UAC всегда вызывает беспокойство, вы совершенно правы. Некоторые программы даже стремятся установить исполняемый файл даже в папку данных, например, я заметил, что исполняемый файл Google Chrome находится в папке данных приложения, а не в папке программных файлов ... Я также сделал это для некоторых проектов, и с точки зрения клиента оно того стоило. Я знаю, что это нарушает дизайн UAC, но ИМХО этот дизайн был сломан с самого начала ... Что за троллинг! ;) - person Arnaud Bouchez; 30.07.2011
comment
Подход @arnaud chrome безнадежен в многопользовательской среде, потому что каждому пользователю нужна собственная установка. Вряд ли хорошая идея. - person David Heffernan; 30.07.2011

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

... и я предлагаю компонент, который помогает: библиотеку TrsStorage с сайта www.deepsoftware.ru. Помимо предоставления простых методов сохранения для широкого диапазона типов данных (включая как малые, так и большие типы данных - строки, целые числа, числа с плавающей запятой, потоки, буферы и т. Д.), У них есть компонент, который вы можете поместить в форму, который обращается к опубликованные свойства всех компонентов в форме ... вы просто отмечаете отдельные свойства, которые хотите сохранить. Нет, это работает не для всех - например, для вашего требования "последние 10 файлов". Но он должен работать для ваших цветов, включения / выключения панелей инструментов, ширины панелей, каталога сохранения по умолчанию, открытого каталога по умолчанию и т. Д.

TrsStorage также имеет множество ручных методов хранения и обхода данных. Я использовал их для реализации своего рода дерева наследования для настроек отчета, что упростило для «дочерних» отчетов хранение настроек, которые переопределяют настройки «предка», такие как шрифт и размер шрифта отчета по умолчанию. (Настройки имитируют иерархию объектов моих типов отчетов.) Вы можете вручную сохранить список «последних 10 файлов», используя один из этих вызовов ручного метода; Фактически, существуют процедуры ReadText / WriteText, которые должны работать для хранения / извлечения вашего списка «последних 10 файлов», если вы храните его в объекте TStrings.

TrsStorage читает / записывает из / в выбранный вами тип файла данных: .INI, .XML или собственный формат .BIN. Также доступны события для перехвата записи / чтения из файла и перенаправления потока в другое место: мы иногда используем это, например, для сохранения настроек каждой записи в поле BLOB таблицы базы данных.

Наконец, я не имею отношения к этим людям, но я успешно использовал их компоненты TrsStorage в течение многих лет.

person Mark Wilsdorf    schedule 30.07.2011

Если это приложение для базы данных (использует базу данных), сохраните и пользовательские настройки в базе данных. Я предпочитаю иметь большой двоичный объект в таблице пользователей, где я храню пользовательские предпочтения в формате файла INI. Основная причина (использование одного BLOB-объекта на пользователя) заключается в том, что использование правильной нормализации, скорее всего, замедлит запуск приложения. Одно небольшое предостережение: TIniFile VCL не поддерживает загрузку контента из TStream, вы придется использовать какой-то сторонний класс или использовать собственный, чтобы избежать временного сохранения данных на диске.

person ain    schedule 30.07.2011
comment
TMemIniFile может транслировать с помощью TStream, и это тоже лучше, чем TIniFile. - person David Heffernan; 30.07.2011
comment
@David AFAIK не напрямую, а через SetStrings ... поэтому вам нужно использовать tmp StringList для загрузки данных из потока. IOW это взлом :) - person ain; 30.07.2011
comment
Согласно n-уровневому шаблону, основная база данных, IMHO, не является лучшим местом для хранения предпочтений пользовательского интерфейса, списков последнего использования и т. Д. Локальный файл на пользовательском компьютере также может иметь смысл. О TIniFile (или TMemIniFile) не проблема скопировать временное содержимое BLOB в файл. - person Arnaud Bouchez; 30.07.2011
comment
Где бы вы хранили информацию о подключении к базе данных? В базе тоже !? :-) - person Warren P; 31.07.2011
comment
@Warren В моих программах есть строка подключения по умолчанию, встроенная в имя сервера БД, например myAppDBserver, где myApp - это, конечно, псевдоним приложения. Каждому клиенту просто нужно определить myAppDBServ в своем DNS, и он работает, нет необходимости настраивать каждый клиентский компьютер вручную. И, конечно же, каждая программа может принимать параметр командной строки, чтобы переопределить строку подключения по умолчанию, если это необходимо. - person ain; 31.07.2011
comment
Интересная идея. Несмотря на то, что вы можете перенаправить с помощью DNS или файла hosts в некоторых местах, в других местах, подобное жесткое кодирование может вызвать у вас проблемы. - person Warren P; 01.08.2011
comment
@Warren Вот здесь и вступает в игру параметр командной строки - создайте ярлык со строкой подключения в качестве параметра, и все готово. Эта система работает у меня много лет. Преимущество заключается в том, что на клиентской машине ничего не нужно / сохранять / настраивать, кроме ярлыка для exe (который сам может быть на сетевом диске, т.е. все пользователи используют его). - person ain; 01.08.2011
comment
Мне нравится идея параметра командной строки + база данных. Мне нравятся усилия, которые вы вложили в мобильность. - person Warren P; 02.08.2011