sauvegarder les enregistrements contenant un membre de type chaîne dans un fichier (Delphi, Windows)

StackOverflow https://stackoverflow.com/questions/1472325

Question

J'ai un dossier qui ressemble à:

type
  TNote = record
    Title : string;
    Note  : string;
    Index : integer;
  end;
Simple

. La raison pour laquelle j'ai choisi de définir les variables telles que la chaîne (par opposition à un tableau de caractères) est que je ne sais pas combien de temps ces cordes vont être. Ils peuvent être 1 caractère long, 200 ou 2000. Bien sûr, quand je tente de sauvegarder l'enregistrement dans un fichier de type (fichier ...) le compilateur se plaint que je dois donner une taille à la chaîne. Y at-il un moyen de surmonter cela? ou un moyen de sauvegarder les enregistrements dans un fichier typées et de maintenir encore une sorte de façon interrogeable?

S'il vous plaît ne me point pas solutions possibles , si vous connaissez la solution s'il vous plaît poster le code. Merci

Était-ce utile?

La solution

Vous ne pouvez pas le faire avec un fichier tapé. Essayez quelque chose comme ça, avec un TFileStream:

type
   TStreamEx = class helper for TStream
   public
      procedure writeString(const data: string);
      function readString: string;
      procedure writeInt(data: integer);
      function readInt: integer;
  end;

function TStreamEx.readString: string;
var
   len: integer;
   iString: UTF8String;
begin
   self.readBuffer(len, 4);
   if len > 0 then
   begin
      setLength(iString, len);
      self.ReadBuffer(iString[1], len);
      result := string(iString);
   end;
end;

procedure TStreamEx.writeString(const data: string);
var
   len: cardinal;
   oString: UTF8String;
begin
   oString := UTF8String(data);
   len := length(oString);
   self.WriteBuffer(len, 4);
   if len > 0 then
      self.WriteBuffer(oString[1], len);
end;

function TStreamEx.readInt: integer;
begin
   self.readBuffer(result, 4);
end;

procedure TStreamEx.writeInt(data: integer);
begin
   self.WriteBuffer(data, 4);
end;

type
  TNote = record
    Title : string;
    Note  : string;
    Index : integer;
    procedure Save(stream: TStream);
  end;

procedure TNote.Save(stream: TStream);
var
   temp: TMemoryStream;
begin
   temp := TMemoryStream.Create;
   try
      temp.writeString(Title);
      temp.writeString(Note);
      temp.writeInt(Index);
      temp.seek(0, soFromBeginning);
      stream.writeInt(temp.size);
      stream.copyFrom(temp, temp.size);
   finally
      temp.Free;
   end;
end;

Je vais laisser la procédure de charge pour vous. idée de base même, mais il ne devrait pas avoir besoin d'un flux de température. Avec la taille de l'enregistrement devant chaque entrée, vous pouvez le lire et de savoir jusqu'où aller si vous êtes à la recherche d'un certain dossier # au lieu de lire la chose.

EDIT: Ceci a été écrit spécifiquement pour les versions de Delphi qui utilisent des chaînes Unicode. Sur les anciennes versions, vous pouvez simplifier un peu.

Autres conseils

Pourquoi ne pas écrire ceci comme XML? Voir ma session " XML pratique avec Delphi " sur la façon dont pour commencer avec cela.

Une autre possibilité serait de faire vos dossiers en cours sous forme descendante TComponent et stocker / récupérer vos données dans les fichiers DFM.

Cette entrée Stackoverflow vous montre comment faire.

- jeroen

PS: Désolé ma réponse XML était un peu dense; Je suis en fait sur la route pour les deux conférences ( BASTA! et DelphiLive! Allemagne ).

En fait ce que vous devez faire est très simple: créer un fichier XML exemple, puis lancez le Data Wizard XML Delphi liaison (disponible en Delphi depuis la version 6).

Cet assistant va générer une unité pour vous qui a les interfaces et les classes XML aux objets Delphi, et quelques fonctions d'aide pour les lire à partir du fichier, la création d'un nouvel objet, etc. Ma session (voir le premier lien ci-dessus) contient en fait la plupart des détails de ce processus.

Le lien ci-dessus est une vidéo montrant l'utilisation de l'Assistant Liaison de données XML Delphi.

Vous pouvez travailler avec deux fichiers différents, qui stocke juste les cordes d'une manière pratique, les autres magasins les dossiers avec une référence aux chaînes. De cette façon, vous aurez toujours un fichier de dossiers pour un accès facile, même si vous ne connaissez pas la taille du contenu.

(Désolé, pas de code.)

  TNote = record
    Title : string;
    Note  : string;
    Index : integer;
  end;

pourrait se traduire par

  TNote = record
    Title : string[255];
    Note  : string[255];
    Index : integer;
  end;

et utiliser Stream.writebuffer (ANodeVariable, sizeof (TNODE), mais vous avez dit que les chaînes se passent plus de 255 caractères dans ce cas, si une chaîne passe au-dessus 65535 caractères puis changer WORD à ENTIER

type
TNodeHeader=Record
  TitleLen,
  NoteLen: Word;
end;

(* this is for writing a TNode *)
procedure saveNodetoStream(theNode: TNode; AStream: TStream);
var
  header: TNodeHeader;
  pStr: PChar;
begin
  ...
  (* writing to AStream which should be initialized before this *)
  Header.TitleLen := Length(theNode.Title);
  header.NodeLen := Length(theNode.Note);
  AStream.WriteBuffer(Header, sizeof(TNodeHeader);
  (* save strings *)
  PStr := PChar(theNode.Title);
  AStream.writeBuffer(PStr^, Header.TitleLen);
  PStr := PChar(theNode.Note);
  AStream.writebuffer(PStr^, Header.NoteLen);
  (* save index *)
  AStream.writebuffer(theNode.Index, sizeof(Integer));
end;
(* this is for reading a TNode *)
function readNode(AStream: TStream): TNode;
var
  header: THeader
  PStr: PChar;
begin
  AStream.ReadBuffer(Header, sizeof(TNodeHeader);
  SetLength(Result.Title, Header.TitleLen);
  PStr := PChar(Result.Title);
  AStream.ReadBuffer(PStr^, Header.TitleLen);
  SetLength(Result.Note, Header.NoteLen);
  PStr := PChar(Result.Note);
  AStream.ReadBuffer(PStr^, Header.NoteLen);
  AStream.ReadBuffer(REsult.Index, sizeof(Integer)(* 4 bytes *);
end;

Vous pouvez utiliser les fonctions disponible dans cet Open unité source .

Il vous permet de sérialiser tout contenu d'enregistrement en binaire, y compris les tableaux dynamiques, même à l'intérieur:

type
  TNote = record
    Title : string;
    Note  : string;
    Index : integer;
  end;

var
  aSave: TRawByteString;
  aNote, aNew: TNote;
begin
  // create some content
  aNote.Title := 'Title';
  aNote.Note := 'Note';
  aNote.Index := 10;
  // serialize the content
  aSave := RecordSave(aNote,TypeInfo(TNote));
  // unserialize the content
  RecordLoad(aNew,pointer(aSave),TypeInfo(TNote));
  // check the content
  assert(aNew.Title = 'Title');
  assert(aNew.Note = 'Note');
  assert(aNew.Index = 10);
end;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top