2011-08-18 9 views
2

시뮬레이션 프로그램의 경우 Delphi 2010에서 작업하고 있습니다. 시뮬레이션에는 문제가 없지만 문제가되는 데이터를 많이 사용해야합니다. 데이터는 Excel 시트에서 사용할 수 있으므로 Delphi에서이 데이터를 편집 할 필요는 없지만 Excel 시트에서이 데이터를 수집하는 데는 약 10 분이 걸립니다. 이는 프로그램을 실행할 때마다 데이터를 수집 할 필요가없는 한 문제가되지 않습니다. 그래서 나는 모든 데이터를 모으는 프로그램을 만들어서 여기에 문제가 아닌 그것을 보이도록 만든 다음 그것을 저장합니다. 그러나 구조를 잃지 않고 "Delphi 형식"으로 저장할 수 없으므로 몇 초 안에로드 할 수 있습니다.델파이 : 어떤 종류의 구조에 데이터 저장

나는 델파이에서 경험이 없기 때문에 오랫동안 해결책을 찾았지만 무엇이 최선인지 이해하지 못했습니다. 나는 데이터를 구조화하는 나의 방식이 잘못되었다고 생각하지만 간단하고 효과적이었다. 그러나 데이터를 저장하는 더 좋은 방법이 있다면 'xml file', 'generict 또는'Ttreeview '를 사용하는 것보다 더 많은 설명이 필요하다는 것을 기억하십시오. (읽었지만 사용할 수 없었습니다).

데이터는 다음 용도로 사용됩니다.이 제품을 만들었습니다. 다음 제품은이 제품이므로 청소해야합니까? 참 또는 거짓.

데이터는 Productnumber (정수)가있는 클래스 (TObject)와 다음에 만들 수있는 모든 제품을 포함하는 List로 저장됩니다.이 목록에는 Productnumber (정수) 및 do I 청소해야합니다 (부울). 이 구조를 파일에 저장하고 데이터를 잃지 않고 다시 같은 구조로 읽으려고합니다.

누군가 도와 주길 바랍니다. 미리 감사드립니다.

업데이트 : 코드는 (영어 수정) 조금 더 많은 정보

Clean_from = class(TObject) 
public 
    myfromNumber  : Integer; 
    mylist   : TList; 
published 
    constructor Create; 
End 

Clean_To = class(TObject) 
public 
    myToNumber  : Integer; 
    Clean    : Boolean; 
End; 

constructor Clean_from.Create; 
begin 
    inherited Create; 
    myList := Tlist.Create; 
end; 

For i = 0 to 100 do 
begin 
    From:= Clean_from.create; 
    for j := 0 to 10 do 
    begin 
    To := Clean_To.create; 
    To.clean := true or false; 
    From.myList.add(To); 
    end; 
    GlobalList.add(from); 
end; 

그리고 지금은 내가 같은 구조를로드 할 수있는 모든 내용에 글로벌 목록을 저장할을 제공합니다.

+0

데이터 구조가 무엇인지 추측하기가 약간 어렵습니다. "clean (boolean)"이란 무엇을 의미합니까? 부울 속성입니까? –

+0

@Arnand : 내가 이해 한 것처럼, "청소해야합니까?"라는 의미의 부울입니다. –

+1

"데이터를 구조화하는 내 방식이 잘못되었다고 생각하지만 간단하고 효과적이었습니다"- 데이터 구조가 간단하고 작동한다면 어떻게 잘못 될 수 있습니까? –

답변

19

필요한 것은 소위 "직렬화"메커니즘입니다.

1. 표준 방법

1.1 SaveToStream

델파이에서, 우리는 일반적으로 (중 하나 TFileStream 또는 대상 TStream에서 각 개체의 내용을 저장하는 SaveToStream 방법을 구현 a TMemoryStream).

직접 작성해야합니다.

1.2 DFM 같은 스트리밍

TWriter/TReader 클래스를 참조하십시오.

게시 된 속성에서 데이터를 정의하면 표준 Delphi 클래스를 사용하여 데이터를 직렬화 할 수 있습니다. this blog article를 참조 JSON과 에서 내용을 어떤 TCollection를 직렬화 할 몇 가지 방법에 대한

.

2. RTTI는

예를 this SO question를 참조하십시오.

특히 향상된 새로운 RTTI (Delphi 2010 이후 사용 가능)는 직렬화에 새로운 기회를 열어줍니다.

3. 기록 대신 클래스

각 항목 콘텐츠 (일부 정수/부울)를 많이 저장하지 않는 경우는 대신 개체의 레코드를 사용하는 의미가 있습니다. 속도와 메모리 소비/조각화를 위해서는 그만한 가치가있을 것입니다.

여기에는 some wrapper able to serialize any dynamic array이며 중첩 된 레코드 또는 동적 배열이 포함됩니다.

4. 응용 프로그램에 대한 독점 아마도 더 나은 방법은 데이터가 아닌 진화 바이너리 형식에 갇혀 가지고 있지 않은 데이터베이스 엔진

. 속성을 추가하려면 직접 속성을 관리해야합니다. 또는 다른 응용 프로그램의 데이터에 액세스하려는 경우 어려울 수 있습니다.

외부 데이터베이스 (예 : MS SQL, FireBird 또는 Oracle)를 사용하는 대신 데이터베이스를 응용 프로그램에 임베드하는 것이 좋습니다 (설치가 훨씬 쉽습니다). a lot of wrappers (our version 포함)이있는 SQLite을 언급 할만한 가치가 있습니다 (MS SQL 또는 Oracle을 대신 사용하려는 경우 다른 데이터베이스로 변경할 수 있음).

다른 해결책이 있습니다 (this SO question 참조). 성능이 필요한 경우 Big Table library을 살펴보십시오.

2

SaveToStream()LoadFromStream() 메서드를 데이터 객체에 추가합니다. 데이터 객체는 스트림에 데이터를 저장하고 스트림에서 데이터를로드합니다.

type 
    TMyData = class(TObject) 
    private 
    FChildProducts: TList; 
    FProductnumber : integer; 
    FClean: boolean; 
    public 
    procedure LoadFromStream(const aStream: TStream); 
    procedure SaveToStream(const aStream: TStream); 
    published 
    property Productnumber: Integer read FProductnumber write FProductnumber; 
    property Clean: Boolean reas FClean write FClean; 
    end; 

procedure TMyData.LoadFromStream(const aStream: TStream); 
var x, cnt: Integer; 
    cD: TMyData; 
begin 
    aStream.Read(FProductnumber, SizeOf(FProductnumber)); 
    aStream.Read(FClean, SizeOf(FClean)); 
    // read number of child products 
    aStream.Read(cnt, SizeOf(cnt)); 
    // load child objects 
    for x := 1 to cnt do begin 
    cD := TMyData.create; 
    cD.LoadFromStream(aStream); 
    FChildProducts.Add(cD); 
    end; 
end; 

procedure TMyData.SaveToStream(const aStream: TStream); 
var x: Integer; 
begin 
    aStream.Write(FProductnumber, SizeOf(FProductnumber)); 
    aStream.Write(FClean, SizeOf(FClean)); 
    // save number of child products 
    x := FChildProducts.Count; 
    aStream.Write(x, SizeOf(x)); 
    // save child objects 
    for x := 0 to FChildProducts.Count - 1 do 
    (FChildProducts[x] as TMyData).SaveToStream(aStream); 
end; 

난 당신이 스트림, 즉

function SaveDataList(const List: TList;const aFileName: string); 
var x: Integer; 
    FS: TFileStream; 
begin 
    FS := TFileStream.Create(aFileName, ...); 
    try 
    // save file version 
    x := 1; 
    FS.Write(x, SizeOf(x)); 
    // save number of products 
    x := List.Count; 
    FS.Write(x, SizeOf(x)); 
    // save objects 
    for x := 0 to List.Count - 1 do 
     (List[x] as TMyData).SaveToStream(FS); 
    finally 
    FS.Free; 
    end; 
end; 

이것은 일반적인 생각에서 당신이 저장 기능이나 방법을 할 수 있도록 "루트 객체"/로/하중을 일부 목록이 있다고 가정합니다 .. 데이터를 다시로드하는 방법도 명확해야합니다. 파일 버전은 데이터 객체가 변경 될 때 (즉, 속성을 추가하는 경우) 로딩 코드에서 데이터 객체의 올바른 버전으로 데이터를로드 할 수 있도록 버전 번호를 증가시킬 수 있습니다.

+0

내부 FChildProducts 인스턴스를 초기화하는 Create 생성자가 아직 없으며이를 해제하는 소멸자가 있습니다. –

+0

@Arnaud 예, 코드는 완벽한 준비가되지 않은 lib가 아닌 아이디어를 제시하기로되어 있습니다. 모든 코드를 작성하는 데 너무 많은 노력이 필요 하겠지만 ... OP가 시작되어야합니다. – ain

+0

OP가이 코드를 모두 읽는 것은 이미 매우 좋습니다. 항상 SO에서 직접 코드를 작성하는 노력입니다. –

0

Arnoud의 옵션 # 4를 사용하지만 중첩 된 ClientDataSets와 함께 ClientDataSet을 사용합니다. 이렇게하면 데이터를 유연한 구조로로드하고 저장할 수있을뿐만 아니라 신속하게 표시 할 수 있습니다. 중첩 된 데이터 세트 정보 및 예제는 this pagehere을 확인하십시오.

관련 문제