Модераторы: Poseidon, Snowy, bems, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Чтение параметров из Ini/Inf-файлов, проблема при чте 
V
    Опции темы
capricorn
Дата 19.4.2008, 14:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 22.10.2007

Репутация: 1
Всего: 1



Всем привет!

Вопрос в следующем:
есть INI-файл, нужно прочитать из него параметры, но дело в том, что они указаны следующим образом:

[SECTION 1]
PARAM1 = "123"
PARAM2 = 555

[SECTION 2]
PARAM3
PARAM4
PARAM5


секцию [SECTION 1] прочитать легко (стандартными ср-вами TIniFile), а вот как прочитать параметры из секции [SECTION 2]?

ЗЫ
Пробовал получить все параметры из секции
ReadSection('SECTION 2', myparams)
, но результата не получил.. как быть?

далее...
на http://www.torry.net/quicksearchd.php?Stri...i&Title=Yes нашел прогу, Ini Edit v.2.1, которая читает файлы как раз, как мне нужно, но исходников нет =(, 

Зарарание спасибо!

ЗЫ
подобные файлы - являются файлами INF (в основном), поэтому тут такая заморочка...
PM MAIL   Вверх
SneG0K
Дата 19.4.2008, 15:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Max Mara
***


Профиль
Группа: Завсегдатай
Сообщений: 1887
Регистрация: 1.12.2007
Где: Wis Dells

Репутация: 1
Всего: 54



PM WWW Skype   Вверх
capricorn
Дата 19.4.2008, 15:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 22.10.2007

Репутация: 1
Всего: 1



хммм...
там полностью расписана работа с INI-файлами правильной структуры...
у меня же проблема в том, что структура файла немного иная, т.е. есть подобные секции:

[SECTION 2]
PARAM3
PARAM4
PARAM5

стандартные ср-ва Windows (для INI-файлов естественно) не позволяют читать такие секции (я говорю о ф-иях GetPrivateProfileString и GetProfileString, на которых и основан класс TIniFile)...

так вот я и спрашиваю, может есть какие-нить компоненты/либы для работы с подобными (INF) файлами...?
PM MAIL   Вверх
SneG0K
Дата 19.4.2008, 15:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Max Mara
***


Профиль
Группа: Завсегдатай
Сообщений: 1887
Регистрация: 1.12.2007
Где: Wis Dells

Репутация: 1
Всего: 54



Берешь TStringList и анализируешь все ручками. Других вариантов не знаю... Либо переделывай структуру файла
PM WWW Skype   Вверх
Poseidon
Дата 21.4.2008, 08:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphi developer
****


Профиль
Группа: Комодератор
Сообщений: 5273
Регистрация: 4.2.2005
Где: Гомель, Беларусь

Репутация: 53
Всего: 133



Цитата(capricorn @  19.4.2008,  15:25 Найти цитируемый пост)
стандартные ср-ва Windows (для INI-файлов естественно) не позволяют читать такие секции
ВОТ ключевая фраза! Нельзя (стандартными средствами, разумеется)! Но, учитывая что ini - это обычный текстовик, читай в ручную. Хотя я не понимаю смысла в записях: 
Цитата
Файлы .INI - это текстовые файлы, предназначенные в 16-разрядных Windows 3.x для хранения информации о настройках различных приложений. Информация логически группируется в разделы, каждый из которых начинается оператором заголовка, заключенным в квадратные скобки. Например, [Desktop]. В строках, следующих за заголовком содержится информация, относящаяся к данному разделу, в форме:
<ключ>=<значение>
 У тебя же только названия ключей. Толку от них?



--------------------
Если хочешь, что бы что-то работало - используй написанное, 
если хочешь что-то понять - пиши сам...
PM MAIL ICQ   Вверх
capricorn
Дата 22.4.2008, 10:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 22.10.2007

Репутация: 1
Всего: 1



Вобщем выяснилось вот что.
Inf-файлы windows, с которыми и предполагалось работать имеют немного другую структуру, чем Ini-файлы: 

Код

[секция]
строка 1
строка 2
;...
строка n


т.е. строки парсятся уже потом (для получения параметров вида <ключ>=<значение> и т.д)...

далее. ф-ии Windows для работы с INI-файлами не позволяют читать параметры с переносами строк:  smile 

Код

; Этот параметр взят из реального файла
; и демонстрирует многострочные параметры (с переносами)
0x3,"Software\Microsoft\MediaPlayer\Battery\Presets\DrowningFlower","Palette",\
  09,00,09,00,09,01,0c,00,09,03,10,00,09,04,14,00,09,06,17,00,09,07,1b,00,09,\
  09,1f,00,09,0a,22,00,09,0c,26,00,09,0d,2a,00,08,0f,2e,00,08,10,31,00,08,12,\
; тут тоже может быть комментарий
  35,00,08,13,39,00,08,15,3c,00,08,16,40,00,08,18,44,00,08,19,48,00,08,1b,4b
; {вырезано}


Такие параметры так-же могут использоваться в REG-файлах

Поэтому я решил написать модуль для работы с Inf-файлами.
(в нем только самые необходимые функции для чтения/записи строк, парсинг параметров пока во внимание не берется)

Сначала я пытался дописать существующий модуль для работы с Ini-файлами IniFiles32 (от Stephan Schneider), но найдя там более 5 грубых ошибок, решил все-таки писать с нуля...  smile 

вот что из этого получилось:

Код

{----------------------------------------------
InfFiles.pas

Модуль для работы с Inf-файлами Windows

Алексей Куликов (C) 2008 г.

freeware
-----------------------------------------------}

unit InfFiles;

interface

uses Classes, SysUtils;

type

  TInfFile = class (TObject)
    private
      FFileName:    string;
      FFileBuffer:  TStringList;
      procedure LoadFromFile;
      function ParseComments(const S: string): string;
      function IsSection(const S: string): boolean;
      function GetSectionIndex(const Section: string): integer;
      function RemoveStr(const Section: string; Target: string): integer;
    public
      constructor Create(const FileName: string);
      destructor Destroy;
      procedure Save();
      procedure SaveAs(const FileName: string);
      procedure ReadSections(Strings: TStrings);
      procedure ReadStrings(const Section: string; Strings: TStrings);
      procedure WriteString(const Section: string; const Ext: string);
      procedure WriteStrings(const Section: string; Strings: TStrings);
      procedure ReplaceString(const Section: string;
                              const Old: string; const New:string);
      procedure ReplaceStrings(const Section: string;
                               const Old: string; const New: TStrings);
      procedure DeleteString(const Section: string; Target: string);
  end;

implementation

constructor TInfFile.Create(const FileName: string);
begin
  FFileName := FileName;
  FFileBuffer := TStringList.Create;
  if FileExists(FFileName) then
    LoadFromFile;
end;

destructor TInfFile.Destroy;
begin
  FFileBuffer.Free;
  Finalize(FFileName);
end;

{
  Сохраняет изменения в открытом файле
}
procedure TInfFile.Save;
begin
  FFileBuffer.SaveToFile(FFileName);
end;

{
  Сохраняет изменения в назначенном файле
}
procedure TInfFile.SaveAs(const FileName: string);
begin
  FFileBuffer.LoadFromFile(FileName);
end;

procedure TInfFile.LoadFromFile;
begin
  FFileBuffer.LoadFromFile(FFileName);
end;

{
  Функция парсит строку, удаляя комментарии
}
function TInfFile.ParseComments(const S: string): string;
var
  i, len: integer;
  tmp: string;
begin
  len := length(S);
  i := 1;
  while (i < len+1) and (S[i] <> ';') do
  begin
    tmp := tmp + S[i];
    Inc(i);
  end;
  result := tmp;
end;

{
  Функция возвращает true, если S яв-ся секцией
}
function TInfFile.IsSection(const S: string): boolean;
var
  tmp: string;
begin
  Result := false;
  if S <> '' then
  begin
    tmp := Trim(s);
    if (tmp[1] = '[') and (tmp[Length(tmp)] = ']') then
      Result := true;
  end;
end;

{
  Функция возвращает инедекс секции
  причем только первый (если секция разбросана по файлу)
}
function TInfFile.GetSectionIndex(const Section: string): integer;
begin
  Result := FFileBuffer.IndexOf('['+Section+']');
end;

{
  Функция получает список всех секций файла
}
procedure TInfFile.ReadSections(Strings: TStrings);
var
  i: integer;
  Section: string;
  bufcount: integer;
begin
  Strings.BeginUpdate;
  try
    Strings.Clear;
    bufcount := FFileBuffer.Count;
    if bufcount > 0 then
    begin
      i := 0;
      while (i < bufcount - 1 )do
      begin
        Section := Trim(FFileBuffer[i]);
        if Section <> '' then
        if IsSection(Section) then
        begin
          Delete(Section, 1, 1);
          Delete(Section, Length(Section), 1);
          Strings.Add(Section);
        end;
        Inc(i);
      end;
    end;
  finally
    Strings.EndUpdate;
  end;
end;

{
  Ищет строку и удаляет ее (учитывая переносы) и возвращает индекс
  удаленной строки, если строка не найдена, возвращает -1.
  Поиск осуществляется по принципу маски, т.е.
  будет удалена первая найденная строка, начанающаяся с Target
}
function TInfFile.RemoveStr(const Section: string; Target: string): integer;

  function CompareStrMask(const Str: string; const Mask: string): boolean;
  begin
    Result := false;
    if Length(Str) < Length(Mask) then Exit;
    if Copy(UpperCase(Trim(Str)), 1, Length(Mask)) = UpperCase(Mask) then
      Result := true;
  end;

var
  i, j: integer;
  InSection: boolean;
  bufcount: integer;
  FirstDelIndex, removecount: integer; // для перенесенных строк
  Current: string;
  tmp: string;
begin
  Result := -1; // если строка не будет найдена
  bufcount := FFileBuffer.Count;
  if bufcount > 0 then
  begin
    if FFileBuffer.Find(Target, i) then // строка полностью совпадает
    begin
      FFileBuffer.Delete(i);
      Result := i;
      Exit;
    end;
    i := GetSectionIndex(Section); // поиск по маске
    if (i <> -1) then
    begin
      Inc(i);
      InSection := true;
      while (i < BufCount) do
      begin
        Current := ParseComments(FFileBuffer[i]);
        if (Current = '') then
          Inc(i)
        else
        begin
        if IsSection(Current) then
          if Current <> '['+Section+']' then
            InSection := false else
            InSection := true;
          if not InSection then // мы находмися в заданной секции?
          Inc(i) else
          if Current[Length(Current)] = '\' then // строка перенесена
          begin
                FirstDelIndex := i;
                tmp := '';
                removecount := 1;
                while (Current[Length(Current)] = '\') do
                begin
                  Delete(Current, Length(Current), 1);
                  tmp := tmp + Current;
                  Inc(i);
                  Current := ParseComments(Trim(FFileBuffer[i]));
                  if Current = '' then
                  while ((Current = '') and (i < BufCount)) do
                  begin
                    Inc(i);
                    Inc(removecount);
                    Current := ParseComments(Trim(FFileBuffer[i]));
                  end;
                  Inc(removecount);
                end;
                tmp := tmp + Current;
                if CompareStrMask(tmp, Target) then
                begin
                  for j := 1 to removecount do
                    FFileBuffer.Delete(FirstDelIndex);
                  Result := FirstDelIndex; // индекс удаленной строки
                  Exit; // выходим после удаления
                end;
                Inc(i);
          end else
           if CompareStrMask(Current, Target) then
          begin
            FFileBuffer.Delete(i);
            Result := i; // индекс удаленной строки
            Exit; // выходим после удаления
        end else // if CompareStrMask(Current, Target)
          Inc(i);
        end; // if (Current = '')
      end;
    end;// if (i <> -1) // заданная секция отсутствует
  end;
end;

{
 Фукция читает все строки из определенной секции и записывает в буфер Strings
 также производит форматирование строк с переносами
}

procedure TInfFile.ReadStrings(const Section: string; Strings: TStrings);
var
  i: integer;
  InSection: boolean;
  BufCount: integer;
  FirstIndex: integer;
  Current, tmp: string;
begin
  Strings.BeginUpdate;
  try
    Strings.Clear;
    BufCount := FFileBuffer.Count;
    if BufCount > 0 then
    begin
      FirstIndex := GetSectionIndex(Section);
      if FirstIndex <> -1 then
      begin
        i := FirstIndex+1;
        InSection := true;
        while (i < BufCount) do
        begin
          Current := ParseComments(Trim(FFileBuffer[i]));
          if (Current <> '') then
          begin
            if IsSection(Current) then
            begin
              if Current = '['+Section+']' then
                InSection := true else
                InSection := false;
              Inc(i);
            end else // if IsSection(Current)
            if InSection then
            begin
              if Current[Length(Current)] = '\' then
              begin
                tmp := '';
                while (Current[Length(Current)] = '\') do
                begin
                  Delete(Current, Length(Current), 1);
                  tmp := tmp + Current;
                  Inc(i);
                  Current := ParseComments(Trim(FFileBuffer[i]));
                  if Current = '' then
                  while ((Current = '') and (i < BufCount)) do
                  begin
                    Inc(i);
                    Current := ParseComments(Trim(FFileBuffer[i]));
                  end;
                end;
                tmp := tmp + Current;
                Strings.Add(tmp);
                Inc(i);
              end else // if Current[Length(Current)] = '\'
              begin
                Strings.Add(Current);
                Inc(i);
              end;
            end else // if InSection
            Inc(i);
          end else // if (Current <> '')
          Inc(i);
        end; // while (i < BufCount)
      end; // if FirstIndex <> -1
    end; // if BufCount > 0
  finally
  Strings.EndUpdate;
  end;
end;

{
  функция записывает строку в заданную секцию
}
procedure TInfFile.WriteString(const Section: string; const Ext: string);
var
  i: integer;
begin
  i := GetSectionIndex(Section);
  if (i <> -1) then
  begin
    Inc(i);
    FFileBuffer.Insert(i, Ext);
  end else
  begin // если секции не существует, добавляем новую
    FFileBuffer.Add('');
    FFileBuffer.Add('['+Section+']');
    FFileBuffer.Add(Ext);
  end;
end;

{
  Функция записывает строки в заданную секцию
}
procedure TInfFile.WriteStrings(const Section: string; Strings: TStrings);
var
  i, j, count: integer;
begin
  i := GetSectionIndex(Section);
  if (i <> -1) then
  begin
    Inc(i);
    count := Strings.Count;
    if count > 0 then
    for j := 0 to count-1 do
      FFileBuffer.Insert(i, Strings[j]);
  end else
  begin
    FFileBuffer.Add('');
    FFileBuffer.Add('['+Section+']');
    FFileBuffer.AddStrings(Strings);
  end;
end;

{
  Функция заменяет строку в файле (учитывая переносы)
}
procedure TInfFile.ReplaceString(const Section: string; const Old: string; const New: string);
var
  i: integer;
  index: integer;
begin
  i := GetSectionIndex(Section);
  if (i <> -1) then
  begin
    index := RemoveStr(Section, Old);
    if (index <> -1) then
        FFileBuffer.Insert(index, New)
    else
      WriteString(Section, New);
  end else
  begin
    FFileBuffer.Add('');
    FFileBuffer.Add('['+Section+']');
    FFileBuffer.Add(New);
  end;
end;

{
  Удаление строки по маске
  (см. ф-ию RemoveStr)
}
procedure TInfFile.DeleteString(const Section: string; Target: string);
begin
  RemoveStr(Section, Target);
end;

{
  Функция заменяет строку в файле на последовательность строк
  (удаляет строку Old и добавляет новые строки в начало секции)
  (удобно для записи многострочных (с переносами) параметров)
}
procedure TInfFile.ReplaceStrings(const Section: string; const Old: string; const New: TStrings);
var
  i, j: integer;
  index: integer;
begin
  i := GetSectionIndex(Section);
  if (i <> -1) then
  begin
    RemoveStr(Section, Old);
    WriteStrings(Section, New);
  end else
  begin
    FFileBuffer.Add('');
    FFileBuffer.Add('['+Section+']');
    FFileBuffer.AddStrings(New);
  end;
end;

end.


Для описания ф-ий см. комментарии...

Надеюсь, что кому-нить может и пригодится  smile

ЗЫ
Если вы нашли ошибку/баг в моем модуле, пожалуйста, сообщайте...

Это сообщение отредактировал(а) capricorn - 22.4.2008, 11:34
PM MAIL   Вверх
vserd
Дата 9.10.2008, 17:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 9.10.2008

Репутация: нет
Всего: нет



Цитата(capricorn @  22.4.2008,  10:58 Найти цитируемый пост)
ЗЫ
Если вы нашли ошибку/баг в моем модуле, пожалуйста, сообщайте...

Код

{
  Сохраняет изменения в назначенном файле
}
procedure TInfFile.SaveAs(const FileName: string);
begin
  FFileBuffer.LoadFromFile(FileName);
end;

меняем на
Код

procedure TInfFile.SaveAs(const FileName: string);
begin
  FFileBuffer.SavetoFile(FileName);
end;


Это сообщение отредактировал(а) vserd - 9.10.2008, 17:49
PM MAIL   Вверх
MetalFan
Дата 9.10.2008, 21:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 62
Всего: 128



вроде как для работы с inf файлами в винде есть ряд функций в setup api...
в частности см. Extracting File Information from the INF file


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
MetalFan
  Дата 9.10.2008, 21:45 (ссылка) |  (голосов:3) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 62
Всего: 128



кстати,
Цитата(capricorn @  22.4.2008,  10:58 Найти цитируемый пост)
но найдя там более 5 грубых ошибок

не знаю, что это за модуль такой и что там за ошибки...
но не удержусь прокомментировать некоторые моменты представленного кода
1. 
Цитата(capricorn @  22.4.2008,  10:58 Найти цитируемый пост)

      destructor Destroy;
...
destructor TInfFile.Destroy;
begin
  FFileBuffer.Free;
  Finalize(FFileName);
end;

я конечно понимаю, что класс является наследником TObject, и на некоторые моменты можно положить...
но стоит, имхо, объявить деструктор перекрытым (override) и вызывать из его реализации метод предка (inherited)
так же неясно, зачем строковому полю класса делается Finalize.
2. 
Цитата(capricorn @  22.4.2008,  10:58 Найти цитируемый пост)
{
  Функция парсит строку, удаляя комментарии
}
function TInfFile.ParseComments(const S: string): string;
var
  i, len: integer;
  tmp: string;
begin
  len := length(S);
  i := 1;
  while (i < len+1) and (S[i] <> ';') do
  begin
    tmp := tmp + S[i];
    Inc(i);
  end;
  result := tmp;
end;

медленное и неэффективное решение, достойное студента первого курса в лабе по паскалю. чем функции Pos и Copy не угодили?

3. запись
Код

    if (tmp[1] = '[') and (tmp[Length(tmp)] = ']') then
      Result := true;

логичнее выглядит так:
Код

Result := (tmp[1] = '[') and (tmp[Length(tmp)] = ']');


4. опять лишние телодвижения
Код

          Delete(Section, 1, 1);
          Delete(Section, Length(Section), 1);

чем copy не угодило?

5. функция RemoveStr вообще не доступна моему пониманию... имхо слишком усложненный код.
и т.д....

p.s. без обид  smile 

Это сообщение отредактировал(а) MetalFan - 9.10.2008, 21:46


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1129 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.