Delphi записывает повторяющиеся записи в TIniFile

Вот любопытное явление. У меня есть приложение Delphi 10.3, которое начало записывать повторяющиеся записи в файл TIniFile.

Вот код:

with TIniFile.Create(UserDatFileName) do
try
  WriteInteger(SFormName, 'Top', AForm.Top);
  WriteInteger(SFormName, 'Left', AForm.Left);
  WriteInteger(SFormName, 'Height', AForm.Height);
  WriteInteger(SFormName, 'Width', AForm.Width);
  WriteString(SFormName, 'WindowState', SWindowState);
finally
  Free;
end;

Это отлично работало в течение многих лет. Теперь, внезапно, я получаю вывод следующим образом:

[fMainForm]
Top=0
Left=0
Height=556
Width=671
WindowState=wsMaximized
pnlNavigation.Width=165
TreeListcxTreeListModule.Width=161
Top=0
Left=0
Height=556
Width=671
WindowState=wsMaximized
pnlNavigation.Width=165
TreeListcxTreeListModule.Width=161
Top=0
Left=0
Height=556
Width=671
WindowState=wsMaximized
pnlNavigation.Width=165
TreeListcxTreeListModule.Width=161
... etcetera etcetera

Любые предложения о том, почему это может происходить? Я думал, что пары значений TIniFile должны быть уникальными в каждом разделе?


person sdaberle    schedule 28.12.2020    source источник
comment
Можете ли вы предоставить минимально воспроизводимый пример? Потому что это, скорее всего, экология.   -  person David Heffernan    schedule 29.12.2020
comment
Я думаю, что теоретически это может произойти, когда несколько приложений пишут одновременно. Я никогда не видел именно такого поведения, но я видел ошибки, указывающие на то, что TIniFile (используя WritePrivateProfileString API) блокирует только часть файла для записи. Так что, возможно, если значение не существует, несколько приложений смогут добавить его одновременно.   -  person GolezTrol    schedule 29.12.2020
comment
Кстати, сейчас я бы использовал TMemIniFile. Это значение по умолчанию на любой платформе, отличной от Windows, и оно также хорошо работает в Windows. Даже немного быстрее. Вы можете сбросить все изменения сразу, вместо того, чтобы вызывать этот относительно медленный API при каждой записи.   -  person GolezTrol    schedule 29.12.2020
comment
Такой ini-файл не является незаконным, и с правильным API вы действительно можете прочитать эти значения.   -  person GolezTrol    schedule 29.12.2020
comment
Все любопытнее и любопытнее. Оказывается, он также не читал записи IniFile при запуске - он выполнял все операторы Read..., но не получал значений. Как ни странно, добавление оператора ReadSection (я пытался проверить содержимое IniFile) заставило другие операции чтения работать, но повторяющиеся записи продолжались при закрытии. Переключение на TMemIniFile, кажется, решило обе проблемы, но я хотел бы знать, что было причиной этого в первую очередь. Вероятно, как предполагает Дэвид Хеффернен, это было связано с окружающей средой, и я предполагаю, что две проблемы связаны: запись дубликатов ключей из-за неправильного чтения.   -  person sdaberle    schedule 29.12.2020
comment
Я предполагаю, что это проблема формата файла. Посмотрите файл шестнадцатеричным редактором, в нем могут быть символы, которые ломают функции PrivateProfileString.   -  person dummzeuch    schedule 29.12.2020
comment
Вы пытались удалить файл, а затем посмотрели, сохраняется ли проблема...   -  person R. Hoek    schedule 29.12.2020
comment
@r-hoek: я не пробовал, нет. Без сомнения, это сработало бы. Но тогда я бы не обязательно нашел проблему.   -  person sdaberle    schedule 29.12.2020


Ответы (1)


@dummzeuch за победу: в начале файла было три посторонних символа (Hex EF BB BF). Удаление тех сняло проблему. Я также обнаружил те же три символа в начале другого столь же проблемного INI-файла.

person sdaberle    schedule 29.12.2020
comment
Это метка порядка байтов (BOM). Он определяет, что последующий текст кодируется как UTF-8. - person LU RD; 30.12.2020
comment
Это означает, что файл ini хранится вашей или какой-либо другой программой в кодировке UTF-8. Если вы используете TMemIniFile, вы можете читать или записывать файл как UTF-8. См. Как прочитать INI-файл в кодировке UTF8?. Но сначала выясните, почему он изначально был написан как UTF-8. - person LU RD; 30.12.2020