6
votes

(Large) String - Stockage dans TfileStream, Delphi 7. Quel est le moyen le plus rapide?

J'utilise Delphi7 (non-Unicode VCL), j'ai besoin de stocker de nombreuses personnes à l'intérieur d'un TfileStream. Je ne peux pas utiliser TstringStream car les chaînes (larges) sont mélangées à des données binaires, le format est prévu pour accélérer le chargement et l'écriture des données ... Cependant, je crois que la voie actuelle que je charge / écriture des chaînes pourrait être un goulot d'étranglement de mon code ...

Actuellement, j'écris la longueur d'une chaîne, puis écrivez-la de ... Lors du chargement, je charge d'abord la longueur, puis chargez de chargement de ...

Donc, quel est le moyen le plus rapide de sauvegarder et de charger les wlandstring à TfileStream?

Merci d'avance


4 commentaires

Changer une zone particulière de votre code parce que vous croyez Ce pourrait être le goulot d'étranglement peut être une énorme perte de temps. Vous devriez mesurer en premier, il y a beaucoup d'outils pour vous aider là-bas, d'un peu de publicité. Essayez-les d'abord pour certains liens: Stackoverflow.com/Questions/291631/... et Stackoverflow.com/questions/368938/Delphi-profiling- Outils


Merci, mais j'utilisais QueryPerformancecounter pour détecter ça;) Quoi qu'il en soit, c'était le goulot d'étranglement, car la lecture de Char est très lente ... toutes les autres opérations ne faisaient que gagner de courtes données binaires.


Ah ok. Je venais de réagir sur votre utilisation des mots "croire" et "pourrait", désolé alors pour la prédication ;-)


Vous êtes le bienvenu, j'ai probablement mal utilisé ces mots, mon anglais est très pauvre;)


4 Réponses :


6
votes

plutôt que de lire et d'écrire un personnage à la fois, lisez-les et écrivez-les tous à la fois: xxx

maintenant, techniquement, puisque windestring est une fenêtre est une fenêtre Code> BSTR , il peut contenir un nombre impair d'octets. La fonction lit le nombre d'octets et divise par deux, il est donc possible (bien que peu probable) que le code ci-dessus puisse couper le dernier octet. Vous pouvez utiliser ce code à la place: xxx

inspiré par La réponse de Mghie , ont remplacé mon lire et écriture appels avec Readbuffer et Writebuffer . Ce dernier augmentera des exceptions si elles ne sont pas en mesure de lire ou d'écrire le nombre demandé d'octets.


7 commentaires

Votre deuxième wristwidestring () ne compile pas (manquante tycaire à pwidechar, paren manquant), mais plus important encore, il échoue pour les chaînes vides. Votre deuxième readwidestring () doit également vérifier la longueur 0 et renvoyer simplement une chaîne vide dans ce cas.


Je ne vois aucune raison pour laquelle cela ne fonctionnerait pas pour les chaînes vides; systringbytelen retourne zéro pour les pointeurs NULL. L'exigence de tapir à pwidechar est que systringbytelen est erroné pour prendre un pwidechar au lieu de widstring , ou bstr est malédé à être pwidechar au lieu de widstring . Néanmoins, j'ai réparé cela et j'ai également abordé vos autres préoccupations. Merci.


Je a fait une raison pour laquelle il pourrait échouer pour des cordes n'ayant qu'un octet, cependant. Avec la vérification de la plage activée, l'expression ws [1] devrait échouer dans ce cas. (Delphi QC Bug 9425 et le bug Pascal gratuit 0010013 affectent si cela échoue sur une version particulière.)


J'ai essayé votre code avec une chaîne vide, dans Delphi 4 et Delphi 2009, et sur une valeur négative (code d'erreur) a été renvoyée. Ceci est sur Windows XP 64.


Essayez Type-Casting vers Pointer et n'hésitez pas à modifier et à corriger cette réponse si cela fonctionne. Je n'ai pas de Delphi à portée de main pour le tester moi-même. Je vais juste sortir de ce que dit MSDN.


Bonne prise. systringbytelen est en effet déclaré pour prendre un pwidechar , et le type de moulage alimente un pointeur sur une chaîne large vide avec une longueur de faux - elle devrait être 0 mais n'est pas. C'est la valeur négative que j'ai vue dans mes tests. L'utilisation d'un point de signalisation fonctionne comme prévu et j'ai édité en conséquence. Merci pour le commentaire.


Support de fermeture manquante sur Stream.writbuffer (Nchars, Taillef (Nchars);



6
votes

Il n'y a rien de spécial à propos des chaînes larges, de lire et d'écrire aussi vite que possible que possible, vous devez lire et écrire autant que possible en une fois:

procedure TForm1.Button1Click(Sender: TObject);
var
  Str: TStream;
  W, W2: WideString;
  L: integer;
begin
  W := 'foo bar baz';

  Str := TFileStream.Create('test.bin', fmCreate);
  try
    // write WideString
    L := Length(W);
    Str.WriteBuffer(L, SizeOf(integer));
    if L > 0 then
      Str.WriteBuffer(W[1], L * SizeOf(WideChar));

    Str.Seek(0, soFromBeginning);
    // read back WideString
    Str.ReadBuffer(L, SizeOf(integer));
    if L > 0 then begin
      SetLength(W2, L);
      Str.ReadBuffer(W2[1], L * SizeOf(WideChar));
    end else
      W2 := '';
    Assert(W = W2);
  finally
    Str.Free;
  end;
end;


0 commentaires

2
votes

Les widssers contiennent une «chaîne» de Widecharar, qui utilisent 2 octets chacun. Si vous souhaitez stocker les chaînes UTF-16 (utilisez les withestrings en interne) dans un fichier et que vous pouvez utiliser ce fichier dans d'autres programmes tels que le Bloc-notes, vous devez écrire un Mark d'octet premier: # $ feff .

Si vous le savez, l'écriture peut ressembler à ceci: xxx

lecture peut ressembler à ceci: xxx


2 commentaires

Il a dit qu'il veut stocker de nombreuses chaînes, ils vont être mélangés avec des données binaires et elles seront préfixées par leurs longueurs. Certainement pas quelque chose à utiliser avec le bloc-notes. Votre code consacre tout le flux à une seule chaîne.


CODE L'accès inconditionnel accédant au premier élément d'une chaîne vide entraînera des violations d'accès.



1
votes

Vous pouvez également utiliser TFASTFileStream pour la lecture des données ou des chaînes, j'ai collé l'unité à http://pastebin.com/ m6ecdc8c2 et un échantillon ci-dessous: xxx


2 commentaires

Remarque: ce code ne fonctionnera pas si la chaîne à lire contient des caractères NULL.


CODE L'accès inconditionnel accédant au premier élément d'une chaîne vide entraînera des violations d'accès.