AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

INI ASCII/ANSI oder Unicode ?

Ein Thema von Bernd Nowak · begonnen am 14. Apr 2007 · letzter Beitrag vom 17. Apr 2007
Antwort Antwort
Bernd Nowak

Registriert seit: 18. Jan 2006
Ort: Duisburg
61 Beiträge
 
Turbo Delphi für Win32
 
#1

INI ASCII/ANSI oder Unicode ?

  Alt 14. Apr 2007, 13:54
Hallo alle,
gibt es einen Weg einfach festzustellen ob eine bestimmte/vorhandene Datei als ASCII/ANSI oder UTF Datei abgespeichert wurde ?
Ich habe ein kleines Programm geschrieben, das für ein älteres Programm einige Sachen prüft. Nun hat sich herausgestellt, das Leute a) eine INI Datei geöffnet, editiert und gespeichert haben und b) dann aus unerklärlichen Gründen UTF benutzt haben wodurch die INI Datei nicht mehr vom Programm zu gebrauchen war.
Habe schon ein bisschen gesucht aber noch nix gefunden. Habe mal mit Ultraedit 2 Dateien geöffnet die ich vorher mit Notepad als ANSI bzw. UTF gespeichert habe und Ultraedit erkennt es.
Im HEX Editor konnte ich sehen das bei der UTF Datei die ersten Stellen FF FE 64 00 beinhalten sowie nach(oder vor) jedem Zeichen ein 00 steht während in einer ANSI/ASCI Datei nur die einzelnen Zeichen zu finden sind.

Würde es reichen nur die ersten 2 Stellen auf FF und FE zu Testen ?
  Mit Zitat antworten Zitat
xaromz

Registriert seit: 18. Mär 2005
1.682 Beiträge
 
Delphi 2006 Enterprise
 
#2

Re: INI ASCII/ANSI oder Unicode ?

  Alt 14. Apr 2007, 14:08
Hallo,

kurz und schmerzlos: BOM.

Die Tnt-Controls (wie auch immer die inzwischen heißen) können damit übrigens automatisch umgehen.

Gruß
xaromz
I am a leaf on the wind - watch how I soar
  Mit Zitat antworten Zitat
bigg
(Gast)

n/a Beiträge
 
#3

Re: INI ASCII/ANSI oder Unicode ?

  Alt 14. Apr 2007, 14:25
Wenn du nur überprüfen möchtest, ob die Datei eine "normale" Text-Datei im ANSI-Format ist, kannst du die untere Funktion verwenden. Wenn du zusätzlich noch herrausfinden möchtest, welches Format exakt vorliegt, könntest du einen Blick in die SynUnicode.pas werfen. Dort gibt es eine Klasse namens TWideStringList mit der man auch Unicode verarbeiten kann.


Delphi-Quellcode:
////////////////////////////////////////////////////////////////////////////////
// Konstanten:
////////////////////////////////////////////////////////////////////////////////

const FILE_OPEN_FAILED = -2;
const FILE_NOT_FOUND = -1;
const FILE_IS_NOT_BINARY = 0;
const FILE_IS_BINARY = 1;

////////////////////////////////////////////////////////////////////////////////
// Dateien: Gibt die Größe einer Datei zurück (auch über 4 GB)
////////////////////////////////////////////////////////////////////////////////

function GetFileSize(const FileName: String): Int64;
var FileHandle: Cardinal;
    Data: WIN32_FIND_DATA;
begin
  Result := -1;
  
  FileHandle := FindFirstFile(PChar(FileName), Data);
  try

    if FileHandle > 0 then
    begin
      Int64Rec(Result).Hi := Data.nFileSizeHigh;
      Int64Rec(Result).Lo := Data.nFileSizeLow;
    end;
    
  finally
    Windows.FindClose(FileHandle);
  end;
end;

////////////////////////////////////////////////////////////////////////////////
// Dateien: Prüft, ob eine Datei binäre Zeichen enthält
////////////////////////////////////////////////////////////////////////////////

function IsBinaryFile(const FileName: String): Integer;
const MAX_BUFFER = 4096; // Clustergröße
      ValidControlChars: Set of Byte = [9, 10, 12, 13]; // typische Textsteuerzeichen

var Buffer: Array[1..MAX_BUFFER] of Byte;
    FilePosition, FileSize: Int64;
    FileHandle, FileBlocks, LastBlock, BufferSize: Integer;
    i, j: Integer;

begin
  Result := FILE_IS_NOT_BINARY;
  FilePosition := 0;

  if FileExists(FileName) then
  begin
    FileHandle := FileOpen(FileName, fmOpenRead or fmShareDenyNone);

    try
      if FileHandle > 0 then
      begin
        FileSize := GetFileSize(FileName); // Dateigröße in Byte ermittln
        FileBlocks := FileSize div MAX_BUFFER; // Anzahl max. Blöcke
        LastBlock := FileSize mod MAX_BUFFER; // Größe des Rest-Block

        // Letzten Block hinzufügen
        if LastBlock <> 0 then Inc(FileBlocks);

        // Blöcke einlesen
        for i := 0 to FileBlocks -1 do
        begin
          if Result = FILE_IS_BINARY then Break;

          // Aktuelle Dateiposition anpassen
          FileSeek(FileHandle, FilePosition, 0);
          Inc(FilePosition, MAX_BUFFER);

          if FilePosition <= FileSize then
          BufferSize := MAX_BUFFER else
          BufferSize := LastBlock;

          FileRead(FileHandle, Buffer[1], BufferSize);

          for j := 1 to BufferSize do
          begin

            if Buffer[j] < 32 then
            begin
              if not (Buffer[j] in ValidControlChars) then
              begin
                Result := FILE_IS_BINARY;
                Break;
              end;
            end;

          end; {\for: j}
        end; {\for: i}

      end
      else
        Result := FILE_OPEN_FAILED;

    finally
      FileClose(FileHandle);
    end;

  end
  else
    Result := FILE_NOT_FOUND;
end;
  Mit Zitat antworten Zitat
Bernd Nowak

Registriert seit: 18. Jan 2006
Ort: Duisburg
61 Beiträge
 
Turbo Delphi für Win32
 
#4

Re: INI ASCII/ANSI oder Unicode ?

  Alt 14. Apr 2007, 14:57
Danke !!!

Beide Ansätze sind nachvollziehbar. Werde erstmal den Code ausprobieren (ja, ja ich bin faul ). Wenn er das tut was ich benötige werde ich das Rad bestimmt nicht neu erfinden
  Mit Zitat antworten Zitat
Bernd Nowak

Registriert seit: 18. Jan 2006
Ort: Duisburg
61 Beiträge
 
Turbo Delphi für Win32
 
#5

Re: INI ASCII/ANSI oder Unicode ?

  Alt 17. Apr 2007, 08:59
Bin erst heute dazu gekommen den Code zu testen. Bei einer Text-Datei die im Ansi Format abgespeichert wurde bekomme ich 0 zurück. Bei der gleichen Datei als Unicode gespeichert bekomme ich 1 zurück. Gleiche Datei als UTF-8 bekomme ich 0 zurück.
Alles mit dem Code Beispiel von Bigg.

Habe bei Überprüfung des Thread Titels aber auch gemerkt das die Frage nicht ganz korrekt ist
Da ich nur Ansi gebrauchen kann und kein UTF/Unicode Werde mir mal das ganze genauer ansehen.
  Mit Zitat antworten Zitat
xaromz

Registriert seit: 18. Mär 2005
1.682 Beiträge
 
Delphi 2006 Enterprise
 
#6

Re: INI ASCII/ANSI oder Unicode ?

  Alt 17. Apr 2007, 09:18
Hallo,
Zitat von Bernd Nowak:
Bei der gleichen Datei als Unicode gespeichert bekomme ich 1 zurück. Gleiche Datei als UTF-8 bekomme ich 0 zurück.
Das ist nicht verwunderlich. Da die Funktion nur testet, ob ein Byte der Datei außerhalb des gültigen Bereichs liegt, kommt es auf die verwendeten Zeichen in der Datei an, ob das Ergebnis stimmt oder nicht. Je nach Zeichen liegt die Codierung nämlich innerhalb oder außerhalb dieses Bereichs.

Gruß
xaromz
I am a leaf on the wind - watch how I soar
  Mit Zitat antworten Zitat
Bernd Nowak

Registriert seit: 18. Jan 2006
Ort: Duisburg
61 Beiträge
 
Turbo Delphi für Win32
 
#7

Re: INI ASCII/ANSI oder Unicode ?

  Alt 17. Apr 2007, 09:35
Da ich mir die Text Datei im HEX Editor angesehen habe würde es also reichen am Anfang der Datei zu prüfen:

EF BB (BF) => UTF 8
FE FF, FF FE, 00 00 FE FF => auch nicht ANSI ( )

Oder sehe ich das Falsch ?

Ich habe in meinem Programm schon einen Byte Check. Der prüft aber nur eine Stelle (zb. Offset: 0 EF). Könnte ich auch gleich Offset 0 EF BB prüfen ?

Delphi-Quellcode:
function checkpatchuneven(exefile: string;offset: Integer; svalue: string):string;
  var
  // p: string;
  Ft: file;
  tmp: byte;

  begin
      //showmessage('File to check: '+exefile);
      //showmessage('Offset to check: '+offset);
      //showmessage('Value to check: '+svalue);
      Assignfile(Ft, exefile);
      FileMode := 0; //Read Only
      Reset(Ft, 1);
      Seek(Ft, offset);
      blockread(Ft, tmp, Sizeof(tmp)); //Temp is the result in decimal number and Sizeof is the just the size of the number.
      closefile(Ft);
        if IntToHex(tmp,2)<> svalue then
          begin
          //showmessage('Active');
          Result := 'Activated';
          end
          else begin
          //showmessage('Not Active');
          Result := 'Not Activated';
        end;
end;
Bernd
  Mit Zitat antworten Zitat
xaromz

Registriert seit: 18. Mär 2005
1.682 Beiträge
 
Delphi 2006 Enterprise
 
#8

Re: INI ASCII/ANSI oder Unicode ?

  Alt 17. Apr 2007, 10:18
Hallo,

folgende Routine verwende ich (stammt von den TntUnicode-Controls):
Delphi-Quellcode:
type
  TStreamCharSet = (csAnsi, csUnicode, csUnicodeSwapped, csUtf8);

const
  UNICODE_BOM = WideChar($FEFF);
  UNICODE_BOM_SWAPPED = WideChar($FFFE);
  UTF8_BOM = AnsiString(#$EF#$BB#$BF);

function DetectCharacterSet(const Stream: TStream): TStreamCharSet;
var
  ByteOrderMark: WideChar;
  BytesRead: Integer;
  Utf8Test: array[0..2] of AnsiChar;
begin
  // Byte Order Mark
  ByteOrderMark := #0;
  if (Stream.Size - Stream.Position) >= SizeOf(ByteOrderMark) then
  begin
    BytesRead := Stream.Read(ByteOrderMark, SizeOf(ByteOrderMark));
    if (ByteOrderMark <> UNICODE_BOM) and (ByteOrderMark <> UNICODE_BOM_SWAPPED) then
    begin
      ByteOrderMark := #0;
      Stream.Seek(-BytesRead, soFromCurrent);
      if (Stream.Size - Stream.Position) >= Length(Utf8Test) * SizeOf(AnsiChar) then
      begin
        BytesRead := Stream.Read(Utf8Test[0], Length(Utf8Test) * SizeOf(AnsiChar));
        if Utf8Test <> UTF8_BOM then
          Stream.Seek(-BytesRead, soFromCurrent);
      end;
    end;
  end;

  if ByteOrderMark = UNICODE_BOM then
    Result := csUnicode
  else
    if ByteOrderMark = UNICODE_BOM_SWAPPED then
      Result := csUnicodeSwapped
    else
      if Utf8Test = UTF8_BOM then
        Result := csUtf8
      else
        Result := csAnsi;
end;
Eine komplette Datei lesen kannst Du so:
Delphi-Quellcode:
procedure StrSwapByteOrder(Str: PWideChar);
var
  P: PWord;
begin
  P := PWord(Str);
  while (P^ <> 0) do
  begin
    P^ := MakeWord(HiByte(P^), LoByte(P^));
    Inc(P);
  end;
end;

function ReadFile(const FileName: WideString): WideString;
var
  Stream: TStream;
  DataLeft: Integer;
  StreamCharSet: TStreamCharSet;
  SW: WideString;
  SA: AnsiString;
begin
  SW := '';
  Stream := TFileStream.Create(FileName, fmOpenRead);
  try
    StreamCharSet := DetectCharacterSet(Stream);

    DataLeft := Stream.Size - Stream.Position;

    case StreamCharSet of
      csAnsi:
      begin
        SetLength(SA, DataLeft div SizeOf(AnsiChar));
        Stream.Read(PAnsiChar(SA)^, DataLeft);
        SW := SA;
      end;

      csUnicode, csUnicodeSwapped:
      begin
        if DataLeft < SizeOf(WideChar) then
          SW := ''
        else
        begin
          SetLength(SW, DataLeft div SizeOf(WideChar));
          Stream.Read(PWideChar(SW)^, DataLeft);
          if StreamCharSet = csUnicodeSwapped then
            StrSwapByteOrder(PWideChar(SW));
        end;
      end;

      csUtf8:
      begin
        SetLength(SA, DataLeft div SizeOf(AnsiChar));
        Stream.Read(PAnsiChar(SA)^, DataLeft);
        SW := UTF8Decode(SA);
      end;
    end;
  finally
    Stream.Free;
  end;
  Result := SW;
end;
Diese Funktion liefert Dir einen WideString mit dem Dateiinhalt bzw. einen Leerstring bei einem Fehler.

Gruß
xaromz
I am a leaf on the wind - watch how I soar
  Mit Zitat antworten Zitat
Bernd Nowak

Registriert seit: 18. Jan 2006
Ort: Duisburg
61 Beiträge
 
Turbo Delphi für Win32
 
#9

Re: INI ASCII/ANSI oder Unicode ?

  Alt 17. Apr 2007, 11:48
Vielen Dank ! Falls ich noch Fragen dazu habe werde ich wieder melden Habe jetzt nämlich ein anderes Problem
  Mit Zitat antworten Zitat
bigg
(Gast)

n/a Beiträge
 
#10

Re: INI ASCII/ANSI oder Unicode ?

  Alt 17. Apr 2007, 16:41
Wenn die Funktion IsBinaryFile() = 0 liefert, ist die Datei im ANSI-Format.
Eine solche Datei sollte sich dann problemlos im Texteditor anzeigen lassen.

Hat der Benutzer allerdings das Zeilenumbruchformat verstellt z.B. auf LF (UNIX),
dann sieht es im Notepad natürlich nicht grade leserlich aus.


edit: Ich sehe grad, die Funktion liefert, wie von Bernd geschrieben bei UTF8 kodierten Dateien nicht das gewüntschte Ergebnis. Vielleicht solltest du dann lieber auf die SynUnicode.pas zurückgreifen. Dort sind Funktionen enthalten, die das exakt feststellen können.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:09 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz