Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2015.09.10;
Скачать: CL | DM;

Вниз

Delphi 2005, проблема с TStream   Найти похожие ветки 

 
Джованни   (2014-02-11 21:22) [0]

Доброг овремени суток, уважаемые.
Возникла проблема с TStream, а именно - необходимо удалить кусок данных в произвольном месте потока.

Вот, как пытаюсь реализовать идею:

procedure ChangeString(Source: TStream; Position, Count, Length: Int64; Data: WideString);
var
 Buffer: array [0..BufMax] of byte;
 readfrom, writeto, red, APos, ASize : int64;
begin
try
 APos := Position;
 ASize := Source.Size;
while APos > 0 do
begin
 Source.Seek(Count, soFromCurrent);
 Source.WriteBuffer(Buffer[0], BufMax);
 Inc(APos);
 Source.Position := APos - Length;
 Source.Seek(Count, soFromCurrent);
 Source.ReadBuffer(Buffer[0], BufMax);
end;
finally
end;
end;

Объясню на пальцах:
есть массив байт:
000000
001110
000000

Необходимо от позиции третьей слева единицы скопировать байты в буфер (Но не во второй TMemoryStream).
Затем с позиции первой единицы слева начать запись иных байт (не из буфера).
Затем поставить позицию в файле в конец новых записанных байт и прочитать туда же данные из ранее записанного буфера.

Приведенный код кстати кажется пишет в буфер (во всяком случае, ошибок не возникало), но не справляется со своей задачей.

ВРоде и алгоритм есть, но реализовать никак не осилю.
Буду благодарен любой помощи и правкам моего "кода".


 
Rouse_ ©   (2014-02-11 21:33) [1]

Не нужно делать дубли веток, тем более с разными никами. (на будущее..)


 
Джованни   (2014-02-11 21:35) [2]

Rouse_ извините, просто браузер выдал ошибку из-за интернета и я подумал, что сообщение не опубликовалось, а проверить не сообразил.
Конечно учту это правило)


 
MBo ©   (2014-02-12 08:19) [3]

Я не понял, что нужно сделать. Объяснение на пальцах не согласуется с заявленной целью "удалить кусок данных"

Может, стоит показать на примере массива abcdefghijklmn и "иных байтов" 0123456


 
brother ©   (2014-02-12 08:23) [4]

> есть массив байт:
> 000000
> 001110
> 000000

это не байты...


 
Джованни   (2014-02-12 09:04) [5]

brother
Я в курсе. Я показал, как вижу, как должна выглядеть работа процедуры.

MBo
Не особо понял насчет массива букв и чисел, но может так будет доступенее:
Есть строка в файле "abcdefghijklmn". После буквы "с"(третья слева) надо вставить строчку "0123456". Но не просто записать, а так, чтобы не повредились данные, которые идут после буквы "с".
Иными словами надо как бы "раздвинуть" данные в файле или потоке с необходимой позиции и записать туда нужные данные, учитывая их размер(длину).

Например, чтобы впихнуть в начало(в идеале - в любое место бы) потока/файл данные длиной 10 байт, сначала надо "отодвинуть" на 10 байт от начала все данные в потоке/файле и только потом записать данные, имеющие размер 10 байт.

Знаю про потоки и TMemoryStream, но не хочется создавать еще один "левый поток" и копировать сначала в него, потом из него и т.д. Громоздко это.

Я думал реализовать это через запись в буфер данных после указанной позиции, затем вписать свои данные (ту же строку, например) и затем произвести чтение из буфера в этот же поток или файл(отталкиваясь от того, с чем изначально оперировали).

А на примере
000000
001110
000000

я просто попытался наглядно продемонстрировать как должен выглядеть процесс в идеале.


 
MBo ©   (2014-02-12 09:28) [6]

В общем случае создание нового файла/потока и копирование в него нужных частей и проще всего, и быстрее.


 
Inovet ©   (2014-02-12 14:09) [7]

> [6] MBo ©   (12.02.14 09:28)
> проще всего, и быстрее

И старый для бэкапа сгодиться.


 
Джованни   (2014-02-12 20:09) [8]

MBo
как быть в случае, если файл имеет размер около 1,5 ГБ?
Оперативки может банально не хватить.

Inovet
не понял, в каком смысле для бэкапа?


 
Inovet ©   (2014-02-12 20:49) [9]

> [8] Джованни   (12.02.14 20:09)
> Оперативки может банально не хватить

А, кроме как в оперативку грузануть, больше никак? Читай и пиши в другой одновременно.


 
Джованни   (2014-02-14 09:31) [10]

Хотелось бы вообще не использовать TEMP-файлы или TMemoryStream.
Говорю же - пробовал в буфер читать, но прога то виснет, то не читает вообще ничего.


 
RWolf ©   (2014-02-14 09:41) [11]

вставить данные в произвольном месте файла нельзя без перезаписи всего файла, так что только временный файл.


 
MBo ©   (2014-02-14 09:47) [12]

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

SetLength(Arr, Length(Arr) + AddSize);
Move(Arr[AddPos], Arr[AddPos + AddSize], Length(Arr) - AddSize - AddPos);
Move(NewSlice[0], Arr[AddPos], AddSize);


 
MBo ©   (2014-02-14 09:50) [13]

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


 
Джованни   (2014-02-14 21:56) [14]

MBo
У меня есть нетипизированный файл, который я создаю лично. То есть это не чужой ЕХЕ, не чужой МП3 или что-то в этом роде.
Я пытаюсь сделать небольшую программу для напоминания задач. Эдакая напоминалка для личного использования (каюсь, еще один велосипед, зато свой).
Суть в том, что данные в файле разнородны: сначала идет версия файла, дата последнего доступа, количество записей.
Каждый элемент (заметка) имеет следующую структуру:

 TNote = Packed Record
 cNoteSize: LongInt;                  
 cDateCreate: TDate;
 cNameSize: LongInt;
 cCommentSize: LongInt;
 cName: WideString;              
 cComment: WideString;

Тут я думаю все понятно.
В результате, приходится записывать данные поочередно. Не просто банальным

var Note: TNote;
...
Stream.WriteBuffer(Note, SizeOf(Note));

но сначала все фиксированные данные, затем только строки.

теперь к сути проблемы - всегда есть необходимость удаления заметки из моего файла. И вот никак не пойму, как это можно реализовать, не прибегая к TEMP-файлам или стороннему TMemoryStream.
По-моему, есть вариант с чтением данных с указанной позиции в некий буфер, и затем перемещение позиции и последующая запись данных из этого буфера. Грубо это можно охарактеризовать как наложение одной картинки на другую. В итоге мы будем видеть только одну картинку (не беря во внимание их содержание).

Я пытался сделать чтение в буфер и чтение из буфера, но как-то не пошло это дело. Алгоритм даже писал на бумажке, думал, может это поможет, но все-таки тяму не хватает осилить проблему.

Кстати, идея с дин. массивом вполне интересна, однако для решения данной проблемы она не подходит, ибо записи разного размера (длины)(((


 
Inovet ©   (2014-02-14 22:52) [15]

Ну так добавить ещё одно поле
Deleted : Boolean;
Что длина разная — плохо. Надо одинаковую, вместо строк хранить смещения, сами строки в специальных кусках файла, не входит — с указанием смещения на следующий. Т.е. тоже некая структура у этух кусков.

И вообще возьми СУБД и не парься.


 
Джованни   (2014-02-15 16:10) [16]

Зачем еще одно поле? Если сделаю функцию удаления, то я там буду указывать заранее известные параметры смещения. Флаг (Удалено) будет полезен только в случае не физического удаления, но удаления "ссылки" на данные в определенном секторе. Но такой подход плох тем, что я не смогу записать данные бОльшей длины, чем были в удаленном секторе. Например, если сектор содержал в себе 10 строк по 5 символов каждая, то я не смогу записать 11 строк по 5 символов каждая, я буду ограничен в редактировании, а это не есть хорошо.
СУБД слишком для такого маленького проекта. Была идея сохранять записи в разные файлы (Например, "Заметка_1.тхт", "Заметка_2.тхт" и т.д.), но захотелось попробовать все держать в одном файле.


 
Inovet ©   (2014-02-15 16:19) [17]

> [16] Джованни   (15.02.14 16:10)
> Но такой подход плох тем, что я не смогу записать данные
> бОльшей длины, чем были в удаленном секторе

Я тебе объяснил, как сделать, чтобы смог записать любой длинны. Только это же самое уже сделано в СУБД.

> [16] Джованни   (15.02.14 16:10)
> СУБД слишком для такого маленького проекта.

Ты ошибаешься. СУБД - они разные бывают, надо взять подходящую.


 
RWolf ©   (2014-02-15 16:27) [18]

SQLite или Firebird Embedded в самый раз.


 
Джованни   (2014-02-16 16:47) [19]

Ладно, всем спасибо, попытаюсь сделать чтение с массивами.
Теперь такой вопрос: как корректно сохранять\читать динамические массивы в файл?
Запись пытаюсь реализовать так:

try
MS := TMemoryStream.Create;
...
SetLength(TCC, 10);
...
for i:=Low(TCC) to High(TCC) do
begin
 MS.WriteBuffer(TCC[i], SizeOf(Category));
end;
...
finally
MS.Free;
end;


Чтение - то же самое, только

MS.ReadBuffer(TCC[i], SizeOf(Category));


Но если запись вроде проходит, чтение выдает не совсем то, что записывал.

З.Ы.

TCatControl = array of TCategory;
TCC: TCatControl;
Category: TCategory;
...
type
TCategory = Packed Record
cCatSize: LongInt;
cDateCreate: TDate;
cNameSize: LongInt;
cCommentSize: LongInt;
end;


Что может быть причиной неудач? или я не правильно записываю?


 
RWolf ©   (2014-02-16 17:42) [20]

if Length(TCC) <> 0 then
 MS.WriteBuffer(TCC[0], SizeOf(Category) * Length(TCC));


 
Джованни   (2014-02-16 17:44) [21]

RWolf
Не могли бы Вы,пожалуйста, пояснить немного данный код?


 
RWolf ©   (2014-02-16 17:47) [22]

[21]
это то же, что

> for i:=Low(TCC) to High(TCC) do begin
>  MS.WriteBuffer(TCC[i],
>  SizeOf(Category));
> end;


 
Джованни   (2014-02-16 17:56) [23]

RWolf
Помогло! Спасибо большое!



Страницы: 1 вся ветка

Текущий архив: 2015.09.10;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.089 c
15-1418938202
Юрий
2014-12-19 00:30
2015.09.10
С днем рождения ! 19 декабря 2014 пятница


15-1418506204
Юрий
2014-12-14 00:30
2015.09.10
С днем рождения ! 14 декабря 2014 воскресенье


15-1415633204
megavoid
2014-11-10 18:26
2015.09.10
Телефон на андроиде сам лазит в мобильную сеть


15-1412022602
Юрий
2014-09-30 00:30
2015.09.10
С днем рождения ! 30 сентября 2014 вторник


2-1392643424
Дмитрий СС
2014-02-17 17:23
2015.09.10
Редактор очень широких текстов.