Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 [ 99 ] 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

8.16. Чтение конфигурационных файлов

Проблема

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

Решение

Организуйте обработку файла в тривиальном формате ПЕРЕМЕННАЯ=ЗНАЧЕНИЕ, создавая для каждого параметра элемент хэша «ключ/значение»;

while (<C0NF1G>) {

chomp, # Убрать перевод строки

s/#.. , и Убрать комментарии

s/~\s+ ; # Убрать начальные пропуски

s/\s+$ ; и Убрать конечные пропуски

next unless length; # Что-нибудь осталось my ($var, Svalue) = split(/\s.=\s./, $ , 2); $User Preferences{$var) = Svalue;

Существует другой более изящный вариант - интерпретировать конфигурационный файл как полноценный код Perl;

do SENViHDME}/ progrc ,

Комментарий

в первом решении конфигурационный файл интерпретируется в тривиальном формате следующего вида (допускаются комментарии и пустые строки):

# Сеть класса С NETMASK = 255.255 255 О МТи = 296

DEVICE = cua1 RATE = 115200 MODE = adaptive

После этого можно легко получить значение нужных параметров - например, $User P references {"RATE"} дает значение 115200. Если вы хотите, чтобы конфигурационный файл непосредственно устанавливал значения переменных в программе вместо заполнения хэша, включите в программу следующий фрагмент:

по strict refs; SSvar = Svalue;

и переменная $RATE будет содержать значение 115200.

Во втором решении do организует непосредственное выполнение кода Perl. Если вместо блока используется выражение, do интерпретирует его как имя файла. Это практически идентично применению require, но без риска фатальных



8.16. Чтение конфигурационных файлов 315

исключений. В формате второго решения конфигурационный файл принимает следующий вид:

# Сеть класса С

SNETMASK = 255.255.255 О;

$МТи = 0x128;

$DEVICE = сиаГ,

$RATE = 115 200;

$M0DE = adaptive;

Если вам непонятно, зачем включать в файл лишние знаки препинания, задумайтесь - в вашем распоряжении оказывается весь синтаксис Perl. Теперь простые присваивания можно дополнить логикой и проверкой условий:

If (SDEVICE =- /1$/) {

SPATE = 28 800, } else {

$RATE = 115 200,

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

SAPPDFLT = "/usr/local/share/myprog ,

do "SAPPDFLT/sysconfig.pl, do "$ENV{HOME}/.myprogrc";

Если при существующем личном файле системный файл должен игнорироваться, проверьте возвращаемое значение do:

do SAPPDFLT/sysconfig. рГ or

do $ENV{HOME}/.myprogrc;

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

{ package Settings; do "$ENV{H0ME}/ myprogrc" }

Файл, прочитанный с помощью do (а также require и use), представляет собой отдельную, самостоятельную область действия. Это означает как то, что конфигурационный файл не может обратиться к лексическим (ту) переменным вызывающей стороны, так и то, что вызывающая сторона не сможет найти такие переменные, заданные в файле. Кроме того, пользовательский код не подчиняется директивам типа use strict или use integer, способным воздействовать на вызывающую сторону.



Если столь четкое разграничение видимости переменных нежелательно, вы можете заставить код конфигурационного файла выполняться в вашей лексической области действия. Имея под рукой программу cat или ее эквивалент, можно написать доморощенный аналог do:

eval cat $ENV{HOME}/.myprogrc;

Мы еще не видели, чтобы кто-нибудь (кроме Ларри) использовал такой подход в рабочем коде.

Во-первых, do проще вводится. Кроме того, do учитывает @INC, который обычно просматривается при отсутствии полностью указанного пути, но в отличие от require в do не выполняется неявная проверка ошибок. Следовательно, вам пе придется заворачивать do в eval для перехвата исключений, от которых ваша программа может скончаться, поскольку do уже работает как eval.

При желании можно организовать собственную проверку ошибок:

$file = "someprog.pi"; unless (Sreturn = do Sfile) {

warn "couldnt parse $file: $@" if $@;

warn "couldnt do $file: $!" unless defined Sreturn;

warn "couldnt run Sfile" unless Sreturn;

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

Однако не следует забывать о безопасности. Как убедиться в том, что фа11л не модифицировался никем, кроме пользователя? Традиционный подход - не делать ничего, полагаясь исключительно на права доступа каталогов и файлов. В девяти случаях из десяти такое решение оказывается правильпы.м, поскольку большинство проектов попросту не оправдывает подобной паранойи. А если все же оправдывает, загляните в следующий рецепт.

1> Смотри также--

Описание функций eval и require вperlfunc(l); рецепты 8.17; 10.12.

8.17. Проверка достоверности файла

Проблема

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

Решение

Получите данные о владельце и правах доступа с помощью функции stat. Можно воспользоваться встроенной версией, которая возвращает список:



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 [ 99 ] 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242