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

Вниз

Неясности в формате файла   Найти похожие ветки 

 
Виталий ©   (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;
Скачать: CL | DM;

Наверх




Память: 0.84 MB
Время: 0.06 c
2-1281601651
Nilman
2010-08-12 12:27
2010.11.07
Подскажите как работать с типом


15-1280474574
Лезнайка на Нуле
2010-07-30 11:22
2010.11.07
когнитивный диссонанс


2-1281765808
Fr
2010-08-14 10:03
2010.11.07
Ping хоста


15-1279771521
Spot
2010-07-22 08:05
2010.11.07
Не работают точки останова


15-1280158011
AKE
2010-07-26 19:26
2010.11.07
Скажите это развод??