00092. Работа с файлами ( форматированное чтение )
Работа с файлам и ( форматированное чтение )|В этом уроке мы вернёмся к файлам, а точнее будет записывать и считывать форматированный текст.|wmysterio|wmysterio||||Привет всем пользователям нашего сайта! Пришло время для очередного урока! Этот способ отличается от работы с ini-файлами по всем статьям, но прочтя этот урок вы многое узнаете и, надеюсь, будете активно использовать в своих скриптах.
Прежде всего нам нужно настроить наш Санник, так как именно настройка ( а точнее не полная настройка ) не давала мне писать скрипты изучаемым сегодня методом. Как оказалось, всё дело в рег истре букв, который компилятор использует по-умолчанию. Давайте откроем настройки и перейдём во вкладку "Форматирование" и обратим внимание на радио-кнопку "Регист букв":

Как видим, по-умолчанию у нас стоит ВЕРХНИЙ регист. Так, как режим открытия файла должен обязательно компилироваться в нижнем регистре, то меняет радиокнопку на Как есть ( нижний - тоже неплохой вариант, это уже наш вкус, но главное, что бы не стоял верхний регистр ). После этого нажимаем "ОК".
В отличии от ini-режима, в этом режиме нет никаких ключевых слов или секций. Как и Cleo - считывание происходит построчно. Существует 6 основных режимов открытия файла:
Таблица 1 | Text |
---|---|
Текстовый режим | |
Режим | Описание |
rt | Режим открытия файла для чтения. Файл должен существовать. |
wt | Режим создания пустого файла для записи. Если файл с таким именем уже существует его содержимое стирается, и файл рассматривается как новый пустой файл |
at | Дописать в файл. Операция добавления данных в конец файла. Файл создается, если он не существует. |
Бинарный режим | |
Режим | Описание |
rb | Режим открытия файла для чтения. Файл должен существовать. |
wb | Режим создания пустого файла для записи. Если файл с таким именем уже существует его содержимое стирается, и файл рассматривается как новый пустой файл |
ab | Дописать в файл. Операция добавления данных в конец файла. Файл создается, если он не существует. |
Рассмотрим опкод, для открытия файла:
0A9A: $hFILE = openfile "Cleo\config.txt" mode "rb" // IF and SET
Здесь:
$hFILE - хендл нашего файла
"Cleo\config.txt" - путь у нашему файлу относительно директории GTA SA
"rb" - режим открытия ( см. Таблица 1 )
Этот опокод является так же явлется условным, поэтому советую использовать его в блоке условий "if...jf". После того, так работа с файлом завершена, обязательно нужно закрыть его опкодом:
0A9B: closefile $hFILE
Обращаю Ваше внимание, что прежде чем открывать файл, нужно убедится в том, что он не открыт в каком-то другом приложении. Если в ini-файле мож но было динамически менять значения, то этим методом так не получится.
Так, так тема нашего урока "форматированное считывание и запись", то мы обязаны рассмотреть какие идентификаторы есть, которые пишутся в опкод в зависимости от типа принимаемых значений:
Та блица 2 | Text |
---|---|
Идентификатор | Описание |
%d | Идентификатор целого числа |
%f | Идентификатор дробного числа ( по-умолчанию число и остаток с шестью символами после запятой ) |
%s | Идентификатор строки |
%c | Идентификатор символа (номер символа) |
Здесь:
% - специальный идентификатор, который указывает компилятору какой тип данных нужно записывать или читать. Они стоят в том порядке, который мы задали в файле, или планируем записать.
d, f, c, s - собственно и есть типы
Давайте рассмотрим 2 опкода, которые позволяют осуществлять запись и чтение:
0AD9: write_formatted_text "Записать %d значений" in_file $hFILE 2
0ADA: 0@ = scan_file $hFile format "Считать %d" 1@
Опкод "0AD9" записует форматированный текст в файл "$hFILE". Будет записан текст, с таким содержимым: "Записать 2 значений". Как видите, в поле строки указываются только идентификаторы, а после опкода идёт перечисление всех значений. То есть, если мы хотим, что бы в файл записало стоку с содержимым "Бокал пива вмещает 0.5 литра" и хотим в скрипте задать объём пива, то наш скрипт приобретёт следующий вид:
0@ = 0.5
0AD9: write_formatted_text "Бокал пива вмещает %.1f литра" in_file $hFILE 0@
Таким образом мы сами задаём в переменную значение, а за тем размещаем в нужном нам месте текста. Но не нужно забывать, что не все числа нужно объявлять через идентификаторы. Можно обойтись и без них, если он не содержит нужной нам информации:
0@ = 1.25
0AD9: write_formatted_text "В 2 бокала пива вмещается %.2f литра" in_file $hFILE 0@
Соответственно в файл будет записан текст: "В 2 бокала пива вмещается 1.25 литра". То есть, если не задать параметр как идентификатор, то он воспринимается как символ. Давайте на этом же примере, напишем текст, с использованием 2-х параметров:
0@ = 1.25
1@ = 2
0AD9: write_formatted_text "В %d бокала пива вмещается %.2f литра" in_file $hFILE 1@ 0@
Думаю вы обратили внимание на "%.2f". Собственно для чего мы поставили это? Дело в том, что при такой установке в файл будет записываться только 2 символа после запятой. Если мы поставим "%.3f", то в файл будет записано 3 символа. Если этого не сделать ( напишем просто "%f" ), то число в файл запишет число "1.250000". Эти идентификаторы уже нужно ставить на своё усмотрение, но как минимум "%.1f". Иначе если дробное число не будет иметь остатка ( например, "1.0"), то во многих случаях в файл запишется просто "1", что вызывает проблемы при считывании. Данные выражения с точкой действуют только на дробные цисла!
Что касается записи строк, то здесь всё тоже самое. Указываем стринговую переменную и задаём ей значение. После этого записуем в файл:
1@v = "Привет"
0AD9: write_formatted_text "text %s" in_file $hFILE 1@v
Содержимое файла: "text Привет". Вот пример простейшего скрипта, который запишет в файл данные:
{$CLEO}
0000:
thread 'WRITE_TEXT'
:WRITE_TEXT
wait 0
if
file.Open(0@, "cleo\text.txt", "wt")
jf @WRITE_TEXT
1@ = 2
2@v = "пива"
3@ = 1.25
0AD9: write_formatted_text "в %d бакалах %s вмещается %.2f литра" in_file 0@ 1@ 2@v 3@
file.Close(0@)
0A93: end_custom_thread
Результат:
× **ВАЖНО:** Если файл имеет какие то записи, то при открытии его режимом "wt" или "wb" его содержимое теряется ( файл перезапишеться ).

Опкод "0ADA" осуществляет считывание файла и очень похож на запись, но здесь есть одно примечание, что содержимое строки файла должно точно совпадать с содержимым строки опкода! Если строка файла "Сейчас 16:21 часов", то содержимое строки опкода будет "Сейчас %d:%d часов" ( планируется считать 2 значения из фай ла ). Следовательно в конце опкода нужно дописать необходимые параметры:
0ADA: 0@ = scan_file $hFile format "Сейчас %d:%d часов" 1@ 2@
Таким образом в переменные "1@" и "2@" будут записаны числа, считанные из файла. В переменную "0@" запишется количество удачных преобразований. Если оно не совпадёт с параметрами файла, то выражение вернёт false и в переменные "1@" и "2@" нифига не запишется =) Это условный опкод, поэтому используйте его в условных конструкциях с "if". Старайтесь правильно указывать идентификаторы. Во многих случаях это и есть решение проблем.
Давайте напишем простой пример скрипта, который будет считывать цвета для автомобиля а за тем задавать их транспорту, в который мы сели:
{$CLEO}
0000:
thread 'READ_TEXT'
:READ_TEXT
wait 0
if
file.Open(0@, "cleo\text.txt", "rt")
jf @READ_TEXT
:READ_TEXT_1
wait 0
if
0ADA: 1@ = scan_file 0@ format "Color car: %d, %d" 2@ 3@
jf @READ_TEXT_1
file.Close(0@)
:READ_TEXT_2
wait 0
if
actor.Driving($PLAYER_ACTOR)
jf @READ_TEXT_2
03C0: 5@ = actor $PLAYER_ACTOR car
0229: set_car 5@ primary_color_to 2@ secondary_color_to 3@
0A93: end_custom_thread
В результате наш скрипт прекрасно перекрашивает наш транспорт на заданный в файле цвет.

В большинстве случаев файлы используют для хранения одинаковой по-структуре информации. Затем считывают весь файл и задают параметры для разных субъектов. К примеру, в файле в нас будет хранится информация о транспорте. Считая её мы создадим несколько машин в генераторе транспорта. Сначала рассмотрим опкод для определения количества параметров в строке:
014B: $CAR = init_parked_car_generator #RHINO color -1 -1 1 alarm 0 door_lock 0 0 10000 at 2435.302 -1671.848 12.8007 angle 90.0
Первый параметр будет у нас модель транспорта. Второй параметр пусть будет цена автомобиля. А следующие четыре: координаты спавна и угол поворота. Остальные пусть будут по-умолчанию. Что бы не терять ваше время, я создал файл с уже готовыми параметрами:
445 5000 2483.021 -1659.0421 12.94315 180.0
446 7000 2477.022 -1659.0422 12.9432 180.0
447 4000 2471.023 -1659.0423 12.9431 180.0
448 8000 2465.024 -1659.0424 12.94321 180.0
491 10000 2459.025 -1659.0425 12.94322 180.0
471 13000 2453.026 -1659.0426 12.94311 180.0
455 20000 2447.027 -1659.0427 12.94314 180.0
438 8000 2441.028 -1659.0428 12.94321 180.0
Дальше уже напишем скрипт:
{$CLEO}
0000:
thread 'READ_TEXT'
var
$CARS: array 8 of car
end
:READ_TEXT
wait 0
if
file.Open(0@, "cleo\text.txt", "rt")
jf @READ_TEXT
$INDEX = 0
while not file.EOF(0@)
if
0ADA: 1@ = scan_file 0@ format "%d %d %f %f %f %f" 2@ 3@ 4@ 5@ 6@ 7@ // IF AND SET
then
014B: $CARS[$INDEX] = init_parked_car_generator 2@ color -1 -1 1 alarm 0 door_lock 0 0 3@ at 4@ 5@ 6@ angle 7@
014C: set_parked_car_generator $CARS[$INDEX] cars_to_generate_to 101
$INDEX += 1
end
wait 0
end
file.Close(0@)
0A93: end_custom_thread
Так как в нас файл состоит из 8 строк, то и в массиве автомобилей тоже будет 8 машин. Дальше считывая файл мы подставляем считанные значения в опкод, тем самым создаём новый элемент генератора транспорта.
Думаю, Вы обратили внимание на опкод "0AD6: end_of_file 0@ reached" ( он же file.EOF(0@) ). Это проверка "Достигнут ли конец файла 0@?". Используя её мы узнаём когда прекращать чтение. В результате мы получили:

Если разобраться, то нет ничего сложного. Используйте файлы и в своих модах. В большинстве случаев, это существенно уменьшает время и код! =)|2411|1|0|52341360
png
500388
400310``\|59636185
png500
300400
240\|25511210`png`460`422`400`366
|39936709png
403301
400`298``||rabota_s_fajlami_formatirovannoe_schityvanie|1504425699Last modified 1yr ago