读取Ini文件到Stringlist中出现空格问题

5

我正在使用inifile存储数值,用于替换文件中的其他数值,例如将A替换为B,A=B这个过程很顺利。但是,如果在值B之前有一个空格,当读取时它会被忽略,例如A= B仍然被读入为'B'而不是' B'。有没有人知道如何解决这个问题?我正在使用Delphi 7,因此无法使用StrictDelimiter选项。

procedure ReadIntoVList(const aSection:string;AValueList:TValueListEditor);
var
  IniFile:TIniFile;
  SL: TStringList;
  i: Integer;
begin
   SL := TStringList.Create;
   IniFile := TIniFile.Create(ChangeFileExt(Application.Exename, '.ini'));
   try
     IniFile.ReadSectionValues(ASection, SL);
     AvalueList.Strings.AddStrings(SL);
   finally
     StampIniFile.Free;
     SL.Free;
   end;
end;

Thanks

Colin


Delphi中一个应该被记录的讨厌功能。嘿!这听起来正是“bug”的定义(“bug是未记录的功能”):) - Gabriel
3个回答

7
TIniFile.ReadSectionValues最终使用Windows API函数GetPrivateProfileString从ini文件中读取键值。GetPrivateProfileString将删除任何前导和尾随空格以及字符串周围的任何引号。这意味着行
[ key = value1 value2 value3 ]
将返回与行
[ key=value1 value2 value3 ]
相同的值(添加方括号以显示额外的空格)。
为了保留任何前导和尾随空格,您必须在写入它们回ini时用单引号或双引号括起来。
由于GetPrivateProfileString会删除任何周围的引号(单引号或双引号),因此在从ini文件中读取值时不需要删除它们。
要添加引号,您不应该使用AnsiQuotedStr函数,因为它会添加周围的双引号,但它也会加倍任何已经在字符串中的双引号。虽然这是当您随后使用AnsiDequoteStr时所需的行为,但当您使用TIniFile读取值时却不是这样,因为GetPrivateProfileString将删除周围的引号,但不会去除嵌入式引号的重复。
因此,如果您要使用TIniFile从文件中读取值并想保留前导和尾随空格,则必须自己添加周围的引号,并确保任何嵌入式引号不会加倍(或者在使用TIniFile读取它们后自己去重)。

AnsiQuotedStr会添加您指定的任何QuoteChar包围符号。使用特殊引号(不是'或")也可以正常工作。然后,您将拥有对称的读写过程,而不是在写入时带有引号而在读取时没有引号,并且无法保证使用文本编辑器手动输入IniFile中的内容。 - Francesca
@Francois:啊,是的,那是个有趣的想法,不过你得非常小心地选择你的“引用”字符,让它成为源字符串中极不可能出现的内容。我在我的关于 AnsiQuotedStr 使用的评论中加了一个限定语。 - Marjan Venema

3
您可能希望将字符串用特殊引号(不是常规的单引号或双引号)括起来,以保留空格(与使用包含空格的长文件名的双引号相同的想法),在写入INI文件时删除引号,并在读取时删除引号。您可以使用SysUtils中的AnsiQuotedStrAnsiDequotedStr进行操作。(不知道它们是否存在于D7中) 更新:如Marjan所指出的那样,如果您使用普通的 ' 或 " ,则不能使用普通的 TIniFile,因为这些将被同时删除,而其中间的内容将保持不变。这会产生一个令人讨厌的副作用,即如果您直接写入所读到的内容,则最终得到的值将不同(除非您在写入之前始终明确添加两端的引号)。 如果您使用TMemInifile将IniFile一次性加载到内存中以加快后续读写速度,则不会发生此行为,并且可以使用常规引号。尽管如此,如果您计划在文本编辑器中修改IniFile,并且希望常规引号作为值的一部分,则仍然有用使用特殊引号将字符串括起来,并确保在某些情况下它们已经存在时将其加倍。 底线:AnsiQuotedStrAnsiDequotedStr与特殊的QuoteChar将对读取和写入起到对称作用,无论您使用TIniFile还是TMemIniFile

如果您使用TIniFile,则在读取字符串时不需要删除引号。这是因为TIniFile在内部使用GetPrivateProfileString,它会删除单引号或双引号。MSDN:“如果与lpKeyName关联的字符串用单引号或双引号括起来,则在GetPrivateProfileString函数检索字符串时将丢弃这些标记。” - Marjan Venema
@Marjan。AnsiQuotedStr的优点是可以选择要使用的QuoteChar。它足够简单,不需要使用常规的单引号或双引号。这就是为什么我使用了“特殊引号”。我会让我的回答更清晰明了。 - Francesca

2
也许您可以在保存StringList之前使用StringReplace将所有前导空格更改为一些数据中从不包含的字符,如@符号?然后在读取数据时执行相反的操作?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接