Что нового

[Данные, строки] Корректная запись в середину файла, без замены уже хранящихся данных

Exhale

Darkness for eternity
Сообщения
11
Репутация
0
Прошу прощения за глупый вопрос, или если такая тема уже была (я лично не нашел), но как записать данные в середину файла, не заменяя уже хранящиеся там данные?

Пробовал так

Код:
#NoTrayIcon
$hFile=FileOpen("test.txt",1)
$sStr="5"
FileSetPos($hFile,3,0)
FileWrite($hFile,$sStr)
FileClose($hFile)
Exit


файл test.txt - представляет собой строку "123467890", и предполагалось, что скрипт должен вставлять недостающую цифру 5 в эту строку, но вместо этого он заменяет 4 (или другую цифру, в зависимости от оффсета). Я понимаю, что можно конечно взять записать в отдельный файл (или в массив или еще куда-либо) все что идет после позиции N, потом вписать нужные нам данные, а затем добавить то что мы "сохранили", но с моей точки зрения это как то... по извращенски, чтоли?... Не кошерно в общем. Особенно если учесть что работать планируется далеко не с такими безобидными файлами в одну строку, а с весьма здоровыми файлами, причем совершенно не обязательно текстовыми.

Может кто подскажет грамотное решение этой проблемы?
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Exhale,
Попробуйте по такой схеме для маленьких и больших файлов.
Код:
Global $sFileS = 'small.txt', $sFileB = 'big.txt', $sText, $sInsert = @CRLF & 'insert string' & @CRLF, $hFile, $hFileNew, _
		$iPosS = 543, $iPosB = 1234567, $sBefore, $sAfter, $iEnc, $iSize, $iMod, $iEnd, $iPart = 1024 * 1024, $iTime
		
;Без проверок на ошибки

;small.txt create
For $i = 1 To 1000
	$sText &= Chr(Random(192, 255, 1))
	If Not Mod($i, 100) Then $sText &= @CRLF
Next

$hFile = FileOpen(@ScriptDir & '\' & $sFileS, 2)
FileWrite($hFile, $sText)
FileClose($hFile)
$sText = ''

;insert into small.txt
$iTime = TimerInit()
$iEnc = FileGetEncoding($sFileS)
$hFile = FileOpen(@ScriptDir & '\' & $sFileS, $iEnc)
$sBefore = FileRead($hFile, $iPosS)
$sText = $sBefore & $sInsert
$sBefore = ''
$sAfter = FileRead($hFile)
FileClose($hFile)
$sText &= $sAfter
$sAfter = ''
$hFile = FileOpen(@ScriptDir & '\New_' & $sFileS, $iEnc + 2)
$iEnc = 0
FileWrite($hFile, $sText)
FileClose($hFile)
$sText = ''
ConsoleWrite('small: ' & TimerDiff($iTime) & @LF)

;big.txt create
$hFile = FileOpen(@ScriptDir & '\' & $sFileB, 1)
For $j = 1 To 10
	$sText = ''
	For $i = 1 To 1000000
		$sText &= Chr(Random(192, 255, 1))
		If Not Mod($i, 100) Then $sText &= @CRLF
	Next
	FileWrite($hFile, $sText)
Next
FileClose($hFile)

;insert into big.txt
If FileExists(@ScriptDir & '\New_' & $sFileB) Then FileDelete(@ScriptDir & '\New_' & $sFileB)
$iTime = TimerInit()
$iSize = FileGetSize(@ScriptDir & '\' & $sFileB)
$iEnc = FileGetEncoding($sFileS)
$hFile = FileOpen(@ScriptDir & '\' & $sFileB, $iEnc)
$hFileNew = FileOpen(@ScriptDir & '\New_' & $sFileB, $iEnc + 1)
If $iPosB > $iPart Then
	$iTmp = Int($iPosB / $iPart)
	$iMod = Mod($iPosB, $iPart)
	For $i = 1 To $iTmp
		$sText = FileRead($hFile, $iPart)
		FileWrite($hFileNew, $sText)
	Next
	$sText = FileRead($hFile, $iMod)
	FileWrite($hFileNew, $sText & $sInsert)
	While 1
		$sText = FileRead($hFile, $iPart)
		If @error Then ExitLoop
		FileWrite($hFileNew, $sText)
	WEnd
Else
	$sText = FileRead($hFile, $iPosB)
	$sText &= $sInsert
	FileWrite($hFileNew, $sText)
	While 1
		$sText = FileRead($hFile, $iPart)
		If @error Then ExitLoop
		FileWrite($hFileNew, $sText)
	WEnd
EndIf
FileClose($hFile)
FileClose($hFileNew)
ConsoleWrite('big: ' & TimerDiff($iTime) & @LF)
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
Exhale [?]
можно конечно взять записать в отдельный файл (или в массив или еще куда-либо) все что идет после позиции N, потом вписать нужные нам данные, а затем добавить то что мы "сохранили",
это самый оптимальный способ, и не такой уж и извращенный.
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
а так нельзя?
ТС вроде хотел в середину записать
Код:
#include <String.au3>
 $count_lines = StringLen(FileRead('1.txt'))
$middle = $count_lines / 2
$mid_fl = Floor($middle)
$string = FileRead('1.txt')
$string_new = _StringInsert($string,'5',$mid_fl)
$new_write = FileOpen('1.txt',2)
FileWrite($new_write,$string_new)
FileClose($new_write)
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
joiner
ну принципиально, это тоже самое, что автор описал в первом посте как "извращенный". но все же, я думаю, под серединой подразумевалось где то между началом и концом, а не ровно посередине :smile:
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
если быть точным, то автор как бы выдвинул два момента, которые противоречат друг другу. написал что нужно посередине, а потом указал на точное действие - нужно подставить пропущенное число..
в итоге вопрос - подставить текст можно в любом месте строки или там, где его по логике не хватает или ровно посередине?.
да, мой вариант вычисляет середину. можно подставлять случайное число, если все равно где..
но опять же, точно не понятно что нужно :smile:
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
joiner [?]
но опять же, точно не понятно что нужно
smiley.gif
предположу, что оффсет заранее известен. просто для данного конкретного вопроса, какой он именно роли не играет.
 
Автор
E

Exhale

Darkness for eternity
Сообщения
11
Репутация
0
[Данные, строки] Корректная запись в середину файла

Спасибо, всем за ответы.
Да, я действительно под "серединой" файла подразумевал не конкретно середину файла, а любое место между началом и концом файла.
Ну что же, если оптимальный, значит так тому и быть, просто мне лично кажется, что если к примеру надо перемещать под 200-300 метров данных ради того, чтобы вписать пару байт - это как-то не рационально. Поэтому я и сказал что вариант "извращенский".
Воспользуюсь пожалуй тем примером, который привел madmasles.
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
во всех случаях будет перемещение. или я сильно ошибся?
 
Верх