Сохранение строк на диск под Delphi 2009 - PullRequest
1 голос
/ 08 марта 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;

До сих пор я использовал что-то подобное для сохранения структуры:

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

Приведенный выше код работал в Delphi 7. В D2009 я получал много предупреждающих сообщений, когда выполняю назначения между короткими и Unicode-строками. До сих пор мне удавалось писать код Delphi без каких-либо предупреждений или подсказок компилятора, и я хочу оставаться таким. Поэтому мне нужно было элегантно сохранить строки (Unicode будет хорош, но не критичен) на диск без получения предупреждений.

Ответы [ 3 ]

8 голосов
/ 08 марта 2009

Эти строковые поля в Delphi 2009 такие же, как и во всех предыдущих версиях. ShortString не является типом Unicode.

Таким образом, вы сможете продолжить использовать эту запись как есть.

Вы говорите, что он работал в Delphi 7. Разве он не работает в Delphi 2009? Опишите проблему, с которой вы столкнулись.

Вы хотите сказать, что хотите Unicode фиксированной длины, эквивалентный ShortString? Такой записи нет, поэтому вы не можете иметь такую ​​запись, хранить в ней строковые значения Юникода и сохранять ее непосредственно на диск.

Однако я не думаю, что это серьезная проблема, поскольку формат вашего диска в любом случае не будет совместим с вашим текущим форматом: ваши символы будут слишком большими.

Вы можете использовать массив символов:

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;

Это будет не так удобно, как в случае с настоящими строковыми типами, но будет работать для большинства целей.

Вы также можете использовать обычный UnicodeString тип:

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;

Вы больше не можете сохранить это непосредственно на диск, но вы также больше не ограничены 255 символами. Вам придется хранить каждое строковое поле отдельно. Обязательно сохраните длину строки, иначе вы не будете знать, где заканчивается одна строка и начинается следующая, когда придет время загрузить файл позже.

6 голосов
/ 08 марта 2009

Кроме того, вы можете объявить сохраняемую короткую строковую запись в юникоде и реализовать неявные преобразования «в строку» и «из строки».

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.

[Вышеприведенный код является общедоступным и не несет никаких лицензионных обязательств.]

2 голосов
/ 27 ноября 2009

Вы можете сохранить существующую структуру (строка [255]), существующий формат файла и даже правильно читать данные, не записанные в Юникоде, ранее сохраненные с помощью следующего:

до записи данных:

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

после чтения данных:

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