Форум: "Прочее";
Текущий архив: 2010.11.07;
Скачать: [xml.tar.bz2];
ВнизНеясности в формате файла Найти похожие ветки
← →
Виталий © (2010-07-12 22:59) [160]Нет, я адекватно воспринимаю критику, просто немного растерялся. Теперь я собран и больше этого не повторится.
← →
Anatoly Podgoretsky © (2010-07-12 23:01) [161]> Sha (12.07.2010 22:38:27) [147]
Не так просто, тем более что Юрий побеспокоился, а ты еще и масла подлил.
Но на мой взгляд он выбрал неверное решение,ему следовало бы сначала решить
это с помощью файлов Паскаля (текстовых), а потом как домашнее задание с
помощью файловых потоков, а на закуску MMF
Ведь выбор оптимального решения входит в мастерство. В умение решать задачи
разными путями. Во взрастание специалиста.
← →
Anatoly Podgoretsky © (2010-07-12 23:02) [162]> Виталий (12.07.2010 22:42:30) [150]
Правильно, так и есть, только цели ты неверно определил.
В конце концов ты же сам напросился, ты в любой момент можешь отказаться.
← →
Виталий © (2010-07-12 23:03) [163]
> MMF
Я хотел бы, если на данный момент это не скачок, чтобы вы подсказали более подробную работу с ними, чем то, что описано в книгах. Или только MSDN?
← →
Виталий © (2010-07-12 23:04) [164]
> ты в любой момент можешь отказаться
я, может, и глупый, но упорный. Не откажусь.
← →
Anatoly Podgoretsky © (2010-07-12 23:05) [165]> Виталий (12.07.2010 22:43:31) [151]
Хочешь совет, прежде чем читать наши ответы, подготовься, приготовь закуску,
поставь графинчик водки, уютно расположишь в кресле и начинай читать. Как
только не понравилось, хлопни стопочку, глядишь к концу чтения, будешь
полностью согласен с нами и песни петь начнешь.
← →
Sha © (2010-07-12 23:06) [166]1. Проблема возникает из-за того, что ты сам решил писать в файл мусор. Нафига туда писать указатели, причем пустые?
2. Проблема возникнет при чтении, т.к. ты этот мусор еще зачем-то читаешь.
Если в момент установки длины строки ее указатель в записи будет содержать
непустое значение, то будет сделана попытка перераспределения памяти
и получено AV. Проблему лучше решать по месту возникновения, напримерpointer(test.FirstName):=nil;
перед установкой длины.
3. Ну и вообще в это поле удобно было бы писать длину строки.
← →
Anatoly Podgoretsky © (2010-07-12 23:06) [167]> Виталий (12.07.2010 22:53:35) [155]
Правильно говорит и ты это должен иметь в виду, но выбери приоритеты, разбей
задачу по этапам. Ведь ты же учишься и хочешь этого?
← →
Anatoly Podgoretsky © (2010-07-12 23:07) [168]> Виталий (12.07.2010 22:57:38) [158]
Не надо проверять ввод пользователя, пустое значение - нормальное значение,
надо писать так, что бы не возникало проблем (ошибок) из-за этого.
← →
Sha © (2010-07-12 23:10) [169]> Anatoly Podgoretsky © (12.07.10 23:01) [161]
> на закуску MMF
Страничная организация данных не предполагает обязательное использование MMF.
Например, MS SQL Server работает через порты завершения.
← →
Юрий Зотов © (2010-07-12 23:10) [170]> Виталий
1. Почему тип структуры объявлен внутри класса, да еще в секции private?
Впрочем, это к теме не относится.
Код, кстати, очень даже неплохой. Не без погрешностей, но вполне разумный. И идея в целом правильная - если данные имеют произвольную длину, то сначала пишем эту длину (блоком заведомо известного размера), а потом сами данные. Читаем соответственно.
2. Писать пустую структуру в файл - незачем (поэтому переменные s, s1, s2 - лишние, можно писать прямо из test^). Читать пустую структуру тоже незачем. То ли в статье что-то не так написано, то ли Вы что-то не так поняли.
3. Нет записи и чтения BirthDate. Дата (и любые другие данные фиксированной длины) пишется и читается так же, как и строки - только длина известна заранее: SizeOf(TDate), поэтому писать сначала длину незачем, можно писать сразу сами данные.
4. Не хватает двух блоков try-finally. Общая схема всегда такая:захват_ресурса;
try
работа_с_ресурсом;
finally
освобождение_ресурса;
end;
В данном случае мы дважды захватываем память - при создании стрима и структуры. Значит, должно быть так:
Stream := TFileStream.Create(...);
try
New(test);
try
...
finally
Dispose(test);
end;
finally
Stream.Free;
end;
==================
Ну и на закуску: вот работающий код. Сравните со своим - никаких принципиальных различий. Поэтому - кто сказал, что Ваш код плохой? Нормальный код, и не надо комплексовать, нет для этого причины.
procedure TForm1.btnSaveClick(Sender: TObject);
var
test: PFriend;
Stream: TFileStream;
len: integer;
begin
Stream := TFileStream.Create("D:\temp\test.dat", fmCreate);
try
New(test);
try
test^.FirstName := "Иван";
test^.LastName := "Петров";
test^.BirthDate := Now;
test^.Phone := "222-22-22";
len := Length(Test^.FirstName);
Stream.WriteBuffer(len, sizeof(len));
Stream.WriteBuffer(pChar(Test^.FirstName)^, len);
len := Length(test^.LastName);
Stream.WriteBuffer(len, sizeof(len));
Stream.WriteBuffer(pChar(test^.LastName)^, len);
Stream.WriteBuffer(Test^.BirthDate, SizeOf(TDate));
len := Length(Test^.Phone);
Stream.WriteBuffer(len, sizeof(len));
Stream.WriteBuffer(pChar(Test^.Phone)^, len);
finally
Dispose(test);
end;
finally
Stream.Free;
end
end;
procedure TForm1.btnLoadClick(Sender: TObject);
var
Stream: TFileStream;
test: PFriend;
len: Integer;
begin
Stream := TFileStream.Create("D:\temp\test.dat", fmOpenRead);
try
New(test);
try
Stream.ReadBuffer(len, sizeof(len));
SetLength(test^.FirstName, len);
Stream.ReadBuffer(pChar(test^.FirstName)^,Len);
Stream.ReadBuffer(len, sizeof(len));
SetLength(test^.LastName, len);
Stream.ReadBuffer(pChar(test^.LastName)^,Len);
Stream.ReadBuffer(test^.BirthDate, SizeOf(TDate));
Stream.ReadBuffer(len, sizeof(len));
SetLength(test^.Phone, len);
Stream.ReadBuffer(pChar(test^.Phone)^,Len);
ShowMessage(test^.FirstName+" "+test^.LastName+" "+DateToStr(test^.BirthDate)+" "+test.Phone);
finally
dispose(test);
end;
finally
Stream.Free;
end
end;
← →
Виталий © (2010-07-12 23:14) [171]
> Как
> только не понравилось, хлопни стопочку, глядишь к концу
> чтения, будешь
> полностью согласен с нами и песни петь начнешь.
Спасибо, не пью.
> Нафига туда писать указатели, причем пустые?
В этом случае, насколько я понимаю, я должен отказаться от удобства писать структуру целиком (скажем, у меня только 3 поля текстовые и 20 - других типов) и писать поле за полем?
А вот это, простите, не понял:
> Проблему лучше решать по месту возникновения, например
> pointer(test.FirstName):=nil; перед установкой длины.
Не будет там непустого значения, разве что кто-то намерено повредит файл записей. Но можно сделать и так, а при сохранении не обнулять - что изменится-то?
← →
Sha © (2010-07-12 23:17) [172]> Юрий Зотов © (12.07.10 23:10) [170]
> 3. Нет записи и чтения BirthDate.
Для этого он и пишет структуру целиком
← →
Юрий Зотов © (2010-07-12 23:18) [173]Да, я это уже позже понял. Кстати, тоже очень неплохая идея.
← →
Виталий © (2010-07-12 23:18) [174]
> Писать пустую структуру в файл
Именно хотел попробовать работу записи структуры сразу, а не по ее полям один за другим.
> Нет записи и чтения BirthDate
когда записывается вся структура, то это поле запишется вместе с ней (и потом считается), у меня по крайней мере вывелось значение
Ваш код прочел, понял, да, насчет try...finally не подумал, но это в принципе более-менее известная мне техника.
← →
Виталий © (2010-07-12 23:20) [175]
> Страничная организация данных не предполагает обязательное
> использование MMF.
> Например, MS SQL Server работает через порты завершения.
>
Уже знаю, вы меня сбиваете :) Я не знаю, что такое порты завершения, но если будет литература и необходимость - попробую осилить.
← →
Sha © (2010-07-12 23:23) [176]> В этом случае, насколько я понимаю, я должен отказаться от удобства писать структуру целиком
Нет. Просто пиши длину строки вместо указателя.
> Но можно сделать и так, а при сохранении не обнулять - что изменится-то?
Очень многое.
Это все равно, что в одной процедуре присвоить значение глобальной переменной,
а в другой его использовать. Если возможно, таких вещей надо избегать.
← →
Sha © (2010-07-12 23:24) [177]> Я не знаю, что такое порты завершения, но если будет литература и необходимость - попробую осилить.
Не надо тебе это. Seek вполне достаточно.
← →
Виталий © (2010-07-12 23:26) [178]
> Нет. Просто пиши длину строки вместо указателя.
Как вместо указателя на строку в структуру записать длину строки?
> Seek вполне достаточно.
а вот с проблемой добавить/удалить записи и их размером все сложнее..
← →
Anatoly Podgoretsky © (2010-07-12 23:27) [179]> Sha (12.07.2010 23:10:49) [169]
Вот в список неоложных дел пусть включит и порты завершения.
← →
Anatoly Podgoretsky © (2010-07-12 23:31) [180]> Виталий (12.07.2010 23:14:51) [171]
С нами придется, если хочешь нервы сохранить
← →
Anatoly Podgoretsky © (2010-07-12 23:31) [181]> Юрий Зотов (12.07.2010 23:10:50) [170]
Если убрать динамическое выделение памяти, то будет только лучше и одни tr
finally уйдет.
← →
Виталий © (2010-07-12 23:36) [182]
> С нами придется, если хочешь нервы сохранить
:)
А если серьезно - дайте совет, куда копать в сторону организации быстрого доступа к данным? Я думаю, это второй шаг.
← →
Sha © (2010-07-12 23:37) [183]> Как вместо указателя на строку в структуру записать длину строки?
Move(person, person2, size);
integer(person.FirstName):=Length(person.FirstName);
....
Move(person2, person, size);
FillChar(person2, size, 0);
> Вот в список неоложных дел пусть включит и порты завершения.
))
← →
Юрий Зотов © (2010-07-12 23:37) [184]> Виталий © (12.07.10 23:26) [178]
> Как вместо указателя на строку в структуру записать длину строки?
Либо приведением типа, либо вариантным объявлением записи:
type
PFriend = ^TFriend;
TFriend = record
case boolean of
True: (
FirstName: AnsiString;
LastName: AnsiString;
BirthDate: TDate;
Phone: AnsiString);
False: (
FirstLen: integer;
LastLen: integer;
Dummy: TDate;
PhoneLen: integer);
end;
← →
Sha © (2010-07-12 23:41) [185]> А если серьезно - дайте совет, куда копать в сторону организации быстрого доступа к данным?
А не надо было проскакивать типизированные файлы.
Мож чего бы на ум и пришло.
← →
Виталий © (2010-07-12 23:45) [186]
> Move(person, person2, size);
> integer(person.FirstName):=Length(person.FirstName);
> ....
> Move(person2, person, size);
> FillChar(person2, size, 0);
При сохранении, как я понимаю, копируем данные во временную запись и с приведением типов записываем длину.
При загрузке - копируем назад и заполняем временную запись нулями - а это-то зачем? И таки таскаем за собой глобальную переменную!
← →
Виталий © (2010-07-12 23:46) [187]
> А не надо было проскакивать типизированные файлы.
> Мож чего бы на ум и пришло.
А в типизированый файл я AnsiString не запишу нормально!
← →
Юрий Зотов © (2010-07-12 23:47) [188]> Виталий © (12.07.10 23:36) [182]
> куда копать в сторону организации быстрого доступа к данным?
> Я думаю, это второй шаг.
Правильно думаете. А копать в сторону Seek, конечно. Но тогда перед каждым блоком нужно писать его размер. Под блоком здесь подразумевается сама структура + 3 ее строки. То есть, если длины строк писать в самой структуре, то размер блока будет равен
SizeOf(TFriend) + Length(FirstName) + Length(LatsName) + Length(Phone)
Тогда, чтобы быстро выйти на N-й блок, в цикле делаем так:
читаем длину блока
перемещаемся на эту длину
← →
Виталий © (2010-07-12 23:47) [189]Там-то я, зная точный размер структуры, легко перейду к нужной с помощью Seek.
← →
Sha © (2010-07-12 23:47) [190]Ниасилил, значит.
← →
Виталий © (2010-07-12 23:50) [191]
> Ниасилил, значит.
что "ниасилил"-то? Какой важный момент я упускаю?
← →
Юрий Зотов © (2010-07-12 23:51) [192]Во всяком случае, уже можно делать резюме: тема записи и чтения произвольных структур данных таки раскрыта.
Причем очень быстро и практически самостоятельно - поэтому непонятно, откуда взялись первоначальные проблемы.
← →
Виталий © (2010-07-12 23:55) [193]
> откуда взялись первоначальные проблемы
До них еще дойду. Они-то не столько с этим связаны, сколько с правильным пониманием.
← →
Юрий Зотов © (2010-07-12 23:55) [194]> Виталий
Как насчет двух файлов? Первый - типизированный, второй - нет.
Второй хранит сами блоки данных, первый - их смещения во втором.
Тогда на любой блок данных выходим за два Seek.
← →
Виталий © (2010-07-12 23:58) [195]
> Как насчет двух файлов? Первый - типизированный, второй
> - нет.
Мне кажется, "настоящие" базы данных не "расходуют" файлы в таком количестве. Хотя - кто их знает, как они реализованы.
← →
Sha © (2010-07-13 00:01) [196]> что "ниасилил"-то?
В целом полет нормальный.
> Какой важный момент я упускаю?
Например, на диске данных хранятся в секторах одного типа размером 512 байт.
И это не мешает тебе туда писать достаточно длинные строки.
> А в типизированый файл я AnsiString не запишу нормально!
Нет ли тут противоречия?
← →
Виталий © (2010-07-13 00:04) [197]
> Нет ли тут противоречия?
Вы предлагаете ограниченную длину строки некоторым все же весьма небольшим значением. А если я хочу записать значение в пару мегабайт (заметку, например)? Причем одна заметка будет на 100 кб, а другая - на 2 мб?
← →
Sha © (2010-07-13 00:05) [198]> Вы предлагаете ограниченную длину строки
Где?
← →
Виталий © (2010-07-13 00:06) [199]
> Например, на диске данных хранятся в секторах одного типа
> размером 512 байт.
> И это не мешает тебе туда писать достаточно длинные строки.
>
Или я чего-то не понимаю.
← →
Sha © (2010-07-13 00:06) [200]Или
Страницы: 1 2 3 4 5 6 7 8 9
10 11 12 вся ветка
Форум: "Прочее";
Текущий архив: 2010.11.07;
Скачать: [xml.tar.bz2];
Память: 0.82 MB
Время: 0.063 c