2016-04-26 103 views
2

我必須閱讀和修改一些JSON文件。文件編碼必須是沒有BOM的UTF8,否則JSON文件將不被接受。用Inno Setup創建一個沒有BOM的UTF8文件(Unicode版本)

我嘗試下面的代碼:

const 
    Utf8Bom  = #$EF#$BB#$BF; 
    Utf16BomLE = #$FF#$FE;     // little endian // 
    Utf16BomBE = #$FE#$FF;     // big endian // 
    Utf16Bom = Utf16BomBE; 
    CP_UTF16 = 1200; 
    CP_UTF8  = 65001; 

function WideStringToString (const wStr: string; codePage: Word): string; 
var 
    len: Integer; 
begin 
    len := WideCharToMultiByte (codePage, 0, wStr, -1, '', 0, 0, 0); 
    if len > 0 then 
    begin 
     SetLength (Result, len-1); 
     WideCharToMultiByte (codePage, 0, wStr, -1, Result, Length (Result), 0, 0); 
    end; 
end; 

function ClearBom(const s, sig: string): string; 
var 
    i, n, len: Integer; 
begin 
    Result := s; 
    len := Length (sig); 
    n := 0; 
    if (len> 0) and (Length (Result)> len) then 
     repeat 
      for i := 1 to len do 
       if Result [1] = sig [i] then 
       begin 
        Delete (Result, 1, 1); 
        Break; 
       end; 
      n := n + 1; 
     until (n = len) or (Result = ''); 
end; 

function ConvertUtf16(const SourceStr: string; codePage: Word): string; 
var 
    wStr: string; 
begin 
    try 
     wStr := ClearBom(SourceStr, Utf16Bom); 
     Result := WideStringToString(wStr, codePage); 
    finally 
     SetLength(wStr, 0); 
    end; 
end; 

function Utf16ToUtf8(const SourceStr: string): string; 
begin 
    Result := ConvertUtf16(SourceStr, CP_UTF8); 
end; 

function JSONSaveFile(const Filename: String; s: String): Boolean; 
var 
    fs: TFileStream; 
    i, len : Integer; 
begin 
    i := 1; 
    len := Length(s) 
    If len > 0 then 
    begin 
     try 
      try 
       fs := TFileStream.Create(Filename, fmCreate or f mShareExclusive); 
       fs.Seek(0, 0); 
       while (s[i] <> #0) and (i < len) do 
       begin 
        fs.WriteBuffer(s[i],CharLength(s,i)); 
        i := i + CharLength(s,i); 
       end; 
       Result := True; 
      except 
       Log('EXCEPTION RAISED in JSONSaveFile: '+Filename); 
      end; 
     finally 
      fs.free; 
     end; 
    end; 
end; 

我只能得到一個ANSI編碼的文件。像SaveStringsToUTF8File()函數這樣的內置函數將不起作用,導致默認添加BOM。

或者是一個更好的方式來保存/創建這個文本文件SaveStringToFile()

如何解決?

+0

你使用Unicode Inno Setup嗎? – Slappy

+0

是的。編輯標題。 thx – GruMu

回答

2

使用WideCharToMultiByte function將字符串轉換爲UTF-8,只是保存:

const 
    CP_UTF8 = 65001; 

function WideCharToMultiByte(CodePage: UINT; dwFlags: DWORD; 
    lpWideCharStr: string; cchWideChar: Integer; lpMultiByteStr: AnsiString; 
    cchMultiByte: Integer; lpDefaultCharFake: Integer; 
    lpUsedDefaultCharFake: Integer): Integer; 
    external '[email protected] stdcall'; 

function GetStringAsUtf8(S: string): AnsiString; 
var 
    Len: Integer; 
begin 
    Len := WideCharToMultiByte(CP_UTF8, 0, S, Length(S), Result, 0, 0, 0); 
    SetLength(Result, Len); 
    WideCharToMultiByte(CP_UTF8, 0, S, Length(S), Result, Len, 0, 0); 
end; 

function SaveStringToUTF8FileWithoutBOM(FileName: string; S: string): Boolean; 
var 
    Utf8: AnsiString; 
begin 
    Utf8 := GetStringAsUtf8(S); 
    Result := SaveStringToFile(FileName, Utf8, False); 
end; 

你必須使用創新安裝的Unicode版本。

+0

我現在注意到,我沒有將函數WideCharToMultiByte的代碼複製到我的問題代碼部分。 而不是「字符串」和「AnsiString」,我用PAnsiChar代替,所以它不能工作。 明天會檢查完整的新功能,所以我會在此之後報告。非常感謝您的幫助。 – GruMu

+1

效果很好。非常感謝你 ! – GruMu

+0

@Martin Prikryl它很適合「創建」一個新文件,但是如果我只想更改文件中的特定行,該怎麼辦? – Alanight