Анимация
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

Что нельзя сделать с неструктурированным файлом? Поскольку вставка и удаление байтов возможны лишь в конце файла, вы не сможете вставить или удалить записи, а также изменить их длину. Исключение составляет последняя запись, которая удаляется простым усечением файла до конца предыдущей записи. В остальных случаях приходится использовать временный файл или копию файла в памяти. Если вам приходится часто заниматься этим, вместо обычных файлов лучше подойдет база данных (см. главу 14 «Базы данных»).

Самый распространенный тип файлов - текстовые файлы, а самый распространенный тип операций с ними - построчное чтение и запись. Для чтения строк используется оператор о (или его внутренняя реализация, readline), а для записи - функция print. Эти способы также могут применяться для чтения или записи любых блоков с конкретным разделителем. Строка представляет собой запись с разделителем "\п".

При достижении конца файла оператор о возвращает undef или ошибку, поэтому его следует использовать в цикле следующего вида:

while (defined ($line = <OATAFILE>)) { chomp $line; Ssize = length Sline;

print SsizeXn"; # Вывести длину строки

>

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

while (<DATAFILE>) { chomp;

print length, "\n, # Вывести длину строки

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

©lines = <DATAFILE>;

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

Заслуживает внимания и другая специальная переменная - $/, разделитель входных записей. По умолчанию ей присваивается "\п", маркер конца строки. Ей можно присвоить любое желаемое значение - например, для чтения записей, разделяемых нуль-байтами. Для чтения целых абзацев следует присвоить $/ пустую строку, "". Это похоже на присваивание "\п\п", поскольку для разделения записей используются пустые строки, однако "" интерпретирует две и более смежных пустых строки как один разделитель, а "\п\п" в таких случаях возвращает пустые записи. Присвойте $/ неопределенное значение, чтобы прочитать остаток файла как одну скалярную величину;



undef $/;

$whole file = <FILE>; # Режим поглощения

Запуск Perl с флагом -О позволяет задать $/ из командной строки:

% perl -040 -е Sword = О; print "First word is Sword\n";

Цифры после -О определяют восьмеричное значение отдельного символа, который будет присвоен $/. Если задать недопустимое значение (например, -0777), Perl присваивает $/ неопределенное значение undef. Если задать -00, $/ присваивается " . Ограничение в один восьмеричный символ означает, что вы не сможете ирисвоить $/ многобайтовую строку - например, "%%\п" для чтения файлов программы fortune. Вместо этого следует воспользоваться блоком BEGIN:

% perl -ne BEGIN { S/=%%\n" > chomp, print if /Unix/i fortune.dat

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

print HANDLE "One", "two", "three, # Onetwothree" print "Baa baa black sheep \n , # Передается выходному манипулятору

# no умолчанию

Между манипулятором и выводимыми данными не должно быть запятых. Если поставить запятую, Perl выдает сообщение об ошибке "No comma allowed after filehandle ". По умолчанию для вывода используется манипулятор STDOUT. Для выбора другого манипулятора применяется функция select (см. главу 7 «Доступ к файлам»).

Во всех системах строки разделяются виртуальным разделителем "\п ", который называется переводом строки (newline). Не существует такого понятия, как символ перевода строки. Это всего лишь иллюзия, которая по общему сговору поддерживается операционной системой, драйверами устройств, библиотеками С и Perl. Иногда это приводит к изменению количества символов в прочитанных или записываемых строках. Подробности заговора изложены в рецепте 8.11.

Записи фиксированной длины читаются функцией read. Функция получает три аргумента: файловый манипулятор, скалярную переменную и количество читаемых байт. Возвращается количество прочитанных байт, а в случае ошибки - undef. Для записи используется функция print:

Srv = read(HANDLE, Sbuffer, 4096)

or die "Couldnt read from HANDLE $i\n;

# Srv - количество прочитанных байт,

# Sbuffer содержит прочитанные данные

Функция truncate изменяет длину файла, который задается с помощью маии-нулятора или по имени. Функция возвращает true, если усечение прошло успешно, и false в противном случае:

truncate(HANDLE, Slength)

or die "Couldnt truncate: S\n"; truncate("/tmp/$$. pid", Slength)

or die Couldnt truncate. $\n";



Для каждого файлового манипулятора отслеживается текущая позиция в файле. Операции чтения/записи выполняются именно в этой позиции, если при открытии не был указан флаг 0 APPEND (см рецепт 7.1). Чтобы узнать текущую позицию файлового манипулятора, воспользуйтесь функцией tell, а чтобы задать ее - функцией seek. Поскольку стандартная библиотека ввода/вывода стремится сохранить иллюзию того, что \п является разделителем строк, вы не сможете обеспечить переносимый вызов seek для смещений, вычисляемых посредством подсчета символов. Вместо этого seek следует вызывать только для смещений, возвращаемых tell:

$pos = tell(DATAFILE),

print I m $pos bytes from the start of DATAFILE \n ,

Функция seek получает три аргумента файловый манипулятор, новое смещение (в байтах) и число, определяющее интерпретацию смещения. Если оно равно О, смещение отсчитывается от начала файла (в соответствии со значениями, возвращаемыми tell); 1 - от текущей позиции (положительное число означает прямое перемещение в файле, а отрицательное - обратное); 2 - от конца файла.

seek(LOGFILE О, 2) or die Couldn t seek to the end $\n ,

seek(DATAFILE $pos, 0) or die Couldn t seek to $pos $i\n seek(OUT, -20, 1) or die Couldn t seek back 20 bytes $i\n ,

Bee сказанное выще относится к буферизованному вводу/выводу. Другими словами, операции о, print, read, seek и tell используют буферы для повыще-пия скорости. В Perl также предусмотрены небуферизованные операции ввода/ вывода: sysopen, sysread, syswrite, sysseek и close. Буферизация, sysopen и close рассматриваются в главе 7.

Функции sysread и syswrite отличаются от своих аналогов, о и print. Они получают одинаковые аргументы - файловый манипулятор; скалярную переменную, с которой выполняется чтение или запись; и количество читаемых или записываемых байт. Кроме того, они могут получать необязательный четвертый аргумент - смещение внутри скалярной переменной:

Swritten = syswrite(DATAFILE Smystring length($mystring)), die syswrite failed $i\n unless Swritten == length($mystring) Sread = sysread(INFILE, Sblock 256, 5) warn only read Sread bytes not 256 if 256 = Sread,

Функция syswrite посылает содержимое Smyst ring в DATAFILE. При вызове sysread из INFILE читаются 256 символов, сохраняемых с щестого символа в $Ь1оск, при этом первые пять символов остаются без изменений. И sysread и syswrite возвращают фактическое количество переданных байт; оно может не совпадать с тем, которое пытались передать вы. Например, файл содержал мень-ще данных, чем вы рассчитывали, и чтение получилось укороченным. Может быть, произошло переполнение носителя, на котором находился файл. А может быть, процесс был прерван на середине записи. Stdio заботится о заверщении записи в случае прерывания, но при вызовах sysread и syswrite этим придется заняться вам. Пример приведен в рецепте 9.3.



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