Работа с файлами.
Для нас цифры это цифры. Типа написал ручкой на бумажке 500 и понятно что это 500. В случае записи в файл - тут не все так однозначно
![Улыбка :)](//www.emu-land.net/forum/Smileys/default/smiley.gif)
Там есть такое понятие как тип переменной - byte, word, long. В чем разница? Дело в размере, который будет занят подобным числом. Если нам надо записать число 13 - достаточно будет byte. А если 1300 - то байта уже не хватит. Понадобится word. А если нам надо записать какоенить 128 000 то даже word не хватит - и нужен будет long. Размеры сколько байт они занимают и какие у них лимиты чисел откуда и докуда - можно посмотреть в таблице. нас интересует верхняя часть, красным.
![](https://i123.fastpic.org/big/2024/0501/0a/b75120e8016d048495bfc847c49dae0a.png)
Тип переменной и её размер мы вроде как уяснили. Теперь обсудим отображение этих чисел для глаз. С точки зрения компьютера то нет никакой разницы, а вот нам - человекам - надо кое что уточнить... В основном их используется 3 типа:
обычные десятичные, как у нас, у людей: 8, 9, 10, 11, 12...
число в хексе, обычно так выглядит в хекс редакторе: 8, 9, A, B, C (чтобы уточнить, что это именно хекс, то обычно пишут значок бакса, и потом уже число $8, $9, $A, $B, $C... либо, если аллергия на валюту: 0х08, 0х09, 0х0A, 0x0B, 0x0C)
бинарный код, то есть нули и единички: 00001000, 00001001, 00001010, 00001011, 00001100 (чтобы уточнить что это в бинарном виде, то обычно пишут значок процента и потом уже число %00001000, %00001001, %00001010)
Но и это еще не все. Запись переменных word и long может быть двух видов. Big-Endian и Little-Endian. Иначе говоря один порядок правильный, второй перевернутый. Какой из них какой - черт его знает
![Улыбка :)](//www.emu-land.net/forum/Smileys/default/smiley.gif)
PB, зараза, может читать и писать только в перевернутом. А обычно в файлах рома порядок правильный. Типа для примера long:
в роме $12, $34, $56, $78
PB прочитает как $78, $56, $34, $12
Эту проблему с невозможностью писать в нужном для нас виде отметим, но пока отложим. Вернемся к ней попозже.
Теперь переходим к практике. Во вложении будет прикреплен тестовой файл. Для понимания процесса хорошо бы чтоб на компьютере был установлен WinHex - чтобы можно было проверять правильность работы нашей программы.
![](https://i123.fastpic.org/big/2024/0501/28/a1e52a046570048e82b7e9d45f75ce28.png)
Работа с файлом может происходить двумя способами:
открываем и работаем с файлом прямо на месте, то есть на жестком диске.
открываем, читаем в память, закрываем, работаем в памяти, если надо сохранить, переписываем файл из памяти на жесткий диск.
На первоначальном этапе думаю мы пойдем первым путем.
Нам понадобятся команды открытия и закрытия файлов, чтения, записи и прыжка в нужное место файла. Из скрина выше нам известен адрес, где лежит наша переменная $12345678 - $1C и мы знаем что она long. Значит нам надо открыть файл, прыгнуть на этот адрес $1C и прочитать. Вроде задача не сложная.
Enumeration
#File
EndEnumeration
If ReadFile(#File, "D:\SEGA\Forum\testfile.bin")
FileSeek(#File, $1C)
x = ReadLong(#File)
CloseFile(#File)
EndIf
Debug x ; как десятичное. не интересно.
Debug Hex(x, #PB_Long) ; в виде хекс. то что надо.
И нас ждет эпик фейл
![Улыбка :)](//www.emu-land.net/forum/Smileys/default/smiley.gif)
Так как число прочиталось в перевернутом виде. Вместо $12345678 мы видим $78563412.
Чтобы выкрутится - можно сделать так: читать не как long - то есть 4 байта за раз - ReadLong, а читать 4 раза по одному байту - ReadAsciiCharacter, и просто потом их сдвигать в нужное место. Звучит конечно страшно и не понятно, но тут можно особо не вникать, так как код все сделает. Я всегда так делаю: если код не понятный, но работает - просто принимаешь на веру и радуешься
![Улыбка :)](//www.emu-land.net/forum/Smileys/default/smiley.gif)
Enumeration
#File
EndEnumeration
If ReadFile(#File, "D:\SEGA\Forum\testfile.bin")
FileSeek(#File, $1C)
;x = ReadLong(#File) ; заккоментировали, и поэтому текст зеленый и не считается
x = ReadAsciiCharacter(#File)
x << 8
x + ReadAsciiCharacter(#File)
x << 8
x + ReadAsciiCharacter(#File)
x << 8
x + ReadAsciiCharacter(#File)
CloseFile(#File)
EndIf
Debug x ; как десятичное. не интересно.
Debug Hex(x, #PB_Long) ; в виде хекс. то что надо.
Что касается сдвига, а в данном случае x << 8 тут надо немного уточнить. 1 байт состоит из 8 битов. Эти самые биты можно увидеть отобразив число в бинарном виде. Например:
x = 120 ; это десятичный вид
Debug Bin(x)
покажет как %1111000 - бинарный, или биты (на самом деле %01111000 просто нолики в начале съедает.)
если мы это число "сдвигаем" << 8, то это означает добавляем нолики в конце.
было %01111000 стало %0111100000000000
типа 120 в хекс это: $78
$78 << 8 = $7800
то-же самое если мы сдвигаем в другую сторону. например было число $789A
$789A >> 8 = $78
С этим разобрались. Теперь усложним наш код и изменим ReadFile на OpenFile, так-же прочитаем из нужного места и перевернем наше число, и попытаемся его записать в другое нужное место.
Enumeration
#File
EndEnumeration
If OpenFile(#File, "D:\SEGA\Forum\testfile.bin")
FileSeek(#File, $1C)
;x = ReadLong(#File) ; заккоментировали, и поэтому текст зеленый и не считается
x = ReadAsciiCharacter(#File)
x << 8
x + ReadAsciiCharacter(#File)
x << 8
x + ReadAsciiCharacter(#File)
x << 8
x + ReadAsciiCharacter(#File)
FileSeek(#File, $3C)
WriteLong(#File, x)
CloseFile(#File)
EndIf
Запускаем, смотрим наш файл в хекс редакторе и видим, что там ошибка. Да, мы прыгнули в нужное место записи - $3C, но записывать надо было не стандартными методами PB - WriteLong - 4 байта за раз, а точно так-же разбив long на 4 байта по одной штуке и писать их по очереди. А то получается мы записали число задом наперед
Enumeration
#File
EndEnumeration
If OpenFile(#File, "D:\SEGA\Forum\testfile.bin")
FileSeek(#File, $1C)
;x = ReadLong(#File) ; заккоментировали, и поэтому текст зеленый и не считается
x = ReadAsciiCharacter(#File)
x << 8
x + ReadAsciiCharacter(#File)
x << 8
x + ReadAsciiCharacter(#File)
x << 8
x + ReadAsciiCharacter(#File)
FileSeek(#File, $3C)
;WriteLong(#File, x) ; выкидываем
y = x >> 24
WriteAsciiCharacter(#File, y)
y = x >> 16
WriteAsciiCharacter(#File, y)
y = x >> 8
WriteAsciiCharacter(#File, y)
WriteAsciiCharacter(#File, x)
CloseFile(#File)
EndIf
Здесь как раз используется сдвиг в другую сторону x >> 8. И глядя на код вы можете сказать:
- Но, позвольте! x >> 24 я согласен, что превратит $12345678 в $12, но ведь x >> 16 сделает не нужные нам $34, а $1234 - а это совершенно не правильно!
Хорошее замечание. Придется ответить:
- А тут все дело в команде записи - WriteAsciiCharacter - она записывает только 1 байт. Поэтому независимо от того, что в нашем числе сейчас сидит двухбайтовое $1234 - запишутся в файл только последние $34 - то что нам и надо.