Форум: "Основная";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.01.17;
Скачать: [xml.tar.bz2];




Вниз

Не, ну вообще прикл... 


VitHouse   (2001-12-27 10:25) [0]

Увожаемые Мастера!

Как сохранять данные в файл, при том они могут быть разного типа
Например

TMonitor = record
Name: string;
ModelNo: integer;
end;

TComputer = record
ProcName: string;
ProcMHZ: integer;
end;


Допустим у нас два массива из мониторов и компьютеров. Как всё это сохранить в ОДИН файл, а потоп читать из него?



gek   (2001-12-27 10:30) [1]

Записи одинаковые зачем две делать сделай одну
TComputerMonitor = record
ProcName: string;
ProcMHZ: integer;
Name: string;
ModelNo: integer;
end;



VitHouse   (2001-12-27 10:42) [2]

Спасибо за интерес!
Рад познакомиться))

дело в том что мониторов и компьютеров может быть разное число, да и ещё в структуре + поле индексной связи(hComputer: THandle), т.е. мониторы отдельно, компы отдельно.
Бытовая ситуация: Монитор сгорел, купили новый, подцепили к какому то компу и т.д.
!!???



Delirium   (2001-12-27 10:48) [3]

Тогда это уже вопрос по БД, советую немного почитать по этому поводу и обращаться в раздел Вопросы по базам данных



VitHouse   (2001-12-27 10:54) [4]

THX!
да нет это просто пример, есть прога "расчет ЧЕГО-то", в которой просто ведется проект, и там куча разных типов, но это не должно работать как БД. Файл записывается, другой юзверь в нем чё-то творит и так далее... как в Ворде, или Ёкселе)



gek   (2001-12-27 11:03) [5]

Блин ну сделай выборку из записи

TComputerMonitor = record
ProcName: string;
ProcMHZ: integer;
Name: string;
ModelNo: integer;
end;

if ProcMHZ = 0 then//енто комп
else// енто монитор


Какие проблемы? Ну и пиши радостью в один файл-будешь счастлив



VitHouse   (2001-12-27 12:00) [6]

>gek
у меня 14 разных типов, и чё делать?

TComputerMonitorUserMousePrintersFloorPaperXerox?



gek   (2001-12-27 12:07) [7]

Или именно так (у меня как-то на турбо 7.0 около 20 полей в записи было и все енто дело в файл писал),
или делай как тебе Delirium сказал с БД работать.
Ну и последнее - упакуй запись packedи используй в записи case если уж так хочется работать таким образом



VitHouse   (2001-12-27 12:11) [8]

а что разве разные типы нельзя одновременно хранить?
зачем усложняться-то. Выглядит не рационально!



Алексей Петров   (2001-12-27 12:14) [9]

Ну введи в каждой записи первым полем байт с её размером или типом - при чтении по нему будешь разбираться, что-же такое прочиталось, и сколько байт нужно до следующей записи читать. Только от типизированного файла тогда отказаться придется - он работает строго с одним типом.



gek   (2001-12-27 12:27) [10]

Да ничего там сложного не будет
выборку сделай по ключу типа
case key of
1:комп
2:монитор
..
10:мышь
end;



VitHouse   (2001-12-27 12:40) [11]

Мне пришло предложение:

****Тело файла******
Минитор(Samsung, 17, 2, P);
Минитор(Philips, 14, 4, D);
Минитор(Akai, 15, 2, P);
Комп(700, 133, Интел, Целерон);
Комп(345, 133, Интел, Пень);
Принтер(Эпсон, 234, А4);
...
...
********************

А потом написать конверторы скриптов на каждую строку.
А все однородные типу будут храниться указателями в своем TList"e.

type ScriptFile = class
...
TComps,
TMonitors,
TPrinters: TList;
...


И в проге работать с записями из ТЛистов.
И с помощью конвертера записывать и читать файл!

Что вы думаете, господа, по этому поводу?



gek   (2001-12-27 12:47) [12]

Интересно как ты этот конвертор себе представляешь?



VitHouse   (2001-12-27 12:54) [13]

Этот конвертор распознает функции типа:
Монитор("Самсунг","20","АА");
Конвертор заполняет тип TStringFunction, Где в него прописывается имя скриптофункции и массив всех параметров!!!!!
Исходник ниже))



unit FuncConvertor10;
{Распознование функций и процедер
Версия 1.01
VitHouse ® 2001}

interface

type
TStringParams = array of string;
{Структура функции Name - Заголовок/Имя,}

PStringFunction = ^TStringFunction;
TStringFunction = record
Name: string;
Params: array of string;
end;

{Локальные явные функции}
function GetFunction (_Value: string): TStringFunction;
function FuncToStringLine (Func: TStringFunction): string;
function CreateFunction (FuncName: string; Params: array of string): TStringFunction;

{Указательные функции}
{
function GetPFunctionAddr(Value: PChar): Pointer;
function PFuncToPChar(FuncAddr: Pointer): PChar;
function CreateFunctionAddr(FuncName: PChar; Params: array of PCHar): Pointer;
}

implementation {Рутинные функции}

function CreateFunction(FuncName: string; Params: array of string): TStringFunction;
var i: integer;
l: integer;
begin
Result.Name := FuncName;
l := Length(Params);
SetLength(Result.Params, l);
for i := 0 to Length(Params) - 1 do
Result.Params[i] := Params[i];
end;


function GetCharCount(CharFind: char; _Value: string): integer;
var CharCount: integer;
Value: string;
begin
Result := 0;
Value := _Value;
CharCount{Количесво запятых} := 0;
while Pos(CharFind, Value)>0 do begin
delete(Value, Pos(",", Value), 1);
Inc(CharCount);
end;

Result := CharCount;
end;

function GetFunction(_Value: string): TStringFunction;
var Value: string;
ZapCount: Integer;
i: integer;
_Params: array of string;
begin
{
Имя функции до первой скобки (
Параметр начинается с ковычки "
Параметр заканчивается ковычкой "
Следующий параметр через запятую ,
Заканчивается функция скобкой )
}

{Этапы расспознования функции}
Value := _Value;
Result.Name := Copy(Value, 1, Pos("(", Value)-1); //Имя функции

if (Pos("(", Value) = 0) and (Pos(")", Value)=0) then
begin
Result.Name := _Value;
EXIT;
end;

{Определяем кол-во параметров}

ZapCount{Количесво запятых} := GetCharCount(",", Value);


{Если параметров нет, то выход}
if ZapCount = 0 then EXIT;


{Задаем длину массива параметров}
SetLength(Result.Params, ZapCount+1);
//SetLength(Params, ZapCount+1);


{Заполнение массива параметров значениями}

delete(Value, 1, Pos("""", Value)-1);
delete(Value, Pos(")", Value), 1);

for i := 0 to LENGTH(Result.Params) - 1 do
begin
{Поиск значения параметра
Находим первую кавычку и стераем все до нее}

{Убиваем первую кавычку}
delete(Value, POS("""", Value), 1);

{Назначаем значение параметра до следующей ковычки}
Result.Params[i] := COPY(Value, 1, Pos("""", Value)-1) ;//""+inttostr(i);

{Убиваем вторую кавычку}
delete(Value, POS("""", Value), 1);

{Убиваем все до следующей кавычки}
delete(Value, 1, Pos("""", Value)-1);
end;


end;

function FuncToStringLine(Func: TStringFunction): string;
var i: integer;
begin
Result := "";

for i := 0 to LENGTH(Func.Params) - 1 do
if i = LENGTH(Func.Params) - 1 then Result :=Result+ """" + Func.Params[i] + """"
else Result := Result+ """" + Func.Params[i] + """, ";

Result := Func.Name + "(" + Result + ")";

end;

end.



Жду Ваших мнений, господа!



gek   (2001-12-27 13:07) [14]

Ты сначала попробуй сам, ну а потом нам скажешь. Тогда и будем смотреть



Snake   (2001-12-27 14:12) [15]

Если это на Дельфях, то можно попробовать поюзать потоки. Правда, скорее всего, в записях нужно будет хранить признак типа этой записи - монитор или комп.



VitHouse   (2001-12-27 14:29) [16]

>gek

Вообще-то я попробывал, по моему не плохо!)
Посмотри мыло: там демошка на основе этого скрипта, + файл для этой проги, посмотри структуру и открой её в проге. прога ещё в разработке!
На векторную графику не обращай внимания - отдельный разговор)



VaS   (2001-12-27 14:48) [17]

Структурированные хранилища не подойдут?



VitHouse   (2001-12-27 15:01) [18]

>VaS

Благодарю за интерес!

А можно по-подробнее...



ValeraVV   (2001-12-27 15:26) [19]

Ну если на то пошло, VitHouse © (27.12.01 12:54), используй XML.

Посмотри также мой примерчик, выслал на мыло, hardware.rar, там правда не документ, а база, но типы объектов произвольные (разработчику еще неизвестные, заводимые пользователем)

XML тебе идеально подходит, используй вместо таблиц (как у меня) TClientDataset, и гони их в XML для обмена между пользователями, а руки дойдут - собственный парсер сделать можно, главное с форматом файла "устандартиться"



gek   (2001-12-27 15:31) [20]

Неа это по-моему изврат.
Лучше все-таки писать все это дело в типизированном файле.
Ну а если в текстовом, ну на мой взгляд(не претендую на гениальность) все-же лучше с ключом
key,str1,str2(все равно строку надо анализировать)
зачем так много кода?



VitHouse   (2001-12-27 16:00) [21]

>ValeraVV © (27.12.01 15:26

Спасибо за совет, как посмотрю отвечу



perov   (2001-12-27 16:03) [22]

в Турбо Паскале 5,5 был и есть хороший пример хранения данных разных типов с помощью потоков (небольшая БД). На основе этой демки я даже написал очень даже неплохую программульку



ValeraVV   (2001-12-27 17:07) [23]

>VitHouse © (27.12.01 16:00)
Поясню идею
Откажись от древовидной структуры (делай не как у меня)
Откажись от интерфейсов (интерфейсы у меня нужны лишь для того, чтобы отражать сходства между объектами разных типов)
Тогда у тебя:
ClientDataSet1 (ObjID, ObjName, ObjAttrs)- список объектов, у него есть поле ObjAttrs типа ftDataSet, то есть дочерняя таблица, к ней привязываешь
ClientDataSet2 - перечень атрибутов со значениями AttrName, AttrValue (можно все типа String)
Заполнил базу - скинул файл ClientDataSet1.SaveToFile(const FileName: string = ""; Format: TDataPacketFormat = dfBinary), если укажешь Format=dfXML или расширение ".xml", тогда все скинется в XML - тогда потом можно свой парсер применять.
В D6 вроде как можно по-приличней оформленные XML получать, я еще не смотрел.
У другого юзера делай ClientDataSet1.LoadFromFile(const FileName: string = "");



ValeraVV   (2001-12-27 17:30) [24]

Точно, в D6, XML поприличней, только что попробовал на своей базе в дезайн-тайме - красиво получается



ValeraVV   (2001-12-27 18:33) [25]

>VitHouse © (27.12.01 16:00)
К чему пришел?
еще идея (вообще изврат)
TMonitor = class(TComponent)
published
Name: string;
ModelNo: integer;
end;
TMonitorSuper=class(TMonitor)
published
ExtraParameter:string;
end;


Создавай объекты так:
TMonitor.Create(DataModule1);
TMonitorSuper.Create(DataModule1);
перебирай через DataModule1.Components
потом делай TFileStream.WriteComponent(DataModule1), а чтобы сделать файл читаемым (и редактируемым в блокноте)используй ObjectBinaryToText и ObjectTextToBinary

Короче и XML и WriteComponent используют встроенные методы чтения/сохранения.
Может легче, научиться работать с потоками?



ValeraVV   (2001-12-27 18:39) [26]

Забыл, чтобы WriteComponent и ReadComponent работали надо RegisterClass(TMonitor), RegisterClass(TMonitorSuper) делать



3d[Power]   (2001-12-28 01:45) [27]

Кстати люди я столкнулся с такой же проблемой!
Вот к примеру у меня есть:

MyBrick = record
x,y : word;
texture : byte;
animated : boolean;
...
end;


Я допустим пишу это все в файл , и получается 1 record у меня занимает, скока, 4 байта(или 5). Вот если я запишу допустим 10 раз это все это будет 40 байт. А после этого мне надо воткнуть вот что:

TMySTRData = record
string1 : shortstring;
value : single;
parameter : byte;
end;


1 раз и затем снова продолжать писать TMyBrick много раз.

Решение номер 1:
Объединить record TMySTRData и TMyBrick. Но это тогда огромная потеря места!.

Решение номер 2:
Создать свой обработчик файла который через blockread будет все это обрабатывать. Допустим:

Байты нового якобы record"a:
$00 - тип записи (если 1 то TMyBrick а 2 TMySTRDATA)
И потом в зависимости от типа записи считывать определенное колво байт.

Вопрос вот вчем:
Можно ли так сделать:
К примеру myfile.seek(someaddr)
а потом read(myfile, mybrick);
или read(myfile, mystrdata);

А приходится указывать myfile : file of TMYBRICK.



ValeraVV   (2001-12-28 06:10) [28]

>3d[Power] © (28.12.01 01:45)
В Дельфи/Паскале, конструкция myfile : file of TMYBRICK, введена в язык для того, чтобы делать:
1.seek(3), вместо seek(3* SizeOf(TMYBRICK)),
2.read(mybrick), вместо blockread(mybrick, SizeOf(TMYBRICK)),
3.write(mybrick), вместо blockwrite(mybrick, SizeOf(TMYBRICK)),
Все, 3 пункта, и больше ничего из этого не выжать, заметь, что везде подставляется SizeOf(TMYBRICK), взятый из объявления myfile (а откуда еще знать какой же все таки размер переменной).
Если нужно пользоваться возможностями "встроенными" в Delphi, то пользуйтесь VCL Streaming System - это когда Delphi сама способна сохранять/загружать объекты зарегистрированных классов (без override методов, по умолчанию, сохраняются published свойства объектов), заботиться практически ни о чем не надо - если такая цель стоит. (см. ValeraVV © (27.12.01 18:33))



VitHouse   (2001-12-28 06:59) [29]

По моему, стандартные решения Дельфи этой проблемы здесь не подайдут!А вот такой пример записи файла (как HTML)

Monitor(Name="Samsung", Size="17", Class="AA");
Computer(Proc="Pentium IV", MHZ="1400");

При этом сделать новую структуру типу чтения скриптофункции:

TScryptoFunc = record
Name: string;
ArrayOfParamNames: array of string;
ArrayOfValueParams: array of string;
end;


И при чтении строки из скриптофайла создается переменная типа TScryptoFunc
Читаем строку Monitor(Name="Samsung", Size="17", Class="AA");
Получаем

var
ReadSF: TScryptoFunc
begin
ReadSF := ReadStringToTScryptoFunc( "Monitor(Name="Samsung", Size="17", Class="AA");");
//получаем
ReadSF.Name = "Monitor";
ReadSF.ArrayOfParamNames = ("Name", "Size", Class);
ReadSF.ArrayOfValueParams = ("Samsung", "17", "AA");


Ну и вроде работает.
Потом Сструктуру TScryptoFunc переганять в свои массивы:

case ReadSF.Name of
"Moniror": AddMonitor(ReadSF);
"Computer": AddComputer(ReadSF);
end;


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

Жду мнений)





3d[Power]   (2001-12-28 07:27) [30]

2 VitHouse & ValeraVV
В таком случае можно самому написать обработчик файла, как я уже предлагал:
1 байт - тип "якобы" record
2 word - скока байт, до следущего seek.

А предложение ReadStringToTScryptoFunc("Monitor(Name="Samsung", Size="17", Class="AA");"); по моему вообще не рациональное, только круто что мона будет самому все в бреде писать.

2 ValeraVV
>1.seek(3), вместо seek(3*SizeOf(TMYBRICK)),
>2.read(mybrick), вместо blockread(mybrick,SizeOf(TMYBRICK)),
>3.write(mybrick), вместо blockwrite(mybrick,SizeOf(TMYBRICK)),
Только в этом случае дельфа сама "расставляет" байты по переменным. а




Форум: "Основная";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.01.17;
Скачать: [xml.tar.bz2];




Наверх





Память: 0.8 MB
Время: 0.022 c
1-52583           Cyber                 2001-12-25 21:44  2002.01.17  
Люди, профы, помогите. Help me!


1-52535           tovSuhov              2001-12-27 16:04  2002.01.17  
Люди! Совсем запутался.


3-52459           dorosh                2001-12-14 06:55  2002.01.17  
Как в DbGrid перерисовать ячейку


3-52496           Шавлюк Евгений        2001-12-13 00:27  2002.01.17  
Использование ClientDataSet


6-52632           maxi                  2001-10-23 09:20  2002.01.17  
Своевременное обновление наборов данных на MIDAS Delphi5