Hallo,
hier 2 Units mit deren Hilfe Ansi-, UTF8- und Unicode-Strings gelesen
und geschrieben werden können. Das funktioniert für Delphi Versionen
mit und ohne Unicode-Unterstützung:
unit Kompat;
interface
TYPE
{$IFDEF UNICODE }
TString = String;
{$ELSE }
TString = WideString;
{$ENDIF }
implementation
end.
unit UniStream;
interface
USES
Kompat,
Classes;
TYPE
TTextStream = Class(TFileStream)
constructor Create(const FileName: String; Mode: Word);
destructor Destroy; override;
PROCEDURE ReadLn(VAR Line : TString);
PROCEDURE WriteStr(CONST Line : TString);
PROCEDURE WriteStrLF(CONST Line : TString);
PROCEDURE Reset;
Function EOF : Boolean;
Public
IOResult : Integer;
Header : AnsiString;
HasHeader : Boolean;
IsUniCode : Boolean;
DateiName : String;
Private
EndeErreicht : Boolean;
Geschrieben : Boolean;
MyPosition : Int64;
MySize : Int64;
AnsPuffer : Array[0..8192] Of AnsiChar;
UniPuffer : Array[0..8192] Of WideChar;
PROCEDURE WriteHeader;
END;
implementation
USES
SysUtils;
VAR
WLineEnd : Array[0..1] OF WideChar;
ALineEnd : Array[0..1] OF AnsiChar;
Constructor TTextStream.Create(const FileName: String; Mode: Word);
VAR
AnsZeichen1 : AnsiChar;
AnsZeichen2 : AnsiChar;
AnsZeichen3 : AnsiChar;
Gelesen : Integer;
BEGIN
Inherited Create(FileName, Mode);
DateiName := FileName;
EndeErreicht := FALSE;
IOResult := 0;
IsUniCode := FALSE;
HasHeader := FALSE;
Geschrieben := FALSE;
Header := '';
IF Mode = fmOpenRead THEN BEGIN
Gelesen := Read(AnsZeichen1, SizeOf(AnsiChar));
IF Gelesen = SizeOf(AnsiChar) THEN BEGIN
Gelesen := Read(AnsZeichen2, SizeOf(AnsiChar));
IF Gelesen = SizeOf(AnsiChar) THEN BEGIN
IF (Ord(AnsZeichen1) = 254) AND (Ord(AnsZeichen2) = 255) THEN BEGIN
IsUniCode := TRUE; // Big Endian
IOResult := 1006;
END
ELSE BEGIN
IF (Ord(AnsZeichen1) = 255) AND (Ord(AnsZeichen2) = 254) THEN
BEGIN
IsUniCode := TRUE; // Little Endian
END;
END;
END;
END;
IF IsUniCode = TRUE THEN BEGIN
HasHeader := TRUE;
Header := AnsZeichen1 + AnsZeichen2;
END
ELSE BEGIN
Gelesen := Read(AnsZeichen3, SizeOf(AnsiChar));
IF Gelesen = SizeOf(AnsiChar) THEN BEGIN
IF (Ord(AnsZeichen1) = 239) AND (Ord(AnsZeichen2) = 187) AND
(Ord(AnsZeichen3) = 191) THEN BEGIN
HasHeader := TRUE; // UTF 8
Header := AnsZeichen1 + AnsZeichen2 + AnsZeichen3;
END;
END;
END;
IF HasHeader = FALSE THEN
Seek(0, soFromBeginning);
MyPosition := Position;
MySize := Size;
END;
END;
PROCEDURE TTextStream.Reset;
BEGIN
EndeErreicht := FALSE;
IF HasHeader = FALSE THEN
Seek(0, soFromBeginning)
ELSE BEGIN
IF IsUniCode = TRUE THEN
Seek(2, soFromBeginning)
ELSE
Seek(3, soFromBeginning);
END;
MyPosition := Position;
MySize := Size;
END;
Destructor TTextStream.Destroy;
BEGIN
Inherited Destroy;
END;
PROCEDURE TTextStream.ReadLn(VAR Line : TString);
VAR
UniZeichen : WideChar;
AnsZeichen : AnsiChar;
Gelesen : Integer;
i : Integer;
BEGIN
i := 0;
IOResult := 0;
IF IsUniCode = TRUE THEN BEGIN
While MyPosition < MySize Do BEGIN
Gelesen := Read(UniZeichen, SizeOf(WideChar));
IF Gelesen <> SizeOf(WideChar) THEN BEGIN
IOResult := -1;
exit;
END;
INC(MyPosition, SizeOf(WideChar));
IF UniZeichen = WideChar(13) THEN BEGIN
IF MyPosition < MySize THEN BEGIN
Read(UniZeichen, SizeOf(WideChar));
IF UniZeichen <> WideChar(10) THEN
Seek(SizeOf(WideChar)*-1,soFromCurrent)
ELSE
INC(MyPosition, SizeOf(WideChar));
END;
Break;
END;
IF UniZeichen = WideChar(10) THEN BEGIN
Break;
END;
UniPuffer[i] := UniZeichen;
INC(i);
END;
UniPuffer[I] := WideChar(0);
Line := UniPuffer;
END
ELSE BEGIN
While MyPosition < MySize Do BEGIN
Gelesen := Read(AnsZeichen, SizeOf(AnsiChar));
IF Gelesen <> SizeOf(AnsiChar) THEN BEGIN
IOResult := -1;
exit;
END;
INC(MyPosition, SizeOf(AnsiChar));
IF AnsZeichen = AnsiChar(13) THEN BEGIN
IF MyPosition < MySize THEN BEGIN
Read(AnsZeichen, SizeOf(AnsiChar));
IF AnsZeichen <> AnsiChar(10) THEN
Seek(SizeOf(AnsiChar)*-1,soFromCurrent)
ELSE
INC(MyPosition, SizeOf(AnsiChar));
END;
Break;
END;
IF AnsZeichen = AnsiChar(10) THEN BEGIN
Break;
END;
AnsPuffer[i] := AnsZeichen;
INC(i);
END;
AnsPuffer[I] := AnsiChar(0);
AnsPuffer[I+1] := AnsiChar(0);
IF HasHeader = TRUE THEN BEGIN
IF I = 0 THEN
Line := ''
ELSE BEGIN
UTF8ToUnicode(Unipuffer,8000,Anspuffer,I); // Wenn I = 0 wird
kein Leerstring gespeichert
Line := TString(Unipuffer);
END;
END
ELSE
Line := TString(AnsPuffer);
END;
IF MyPosition >= MySize THEN
EndeErreicht := TRUE;
END;
Function TTextStream.EOF : Boolean;
BEGIN
Result := EndeErreicht;
END;
PROCEDURE TTextStream.WriteHeader;
BEGIN
IF HasHeader = TRUE THEN BEGIN
INHERITED Write(Header[1], SizeOf(AnsiChar));
INHERITED Write(Header[2], SizeOf(AnsiChar));
IF IsUniCode = FALSE THEN
INHERITED Write(Header[3], SizeOf(AnsiChar));
END;
Geschrieben := TRUE;
END;
PROCEDURE TTextStream.WriteStr(CONST Line : TString);
VAR
AnsLine : AnsiString;
UtfLine : UTF8String;
BEGIN
IF geschrieben = FALSE THEN
WriteHeader;
IF Length(Line) = 0 THEN
Exit;
IF IsUniCode = TRUE THEN
INHERITED Write(Line[1], Length(line)*SizeOF(WideChar))
ELSE BEGIN
IF HasHeader = TRUE THEN BEGIN
UtfLine := UTF8Encode(Line);
INHERITED Write(UtfLine[1], Length(UtfLine)*SizeOF(AnsiChar));
END
ELSE BEGIN
AnsLine := AnsiString(Line);
INHERITED Write(AnsLine[1], Length(AnsLine)*SizeOF(AnsiChar));
END;
END;
END;
PROCEDURE TTextStream.WriteStrLF(CONST Line : TString);
BEGIN
WriteStr(Line);
IF IsUniCode = TRUE THEN
INHERITED Write(WLineEnd, 2*SizeOF(WideChar))
ELSE
INHERITED Write(ALineEnd, 2*SizeOF(AnsiChar));
END;
INITIALIZATION
WLineEnd[0] := #13; WLineEnd[1] := #10;
ALineEnd[0] := #13; ALineEnd[1] := #10;
end.
Post by Matthias FreyHallo,
ich habe hier eine Datei die z.B. mit FF FE 5B 00 45 00
beginnt. Diese möchte ich in einen TStringStream laden und
zwar als Unicode.
Wie kann ich das tun? Bislang lade ich erst ein TFileStream
und kopiere dann mit CopyFrom den kompletten Inhalt.
Allerdings werden dann auch die 00 zu einem Zeichen.
Alternativ: wie kann ich die ganze Datei in einen
Unicode-String laden?
Matthias
---
Diese E-Mail ist frei von Viren und Malware, denn der avast! Antivirus Schutz ist aktiv.
http://www.avast.com