Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2015.09.10;
Скачать: [xml.tar.bz2];

Вниз

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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.52 MB
Время: 0.056 c
2-1392837011
alexdn
2014-02-19 23:10
2015.09.10
Узнать ip


15-1415447176
dmk
2014-11-08 14:46
2015.09.10
Про переменные


2-1392702611
Novicer
2014-02-18 09:50
2015.09.10
Как подружить Group by и Containing?


2-1394360821
Novicer
2014-03-09 14:27
2015.09.10
Ошибка Arithmetic exception, numeric overflow, or string truncati


15-1415987381
Rouse_
2014-11-14 20:49
2015.09.10
Пара слов о кэшировании данных при чтении и смартпойнтерах





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский