Что нового

Алгоритм действий над бинарным файлом

ynbIpb

Скриптер
Сообщения
399
Репутация
110
Помогите продумать алгоритм действий над необычным бинарным файлом, а точнее запись данных в него. Он содержит текстовые данные.
Структура файла такова:
Заголовок, размер, количество текстовых строк, и потом идут смещения этих строк по 4 байта и 4 байта ID строки, когда все смещения указаны начинаются текстовые строки одна за другой разделённые нулевым байтом (0x00, нультерминованная строка). _http://img829.imageshack.us/img829/2434/hexe.png
Так вот читать я эти строки умею, а вот Необходимо обратно записывать, учитывая, что строка может быть диннее чем была и соответственно все смещения последующих строк изменятся и их нужно пересчитывать и править в файле. Не представляю как проделать это с файлом если его полностью читать в память и работать как со строкой. По этому мне видится следующий алгоритм:
1. определяю оффсет заменяемой строки
2. Читаю бинарные данные, которые находяться после этой строки (не включая текущую строку) во временную переменную.
3. открываю файл для записи в бинарном виде и ставлю текущую позицию на этот офсет (FileSetPos )
4. пишу новую строку на выбранной позиции (при этом если строка длиннее она уже затирает последущие)
5. потом на той позиции, на которой остановился после записи новой строки пишу те данные, которые предварительно сохранил во временную переменную.
6. пересчитываю все оффсеты тех строк, которые шли после и поочерёдно правлю их выставляя позицию для записи (FileSetPos ) на те места, где эти оффсеты записаны.

Вот в общих чертах. Может кто предложит получше?
 

asdf8

Скриптер
Сообщения
564
Репутация
152
Если файл не слишком большой, то удобнее сделать "разбиралку" всего файла на данные.
А после обработки данных, все их в "собиралку", и далее в файл.
 
Автор
ynbIpb

ynbIpb

Скриптер
Сообщения
399
Репутация
110
ну по размеру файл не большой около 100 Кб, но строк там гдето в районе 2000.
Я думал над этим, но такой подход будет полезен при экспорте\импорте всего текста из файла. А при редактировании единичной строки думаю не стоит пересобирать весь файл, будут задержки во времени.
 

SyDr

Сидра
Сообщения
651
Репутация
158
Напиши точную структуру файла (сколько на что и где байт). Если никто не напишет до воскресенья - напишу я (уезжаю сейчас).
 
Автор
ynbIpb

ynbIpb

Скриптер
Сообщения
399
Репутация
110
Структура:
Заголовок:
{01 00 00 00} - 4 байта вероятно версия формата (редактировать НЕ нужно)
{XX XX XX XX} - 4 байта Размер последующего блока данных (равен полному размеру файла минус 8 байт) , чтобы получить правильное значение необходимо перевернуть последовательность байт, например было: 10ABCDEF будет: EFCDAB10 (редактировать нужно)
Блок данных:
{XX XX XX XX} - 4 байта Количество текстовых строк, которые содержит файл, чтобы получить правильное значение необходимо также перевернуть байты. (редактировать НЕ нужно)
{10 00 00 00} - 4 байта, предназначение неизвестно (редактировать НЕ нужно)
{00 00 00 00} - 4 байта, просто нули предназначение неизвестно (редактировать НЕ нужно)
{XX XX XX XX} - 4 байта, опять размер блока с данными, содержит теже данные, что и в первом случае: полный размер файла минус 8 байт (редактировать нужно)
{XX XX XX XX} - 4 байта, вероятно ID текстовой строки (редактировать НЕ нужно)
{XX XX XX XX} - 4 байта, смещение текстовой строки в этом файле, исключая заголовок. Чтоб получить правильное значение необходимо сначала перевенуть байты, потом прибавить к ним 8 (редактировать нужно)
{XX XX XX XX} - 4 байта, ID следующей строки (редактировать НЕ нужно)
{XX XX XX XX} - 4 байта, смещение следующей строки (редактировать нужно)
{XX XX XX XX} - 4 байта, ID третьей строки (редактировать НЕ нужно)
{XX XX XX XX} - 4 байта, смещение третьей строки (редактировать нужно)
И т.д. и т.п. N- количество раз, равное количеству строк.

Потом как только кончаются смещения и ID сразу начинаются строки в формате UTF-8 одна за другой с разделителем 0x00

Образец файла в аттаче
 
Автор
ynbIpb

ynbIpb

Скриптер
Сообщения
399
Репутация
110
Решил последовать совету asdf8 и читать сразу целиком, а потом формировать файл по новой. Читаю так:
Код:
#Include <Array.au3>
Global $sAllTextEng_bin = @ScriptDir & "\AllTextEng.bin"

$hAllTextEng_bin = FileOpen ($sAllTextEng_bin, 16); открываем для чтения в бинарном режиме
$bAllTextEng_bin = FileRead ($hAllTextEng_bin) ; читаем весь файл в память
FileClose ($hAllTextEng_bin); закрываем файл

$iStrNumber = _Rotate(BinaryMid ($bAllTextEng_bin, 9, 4)); читаем количество строк
$iStrNumber = Dec (HEX ($iStrNumber)); преобразуем в HEX и переводим в десятичную систему
Dim $aALLDataArray[$iStrNumber+1][3] ; объявляем массив для хранения всех необходимых данных: [0][0]=количество, [$i][0]=ID, [$i][1]=offset, [$i][2]=String, 
$aALLDataArray[0][0] = $iStrNumber ; в нулевую ячейку заносим количество элементов
$iStartPos = 25 ; начальная позиция, с которой начинаем читать данные
For $i = 1 To $aALLDataArray[0][0] ; крутим цикл столько раз, сколько должно быть элементов в массиве
	$aALLDataArray[$i][0] = BinaryMid ($bAllTextEng_bin, $iStartPos, 4); читаем ID строки
	$aALLDataArray[$i][1] = BinaryMid ($bAllTextEng_bin, $iStartPos + 4, 4); читаем Offset строки (в оригинальном виде)
	$iOffset = Dec (HEX (_Rotate($aALLDataArray[$i][1]))) + 8 + 1; переворачиваем смещение и переводим в десятичный вид, прибавляем 8 (размер заголовка) и 1 (отсчёт идёт с 1)
	$aALLDataArray[$i][2] = _GetBinString(BinaryMid ($bAllTextEng_bin, $iOffset))
	$iStartPos += 8 ; каждый круг прибавляем по 8, чтоб читать следующий офсет
Next
_ArrayDisplay($aALLDataArray); отображаем содержимое массива

; ~~~~~~~функция переворачивания байтов ~~~~~~~
Func _Rotate($bBytesToRotate)
	If IsBinary ($bBytesToRotate) = 0 Then Return "" ; если переданные данные не являются бинарными, возвращаем из функции пустоту
	$iBytes = BinaryLen ($bBytesToRotate) ; определяем количество байт
	$bRotatedBytes = Binary ("") ; объявляем переменную, в которой будет перевёрнутое значение и указываем, что она для хранения бинарных данных
	For $i = $iBytes To 1 Step -1 ; крутим цикл от максимального значения до 1
		$bRotatedBytes &= BinaryMid ($bBytesToRotate, $i, 1); выбираем по 1 байту с конца и объединяем с содержимым объявленной переменной
	Next
	Return $bRotatedBytes ; возвращаем перевёрнутый результат из функции
EndFunc ;==>_Rotate

; ~~~~~~ функция получения бинарного фрагмента ~~~~~~~
Func _GetBinString($bBytesTextString)
	If IsBinary ($bBytesTextString) = 0 Then Return "" ; если переданные данные не являются бинарными, возвращаем из функции пустоту
	$iBytes = BinaryLen ($bBytesTextString) ; определяем количество байт
	$bTextString = Binary ("") ; объявляем переменную для будующей строки
	For $i = 1 To $iBytes ; крутим цикл столько раз сколько у нас байт или пока не встретим 0x00 (нультерминованная строка)
		$b = BinaryMid ($bBytesTextString, $i, 1) ; каждый круг читаем по одному байту сначала
		If $b = "0x00" Then ExitLoop ; если встретили нулевой байт, то выходим из цикла
		$bTextString &= $b
	Next
	;$bTextString = BinaryToString ($bTextString, 4) ; Преобразуем бинарные данные в текст, учитывая что данные в кодировке UTF-8
	Return $bTextString
EndFunc ;==>_GetBinString
 
Верх