Q&A

  • 레코드 파일에서 입력과 삭제문제..
레코드 파일을 이용하여, 간단하게 자료를 입력하고 찾고 삭제하는 모듈을 만들려고 합니다. 그런데, 입력하고, 삭제하는 부분이 막막하네여...(T.T)



아래있는 부분은 소스 파일입니다.



unit Global;



interface

uses Classes, dialogs, sysutils;



const

c_Title = 'test';

FName = 'Reserve.DAT';



type



// 개인 정보를 담을 레코드를 정의한다.

// 정보를 담을 레코드를 정의한다.

TReserve = packed record

RDate : String[10];

RTime : String[5];

RProject : String[16];

ROrgID : String[16];

State : String[1]; //0 : 진행 대기, 1 : 진행 중, 2 : 진행 완료

end;



// TFileStream 상속 객체의 정의. 이 객체가 TPersonRec의 파일 I/O를 담당한다.



TRecordStream = class(TFileStream)

private

function GetNumRecs: Longint;

function GetCurRec: Longint;

procedure SetCurRec(RecNo: Longint);

protected

function GetRecSize: Longint; virtual;

public

function SeekRec(RecNo: Longint; Origin: Word): Longint;

function WriteRec(const Rec): Longint;

function AppendRec(const Rec): Longint;

function ReadRec(var Rec): Longint;

procedure First;

procedure Last;

procedure NextRec;

procedure PreviousRec;

// NumRecs는 스트림의 레코드 개수를 뜻하는 속성

property NumRecs: Longint read GetNumRecs;

// CurRec는 스트림의 현재 레코드를 뜻하는 속성

property CurRec: Longint read GetCurRec write SetCurRec;

end;



implementation



function TRecordStream.GetRecSize:Longint;

begin

{ 이 함수는 이 스트림이 인식하는 레코드(TPersonRec)의 크기를 돌려준다. }

Result := SizeOf(TReserve);

end;



function TRecordStream.GetNumRecs: Longint;

begin

// 이 함수는 스트림 안에 있는 레코드 수를 돌려준다.

Result := Size div GetRecSize;

end;



function TRecordStream.GetCurRec: Longint;

begin

{ 이 함수는 현재 레코드의 위치를 돌려준다. 파일 포인터는 항상 레코드의

시작 위치에 있으므로 1을 더해야 레코드 위치가 제대로 계산된다. }

Result := (Position div GetRecSize) + 1;

end;



procedure TRecordStream.SetCurRec(RecNo: Longint);

begin

{ 이 프로시저는 스트림 안에서의 레코드 위치를 RecNo 인자로 지정된

위치로 설정한다. }

if RecNo > 0 then

Position := (RecNo - 1) * GetRecSize

else

Raise Exception.Create('Cannot go beyond beginning of file.');

end;



function TRecordStream.SeekRec(RecNo: Longint; Origin: Word): Longint;

begin

{ 이 함수는 파일 포인터를 RecNo로 지정된 위치로 옮긴다. }



{ 주의: 이 메소드에는 파일 포인터가 스트림 파일의 시작/끝을 넘을 때 생기는

에러를 처리하지 않는다. }

Result := Seek(RecNo * GetRecSize, Origin);

end;



function TRecordStream.WriteRec(Const Rec): Longint;

begin

// 이 함수는 레코드 Rec를 스트림에 기록한다.

Result := Write(Rec, GetRecSize)

end;



//문제의 부분......

function TRecordStream.AppendRec(Const Rec): Longint;

begin

// 이 함수는 레코드 Rec를 스트림에 기록한다.

// Seek(-Size , 1);

Result := Write(Rec, GetRecSize);

end;



function TRecordStream.ReadRec(var Rec): Longint;

begin

{ 이 함수는 스트림으로부터 레코드 Rec을 읽고 파일 포인터의 위치를

레코드의 시작 위치로 다시 되돌린다. }

Result := Read(Rec, GetRecSize);

Seek(-GetRecSize, 1);

end;



procedure TRecordStream.First;

begin

{ 이 함수는 파일 포인터의 위치를 스트림의 시작 위치로 옮긴다. }

Seek(0, 0);

end;



procedure TRecordStream.Last;

begin

// 이 프로시저는 파일 포인터를 스트림의 끝으로 옮긴다.

Seek(0, 2);

Seek(-GetRecSize, 1);

end;



procedure TRecordStream.NextRec;

begin

{ 이 프로시저는 파일 포인터를 다음 레코드 위치로 옮긴다. }

{ 파일의 끝을 지나지 않는다면 다음 레코드로 넘어간다. }

if ((Position + GetRecSize) div GetRecSize) = GetNumRecs then

raise Exception.Create('Cannot read beyond end of file')

else

Seek(GetRecSize, 1);

end;



procedure TRecordStream.PreviousRec;

begin

{ 이 프로시저는 파일 포인터를 스트림의 이전 레코드로 옮긴다. }



{ 파일의 시작을 넘지 않는다면 이전 레코드로 돌아간다. }

if (Position - GetRecSize >= 0) then

Seek(-GetRecSize, 1)

else

Raise Exception.Create('더 이상의 레코드는 존재하지 않습니다.');

end;



end.



이렇게 하면, 새로운 레코드가 기록되는게 아니라, over write 해 버립니다.

제발 도와 주세요.

1  COMMENTS
  • Profile
    최용일 2000.09.09 08:33
    안녕하세요. 델파이세상(http://www.freechal.com/delphiworld)의 최용일입니다.



    TRecordStream.WriteRec은 현재의 파일위치에 그대로 쓰니까 오버라이트가 되죠.



    쓰기 전에 파일의 맨 끝으로 이동을 해주어야 하지 않나요?



    function TRecordStream.WriteRec(Const Rec): Longint;

    begin

    Seek(0, soFromEnd); // 파일포인터를 파일의 끝으로 이동시킨다.

    // 이 함수는 레코드 Rec를 스트림에 기록한다.

    Result := Write(Rec, GetRecSize)

    end;



    ^^ 항상 즐코하세요.



    종상이 wrote:

    > 레코드 파일을 이용하여, 간단하게 자료를 입력하고 찾고 삭제하는 모듈을 만들려고 합니다. 그런데, 입력하고, 삭제하는 부분이 막막하네여...(T.T)

    >

    > 아래있는 부분은 소스 파일입니다.

    >

    > unit Global;

    >

    > interface

    > uses Classes, dialogs, sysutils;

    >

    > const

    > c_Title = 'test';

    > FName = 'Reserve.DAT';

    >

    > type

    >

    > // 개인 정보를 담을 레코드를 정의한다.

    > // 정보를 담을 레코드를 정의한다.

    > TReserve = packed record

    > RDate : String[10];

    > RTime : String[5];

    > RProject : String[16];

    > ROrgID : String[16];

    > State : String[1]; //0 : 진행 대기, 1 : 진행 중, 2 : 진행 완료

    > end;

    >

    > // TFileStream 상속 객체의 정의. 이 객체가 TPersonRec의 파일 I/O를 담당한다.

    >

    > TRecordStream = class(TFileStream)

    > private

    > function GetNumRecs: Longint;

    > function GetCurRec: Longint;

    > procedure SetCurRec(RecNo: Longint);

    > protected

    > function GetRecSize: Longint; virtual;

    > public

    > function SeekRec(RecNo: Longint; Origin: Word): Longint;

    > function WriteRec(const Rec): Longint;

    > function AppendRec(const Rec): Longint;

    > function ReadRec(var Rec): Longint;

    > procedure First;

    > procedure Last;

    > procedure NextRec;

    > procedure PreviousRec;

    > // NumRecs는 스트림의 레코드 개수를 뜻하는 속성

    > property NumRecs: Longint read GetNumRecs;

    > // CurRec는 스트림의 현재 레코드를 뜻하는 속성

    > property CurRec: Longint read GetCurRec write SetCurRec;

    > end;

    >

    > implementation

    >

    > function TRecordStream.GetRecSize:Longint;

    > begin

    > { 이 함수는 이 스트림이 인식하는 레코드(TPersonRec)의 크기를 돌려준다. }

    > Result := SizeOf(TReserve);

    > end;

    >

    > function TRecordStream.GetNumRecs: Longint;

    > begin

    > // 이 함수는 스트림 안에 있는 레코드 수를 돌려준다.

    > Result := Size div GetRecSize;

    > end;

    >

    > function TRecordStream.GetCurRec: Longint;

    > begin

    > { 이 함수는 현재 레코드의 위치를 돌려준다. 파일 포인터는 항상 레코드의

    > 시작 위치에 있으므로 1을 더해야 레코드 위치가 제대로 계산된다. }

    > Result := (Position div GetRecSize) + 1;

    > end;

    >

    > procedure TRecordStream.SetCurRec(RecNo: Longint);

    > begin

    > { 이 프로시저는 스트림 안에서의 레코드 위치를 RecNo 인자로 지정된

    > 위치로 설정한다. }

    > if RecNo > 0 then

    > Position := (RecNo - 1) * GetRecSize

    > else

    > Raise Exception.Create('Cannot go beyond beginning of file.');

    > end;

    >

    > function TRecordStream.SeekRec(RecNo: Longint; Origin: Word): Longint;

    > begin

    > { 이 함수는 파일 포인터를 RecNo로 지정된 위치로 옮긴다. }

    >

    > { 주의: 이 메소드에는 파일 포인터가 스트림 파일의 시작/끝을 넘을 때 생기는

    > 에러를 처리하지 않는다. }

    > Result := Seek(RecNo * GetRecSize, Origin);

    > end;

    >

    > function TRecordStream.WriteRec(Const Rec): Longint;

    > begin

    > // 이 함수는 레코드 Rec를 스트림에 기록한다.

    > Result := Write(Rec, GetRecSize)

    > end;

    >

    > //문제의 부분......

    > function TRecordStream.AppendRec(Const Rec): Longint;

    > begin

    > // 이 함수는 레코드 Rec를 스트림에 기록한다.

    > // Seek(-Size , 1);

    > Result := Write(Rec, GetRecSize);

    > end;

    >

    > function TRecordStream.ReadRec(var Rec): Longint;

    > begin

    > { 이 함수는 스트림으로부터 레코드 Rec을 읽고 파일 포인터의 위치를

    > 레코드의 시작 위치로 다시 되돌린다. }

    > Result := Read(Rec, GetRecSize);

    > Seek(-GetRecSize, 1);

    > end;

    >

    > procedure TRecordStream.First;

    > begin

    > { 이 함수는 파일 포인터의 위치를 스트림의 시작 위치로 옮긴다. }

    > Seek(0, 0);

    > end;

    >

    > procedure TRecordStream.Last;

    > begin

    > // 이 프로시저는 파일 포인터를 스트림의 끝으로 옮긴다.

    > Seek(0, 2);

    > Seek(-GetRecSize, 1);

    > end;

    >

    > procedure TRecordStream.NextRec;

    > begin

    > { 이 프로시저는 파일 포인터를 다음 레코드 위치로 옮긴다. }

    > { 파일의 끝을 지나지 않는다면 다음 레코드로 넘어간다. }

    > if ((Position + GetRecSize) div GetRecSize) = GetNumRecs then

    > raise Exception.Create('Cannot read beyond end of file')

    > else

    > Seek(GetRecSize, 1);

    > end;

    >

    > procedure TRecordStream.PreviousRec;

    > begin

    > { 이 프로시저는 파일 포인터를 스트림의 이전 레코드로 옮긴다. }

    >

    > { 파일의 시작을 넘지 않는다면 이전 레코드로 돌아간다. }

    > if (Position - GetRecSize >= 0) then

    > Seek(-GetRecSize, 1)

    > else

    > Raise Exception.Create('더 이상의 레코드는 존재하지 않습니다.');

    > end;

    >

    > end.

    >

    > 이렇게 하면, 새로운 레코드가 기록되는게 아니라, over write 해 버립니다.

    > 제발 도와 주세요.