Форум: "Основная";
Текущий архив: 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)),
Только в этом случае дельфа сама "расставляет" байты по переменным. а
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2002.01.17;
Скачать: [xml.tar.bz2];
Память: 0.54 MB
Время: 0.005 c