TStringlist 未加载 Google 联系人文件
TStringlist not loading Google Contacts file
我正在尝试使用 Stringlist 加载由 Google 联系人生成的 CSV 文件。当我在像 Sublime Text 这样的文本编辑器中打开这个文件时,我可以正确地看到内容,有 75 行。这是来自 Google 联系人文件的示例:
Name,Given Name,Additional Name,Family Name,Yomi Name,Given Name Yomi,Additional Name Yomi,Family Name Yomi,Name Prefix,Name Suffix,Initials,Nickname,Short Name,Maiden Name,Birthday,Gender,Location,Billing Information,Directory Server,Mileage,Occupation,Hobby,Sensitivity,Priority,Subject,Notes,Group Membership,Phone 1 - Type,Phone 1 - Value,Phone 2 - Type,Phone 2 - Value,Phone 3 - Type,Phone 3 - Value
H,H,,,,,,,,,,,,, 1-01-01,,,,,,,,,,,,* My Contacts ::: Importado 01/02/16,,,,,,
H - ?,H,-,?,,,,,,,,,,, 1-01-01,,,,,,,,,,,,* My Contacts ::: Importado 01/02/16,Mobile,031-863-64393,,,,
H - ?,H,-,?,,,,,,,,,,,,,,,,,,,,,,,* My Contacts ::: Importado 01/02/16,Mobile,031-986-364393,,,,
但是当我尝试使用 Stringlist 加载同一个文件时,这就是我在 Stringlist.text 属性 中看到的内容:
'ÿþN'#$D#$A
这是我的代码:
procedure Tform1.loadfile;
var sl : tstringlist;
begin
sl := tstringlist.create;
sl.loadfromfile('c:\google.csv');
showmessage('lines : '+inttostr(sl.count)+' / text : '+ sl.text);
end;
这是我得到的结果:
'1 / 'ÿþN'#$D#$A'
这里发生了什么?
谢谢
根据您提供的十六进制转储,BOM 表明您的文件是使用 UTF-16LE 编码的。摆在你面前的几个选项,如我所见:
- 切换到 Unicode 并使用 TnT Unicode 控件处理此文件。
- 以字节数组形式读取文件。转换为 ANSI,然后继续使用 ANSI 编码的文本。显然,您将丢失任何字符的信息,而不是您的 ANSI 代码页无法编码的字符。一种廉价的方法是将文件作为字节数组读取。将前两个字节BOM之后的内容复制到
WideString
中。然后将 WideString
分配给 ANSI string
.
- 将您的程序移植到 Delphi 的 Unicode 版本(任何晚于 Delphi 2007 的版本)并在本地使用 Unicode。
我怀疑你对文本编码不是很熟悉。如果你是那么我想你就可以自己回答这个问题了。这很好,但我敦促你花时间正确地了解这个问题。如果你现在急于编码,在没有良好的基础之前,你肯定会把它弄得一团糟。我们已经看到很多人犯了同样的错误。请不要添加到文本编码伤亡列表中。
感谢大卫的信息,我可以使用下面的函数完成任务;因为Delphi2007不支持unicode,所以需要第三方函数才可以。
procedure loadUnicodeFile( const filename: String; strings: TStringList);
Procedure SwapWideChars( p: PWideChar );
Begin
While p^ <> #0000 Do Begin
// p^ := Swap( p^ ); //<<< D3
p^ := WideChar( Swap( Word(p^)));
Inc( p );
End; { While }
End; { SwapWideChars }
Var
ms: TMemoryStream;
wc: WideChar;
pWc: PWideChar;
Begin
ms:= TMemoryStream.Create;
try
ms.LoadFromFile( filename );
ms.Seek( 0, soFromend );
wc := #0000;
ms.Write( wc, sizeof(wc));
pWC := ms.Memory;
If pWc^ = #$FEFF Then // normal byte order mark
Inc(pWc)
Else If pWc^ = #$FFFE Then Begin // byte order is big-endian
SwapWideChars( pWc );
Inc( pWc );
End { If }
Else; // no byte order mark
strings.Text := WideChartoString( pWc );
finally
ms.free;
end;
End;
我正在尝试使用 Stringlist 加载由 Google 联系人生成的 CSV 文件。当我在像 Sublime Text 这样的文本编辑器中打开这个文件时,我可以正确地看到内容,有 75 行。这是来自 Google 联系人文件的示例:
Name,Given Name,Additional Name,Family Name,Yomi Name,Given Name Yomi,Additional Name Yomi,Family Name Yomi,Name Prefix,Name Suffix,Initials,Nickname,Short Name,Maiden Name,Birthday,Gender,Location,Billing Information,Directory Server,Mileage,Occupation,Hobby,Sensitivity,Priority,Subject,Notes,Group Membership,Phone 1 - Type,Phone 1 - Value,Phone 2 - Type,Phone 2 - Value,Phone 3 - Type,Phone 3 - Value
H,H,,,,,,,,,,,,, 1-01-01,,,,,,,,,,,,* My Contacts ::: Importado 01/02/16,,,,,,
H - ?,H,-,?,,,,,,,,,,, 1-01-01,,,,,,,,,,,,* My Contacts ::: Importado 01/02/16,Mobile,031-863-64393,,,,
H - ?,H,-,?,,,,,,,,,,,,,,,,,,,,,,,* My Contacts ::: Importado 01/02/16,Mobile,031-986-364393,,,,
但是当我尝试使用 Stringlist 加载同一个文件时,这就是我在 Stringlist.text 属性 中看到的内容:
'ÿþN'#$D#$A
这是我的代码:
procedure Tform1.loadfile;
var sl : tstringlist;
begin
sl := tstringlist.create;
sl.loadfromfile('c:\google.csv');
showmessage('lines : '+inttostr(sl.count)+' / text : '+ sl.text);
end;
这是我得到的结果:
'1 / 'ÿþN'#$D#$A'
这里发生了什么?
谢谢
根据您提供的十六进制转储,BOM 表明您的文件是使用 UTF-16LE 编码的。摆在你面前的几个选项,如我所见:
- 切换到 Unicode 并使用 TnT Unicode 控件处理此文件。
- 以字节数组形式读取文件。转换为 ANSI,然后继续使用 ANSI 编码的文本。显然,您将丢失任何字符的信息,而不是您的 ANSI 代码页无法编码的字符。一种廉价的方法是将文件作为字节数组读取。将前两个字节BOM之后的内容复制到
WideString
中。然后将WideString
分配给 ANSIstring
. - 将您的程序移植到 Delphi 的 Unicode 版本(任何晚于 Delphi 2007 的版本)并在本地使用 Unicode。
我怀疑你对文本编码不是很熟悉。如果你是那么我想你就可以自己回答这个问题了。这很好,但我敦促你花时间正确地了解这个问题。如果你现在急于编码,在没有良好的基础之前,你肯定会把它弄得一团糟。我们已经看到很多人犯了同样的错误。请不要添加到文本编码伤亡列表中。
感谢大卫的信息,我可以使用下面的函数完成任务;因为Delphi2007不支持unicode,所以需要第三方函数才可以。
procedure loadUnicodeFile( const filename: String; strings: TStringList);
Procedure SwapWideChars( p: PWideChar );
Begin
While p^ <> #0000 Do Begin
// p^ := Swap( p^ ); //<<< D3
p^ := WideChar( Swap( Word(p^)));
Inc( p );
End; { While }
End; { SwapWideChars }
Var
ms: TMemoryStream;
wc: WideChar;
pWc: PWideChar;
Begin
ms:= TMemoryStream.Create;
try
ms.LoadFromFile( filename );
ms.Seek( 0, soFromend );
wc := #0000;
ms.Write( wc, sizeof(wc));
pWC := ms.Memory;
If pWc^ = #$FEFF Then // normal byte order mark
Inc(pWc)
Else If pWc^ = #$FFFE Then Begin // byte order is big-endian
SwapWideChars( pWc );
Inc( pWc );
End { If }
Else; // no byte order mark
strings.Text := WideChartoString( pWc );
finally
ms.free;
end;
End;