2009-08-29 7 views
2

Je cette méthode,Chaîne perte de données lors de l'attribution à TStringList

var 
s : TStringList; 
fVar : string; 
begin 
s := TStringList.Create; 
fVar := ZCompressStr('text'); 

ShowMessage(IntToStr(length(fVar) * SizeOf(Char))); 
//24 

s.text := fVar; 

ShowMessage(IntToStr(length(s.text) * SizeOf(Char))); 
//18 
end; 

Le ZCompressStr est de http://www.base2ti.com/zlib.htm avec la ligne 121 changé de {$ ifndef UNICODE} à {$ ifdef UNICODE} pour le rendre compiler.

De toute façon, je peux appeler ZDecompressStr si j'utilise la variable fVar, mais une fois que je l'ai déplacé vers une liste de cordes ou un mémo, il semble perdre ces 6 octets de données .... Si j'essaie d'utiliser ZDecompressStr sur le s.text var échoue avec une erreur de buffer.

+0

Pourquoi utilisez-vous une TStringList? – stukelly

+2

Si vous fournissez une description de ce que vous essayez d'accomplir, vous aurez plus de chances d'obtenir des réponses qui vous aideront à atteindre votre objectif. Par exemple, tstringlist n'est peut-être pas le meilleur outil (un tableau de chaînes pourrait être meilleur, par exemple) et certainement assigner à tstringlist.text peut causer une certaine confusion (la méthode tstringlist.add pourrait être ce que vous voulez). C'est difficile à dire, cependant, à partir de votre question. – Argalatyr

+0

La raison pour laquelle j'utilise un TStringList est parce que je veux enregistrer les données dans le fichier une fois que je l'ai compressé - et pour cela j'ai généralement toujours utilisé TStringList. Il semble que ce soit un non non avec lequel je m'en suis sorti mais avec D2009 il m'a rattrapé. – Wizzard

Répondre

2

Cela peut être la conversion - TStringList.Text propriété est une propriété, pas variable. Vous l'utilisez d'une manière un peu dangereuse, car il y a un traitement de texte dans TStringList.

+1

J'ai été déprimé. Ce serait bien de savoir ce qui n'allait pas avec ma réponse? – smok1

14

Il n'y a aucune raison que vous deviez modifier la ligne 121 de ZLibEx.pas; il est correct pour toutes les versions de Delphi, y compris Delphi 2009. Le symbole UNICODE devrait seulement être défini pour Delphi 2009, et quand il est, les définitions de type pour RawByteString, UnicodeString, et UnicodeChar devraient tous être ignorés, car ils sont déjà types intrinsèques dans la langue.

ZCompressStr génère une chaîne pouvant contenir des caractères non imprimables, y compris des octets nuls. Il stocke son résultat dans un RawByteString, que Delphi traite spécialement.

TStringList, comme à peu près tout le reste dans Delphi 2009, utilise Unicode. Sa propriété Text est du type UnicodeString. Lorsque vous affectez n'importe quelle valeur non UnicodeString à UnicodeString, vous obtenez une conversion, à partir de la fonction API MultiByteToWideStr. Même RawByteString est inclus dans cette règle. Si vous n'avez pas attribué de valeur de chaîne spécifique à une page de codes à un RawByteString, la page de codes 0, CP_ACP, est la page de code par défaut de votre système.

Si la chaîne ne contient pas vraiment de caractères codés conformément à la page de codes système, toute conversion demande des problèmes: garbage in, garbage out. En particulier, il n'y a aucune garantie que vous obtiendrez le même nombre de caractères.

As Smok1 mentioned, TStringList.Text est une propriété. Il a une méthode setter qui sépare la chaîne donnée en lignes séparées. Lorsque vous lisez la propriété, elle rejoint à nouveau toutes ces lignes dans une seule chaîne. Alors que mise la propriété, TStrings.SetTextStrClasses.pas, si vous êtes curieux) se partageront la ligne à tout événement de #0, #10 ou #13. C'est-à-dire, les caractères nuls, les sauts de ligne et les retours chariot. En rejoignant toutes les lignes, il utilisera sa propriété LineBreak, qui est initialisée avec la variable globale sLineBreak. Un saut de ligne est également placé après la dernière chaîne, donc chaque ligne se termine par LineBreak. Par conséquent, la conversion ne sera pas nécessairement aller-retour.

Donc, il y a deux choses à apprendre de cette:

  1. Ne pas traiter les données compressées sous forme de texte.
  2. N'utilisez pas les descendants TStrings pour stocker des objets dont vous ne souhaitez pas traiter plusieurs chaînes.

Un autre bon conseil: N'utilisez pas string comme type générique de stockage de données. Utilisez-le uniquement pour le texte réel. Pour le stockage de données binaires arbitraires, préférez TBytes ou TMemoryStream. En utilisant votre exemple, vous pouvez compresser une chaîne comme ceci:

var 
    ss: TStream; 
    ms: TMemoryStream; 
begin 
    ss := TStringStream.Create('text'); 
    try 
    ms := TMemoryStream.Create; 
    try 
     ShowMessage(IntToStr(ss.Size)); 
     ZCompressStream(ss, ms); 
     ShowMessage(IntToStr(ms.Size)); 
    finally 
     ms.Free; 
    end; 
    finally 
    ss.Free; 
    end; 
end; 
+0

Bon point. En fait TStringList est quit intelligent, donc peu importe si la fin-de-ligne de style DOS ou unix-style est utilisé. – smok1

+0

Merci Rob c'est une réponse fantastique. Votre premier paragraphe - oui, c'est étrange mais avez-vous téléchargé et essayé d'utiliser ce ZlibEx pour leur site Web, il ne compilerait tout simplement pas jusqu'à ce que j'ai changé cette ligne, voir aussi https://forums.embarcadero.com/thread.jspa?messageID = 130234 La réinitialisation de la réponse est absolument sur place. J'ai utilisé TStrlingList parce que je veux savetofile (que TMemoryStream peut faire) mais je vais vouloir POST ces données via un formulaire sur Internet. Je vais écrire ce petit peu et modifier ma question un peu. Merci! – Wizzard

Questions connexes