Saving strings to disk under Delphi 2009
-
05-07-2019 - |
Question
I have a structure like below that needs to be saved and loaded from disk.
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;
Until now I have used something like this to save the structure:
function
var F: FILE;
Hdr: RSecStructure;
begin
...
BlockWrite (F, Hdr, SizeOf(Hdr));
...
end
The above code worked under Delphi 7. Under D2009 I got a lot of warning messages when I make assignments between short and Unicode strings. Until now I managed to write Delphi code without having ANY compiler warnings or hints and I want to stay like that. So I need an elegant was to save strings (Unicode will be great but not critical) to disk without getting warnings.
Solution
Alternatively, you can declare storable short unicode string record and implement implicit 'to string' and 'from string' conversions.
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.
[The code above is released to public domain and carries no license obligations.]
OTHER TIPS
Those string fields are the same in Delphi 2009 as they were in all previous versions. ShortString
is not a Unicode type.
So you should be able to continue using that record as-is.
You say it worked in Delphi 7. Does it not work in Delphi 2009? Describe the problem you're having.
Do you mean to say that you want a fixed-length Unicode equivalent to ShortString
? There isn't one, so you can't have a record like that, have it hold string-like Unicode values, and save it directly to disk.
I don't think that's a major problem, though, since your disk format wouldn't be compatible with your current format anyway: your characters would be too big.
You can use an array of characters:
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;
That's not going to be quite as convenient as real string types, but it will work for most purposes.
You can also use a normal UnicodeString
type:
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;
You can't save that directly to disk anymore, but you're also no longer limited to 255 characters. You'll have to store each string field separately. Make sure to store the string's length, too, or you won't know where one string ends and the next begins when it comes time to load your file later.
You can keep existing structure (string[255]), existing file format and even correctly read non-unicode data previously saved by using the following:
before writing data:
...
record.Name:= UTF8EncodeToShortString(Name);
after reading data:
...
Name:= UTF8ToString(record.Name);