2009-03-07 10 views
1

J'ai une structure comme ci-dessous qui doit être sauvegardée et chargée à partir du disque.Enregistrement des chaînes sur le disque sous Delphi 2009

RSecStructure= packed record 
    Name    : string[255];  {NEED UNICODE SUPPORT HERE} 
    ScreenName   : string[255]; 
    OrigFileName  : string[255];      
    Prim    : string[255];           
    ParentVersion  : integer; 
    sTag1    : string[255];  
    sTag2    : string[255]; 
    sTag3    : string[255]; 
    sTag4    : string[255]; 
    DateAdd   : TDateTime; 
    DateModify   : TDateTime; 
    end; 

Jusqu'à présent, j'ai utilisé quelque chose comme ça pour sauver la structure:

function 
var F: FILE; 
    Hdr: RSecStructure; 
begin 
... 
BlockWrite (F, Hdr, SizeOf(Hdr)); 
... 
end 

Le code ci-dessus a travaillé sous Delphi 7. Sous D2009 j'ai eu beaucoup de messages d'avertissement quand je fais des missions entre court et les chaînes Unicode. Jusqu'à présent, j'ai réussi à écrire du code Delphi sans avoir d'avertissements ou d'astuces du compilateur et je veux rester comme ça. J'ai donc besoin d'un élégant pour enregistrer des chaînes (Unicode sera génial mais pas critique) sur le disque sans avoir d'avertissements.

Répondre

6

Vous pouvez également déclarer un enregistrement de chaîne unicode court pouvant être stocké et implémenter des conversions implicites 'to string' et 'from string'.

program TestShortUnicodeString; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils; 

type 
    TShortUnicodeString = record 
    private 
    Data: array [0..255] of char; //WARNING - NOT initialized to an empty string 
    public 
    class operator Implicit(const sus: TShortUnicodeString): string; inline; 
    class operator Implicit(const ws: string): TShortUnicodeString; inline; 
    end; 

class operator TShortUnicodeString.Implicit(const sus: TShortUnicodeString): string; 
begin 
    Result := StrPas(sus.Data); 
end; 

class operator TShortUnicodeString.Implicit(const ws: string): TShortUnicodeString; 
begin 
    // too long strings are silently truncated 
    StrPLCopy(Result.Data, ws, Length(Result.Data)-1); 
end; 

type 
    TTestRec = record 
    ws1: TShortUnicodeString; 
    ws2: TShortUnicodeString; 
    end; 

var 
    f : file; 
    test1: TTestRec; 
    test2: TTestRec; 

begin 
    test1.ws1 := '6*9 ='; 
    test1.ws2 := ' 42'; 
    AssignFile(f, 'test.dat'); 
    Rewrite(f, 1); 
    BlockWrite(f, test1, SizeOf(test1)); 
    CloseFile(f); 
    AssignFile(f, 'test.dat'); 
    Reset(f, 1); 
    Assert(FileSize(f) = SizeOf(test2)); 
    BlockRead(f, test2, SizeOf(test2)); 
    CloseFile(f); 
    Writeln(string(test2.ws1), string(test2.ws2)); 
    Readln; 
end. 

[Le code ci-dessus est publié dans le domaine public et ne comporte aucune obligation de licence.]

+0

Est-il possible d'écrire quelque chose comme 'TShortUnicodeString = enregistrement' analogue à' chaîne [N] '(je n'ai pas de D2010 pour le tester.) –

8

Ces champs de chaîne sont les mêmes dans Delphi 2009 que dans toutes les versions précédentes. ShortString n'est pas un type Unicode.

Vous devriez donc pouvoir continuer à utiliser cet enregistrement tel quel.

Vous dites que cela a fonctionné dans Delphi 7. Est-ce que pas fonctionne dans Delphi 2009? Décrivez le problème que vous rencontrez. Voulez-vous dire que vous voulez un équivalent Unicode de longueur fixe ShortString? Il n'y en a pas, donc vous ne pouvez pas avoir un enregistrement comme ça, avoir des valeurs Unicode en forme de chaîne et l'enregistrer directement sur le disque.

Je ne pense pas que ce soit un problème majeur, cependant, puisque votre format de disque ne serait pas compatible avec votre format actuel: vos personnages seraient trop grands.

Vous pouvez utiliser un tableau de caractères:

type 
    TSecStructure = packed record 
    Name    : array[0..255] of UnicodeChar; 
    ScreenName   : array[0..255] of UnicodeChar; 
    OrigFileName  : array[0..255] of UnicodeChar; 
    Prim    : array[0..255] of UnicodeChar; 
    ParentVersion  : integer; 
    sTag1    : array[0..255] of UnicodeChar; 
    sTag2    : array[0..255] of UnicodeChar; 
    sTag3    : array[0..255] of UnicodeChar; 
    sTag4    : array[0..255] of UnicodeChar; 
    DateAdd   : TDateTime; 
    DateModify   : TDateTime; 
    end; 

Ce ne va pas être aussi pratique que les types réels de chaîne, mais cela fonctionnera pour la plupart des cas.

Vous pouvez également utiliser un type UnicodeString normal:

type 
    TSecStructure = record 
    Name    : UnicodeString; 
    ScreenName   : UnicodeString; 
    OrigFileName  : UnicodeString; 
    Prim    : UnicodeString; 
    ParentVersion  : integer; 
    sTag1    : UnicodeString; 
    sTag2    : UnicodeString; 
    sTag3    : UnicodeString; 
    sTag4    : UnicodeString; 
    DateAdd   : TDateTime; 
    DateModify   : TDateTime; 
    end; 

Vous ne pouvez pas enregistrer plus que directement sur le disque, mais vous êtes également plus limité à 255 caractères. Vous devrez stocker chaque champ de chaîne séparément. Assurez-vous de stocker la longueur de la chaîne, ou vous ne saurez pas où une chaîne se termine et la prochaine commence quand il vient le temps de charger votre fichier plus tard.

+0

> array [0..255] de UnicodeChar; Je pense que ça va le faire. Merci beaucoup. – Ampere

+0

Cela double la taille de stockage pour les caractères ASCII. Au lieu de cela, vous pouvez utiliser ShortString et stocker des chaînes UTF8 (UTF8Encode, UTF8ToString) –

+0

> Cela double la taille de stockage pour les caractères ASCII. C'est très bien. Merci. – Ampere

2

Vous pouvez conserver la structure existante (string [255]), le format de fichier existant et même lire correctement les données non-unicode enregistrées précédemment en utilisant les éléments suivants:

avant l'écriture des données:

... 
record.Name:= UTF8EncodeToShortString(Name); 

après lecture des données:

... 
Name:= UTF8ToString(record.Name); 
Questions connexes