2009-03-07 3 views
1

У меня есть структура, как показано ниже, которая должна быть сохранена и загружена с диска.Сохранение строк на диск в 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; 

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

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

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

ответ

6

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

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. 

[Код высвобождается в свободном доступе и не имеет лицензионных обязательств.]

+0

Можно ли написать что-то вроде 'TShortUnicodeString = record' analog to' string [N] '(у меня нет D2010 для его проверки). –

8

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

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

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

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

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

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

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 символов. Вам нужно будет хранить каждое поле строки отдельно. Обязательно сохраните длину строки, или вы не узнаете, где заканчивается одна строка, а затем начинается, когда приходит время для загрузки вашего файла позже.

+0

> массив [0..255] of UnicodeChar; Я думаю, что это будет сделано. Большое спасибо. – Ampere

+0

Это удваивает размер хранилища для символов ASCII. Вместо этого вы можете использовать ShortString и хранить в нем строки UTF8 (UTF8Encode, UTF8ToString) –

+0

> Это удваивает размер хранилища для символов ASCII. Это прекрасно. Благодарю. – Ampere

2

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

перед записью данных:

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

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

... 
Name:= UTF8ToString(record.Name); 
Смежные вопросы