C чтение настроек из файла

Обновлено: 25.06.2024

До этого при вводе-выводе данных мы работали со стандартными потоками — клавиатурой и монитором. Теперь рассмотрим, как в языке C реализовано получение данных из файлов и запись их туда. Перед тем как выполнять эти операции, надо открыть файл и получить доступ к нему.

В языке программирования C указатель на файл имеет тип FILE и его объявление выглядит так:

С другой стороны, функция fopen() открывает файл по указанному в качестве первого аргумента адресу в режиме чтения ("r"), записи ("w") или добавления ("a") и возвращает в программу указатель на него. Поэтому процесс открытия файла и подключения его к программе выглядит примерно так:

Примечание. В случае использования относительной адресации текущим/рабочим каталогом в момент исполнения программы должен быть тот, относительно которого указанный относительный адрес корректен. Место нахождения самого исполняемого файла не важно.

При чтении или записи данных в файл обращение к нему осуществляется посредством файлового указателя (в данном случае, myfile).

Если в силу тех или иных причин (нет файла по указанному адресу, запрещен доступ к нему) функция fopen() не может открыть файл, то она возвращает NULL. В реальных программах почти всегда обрабатывают ошибку открытия файла в ветке if , мы же далее опустим это.

Объявление функции fopen() содержится в заголовочном файле stdio.h, поэтому требуется его подключение. Также в stdio.h объявлен тип-структура FILE.

После того, как работа с файлом закончена, принято его закрывать, чтобы освободить буфер от данных и по другим причинам. Это особенно важно, если после работы с файлом программа продолжает выполняться. Разрыв связи между внешним файлом и указателем на него из программы выполняется с помощью функции fclose() . В качестве параметра ей передается указатель на файл:

В программе может быть открыт не один файл. В таком случае каждый файл должен быть связан со своим файловым указателем. Однако если программа сначала работает с одним файлом, потом закрывает его, то указатель можно использовать для открытия второго файла.

Чтение из текстового файла и запись в него

fscanf()

Функция fscanf() аналогична по смыслу функции scanf() , но в отличии от нее осуществляет форматированный ввод из файла, а не стандартного потока ввода. Функция fscanf() принимает параметры: файловый указатель, строку формата, адреса областей памяти для записи данных:

Возвращает количество удачно считанных данных или EOF. Пробелы, символы перехода на новую строку учитываются как разделители данных.

Допустим, у нас есть файл содержащий такое описание объектов:

Тогда, чтобы считать эти данные, мы можем написать такую программу:

В данном случае объявляется структура и массив структур. Каждая строка из файла соответствует одному элементу массива; элемент массива представляет собой структуру, содержащую строковое и два числовых поля. За одну итерацию цикл считывает одну строку. Когда встречается конец файла fscanf() возвращает значение EOF и цикл завершается.

fgets()

Функция fgets() аналогична функции gets() и осуществляет построчный ввод из файла. Один вызов fgets() позволят прочитать одну строку. При этом можно прочитать не всю строку, а лишь ее часть от начала. Параметры fgets() выглядят таким образом:

Такой вызов функции прочитает из файла, связанного с указателем myfile, одну строку текста полностью, если ее длина меньше 50 символов с учетом символа '\n', который функция также сохранит в массиве. Последним (50-ым) элементом массива str будет символ '\0', добавленный fgets() . Если строка окажется длиннее, то функция прочитает 49 символов и в конце запишет '\0'. В таком случае '\n' в считанной строке содержаться не будет.

В этой программе в отличие от предыдущей данные считываются строка за строкой в массив arr. Когда считывается следующая строка, предыдущая теряется. Функция fgets() возвращает NULL в случае, если не может прочитать следующую строку.

getc() или fgetc()

Функция getc() или fgetc() (работает и то и другое) позволяет получить из файла очередной один символ.

Приведенный в качестве примера код выводит данные из файла на экран.

Запись в текстовый файл

Также как и ввод, вывод в файл может быть различным.

  • Форматированный вывод. Функция fprintf ( файловый_указатель, строка_формата, переменные ) .
  • Посточный вывод. Функция fputs ( строка, файловый_указатель ) .
  • Посимвольный вывод. Функция fputc() или putc( символ, файловый_указатель ) .

Ниже приводятся примеры кода, в которых используются три способа вывода данных в файл.

Запись в каждую строку файла полей одной структуры:

Построчный вывод в файл ( fputs() , в отличие от puts() сама не помещает в конце строки '\n'):

Пример посимвольного вывода:

Чтение из двоичного файла и запись в него

С файлом можно работать не как с последовательностью символов, а как с последовательностью байтов. В принципе, с нетекстовыми файлами работать по-другому не возможно. Однако так можно читать и писать и в текстовые файлы. Преимущество такого способа доступа к файлу заключается в скорости чтения-записи: за одно обращение можно считать/записать существенный блок информации.

При открытии файла для двоичного доступа, вторым параметром функции fopen() является строка "rb" или "wb".

Тема о работе с двоичными файлами достаточно сложная, для ее изучения требуется отдельный урок. Здесь будут отмечены только особенности функций чтения-записи в файл, который рассматривается как поток байтов.

Функции fread() и fwrite() принимают в качестве параметров:

  1. адрес области памяти, куда данные записываются или откуда считываются,
  2. размер одного данного какого-либо типа,
  3. количество считываемых данных указанного размера,
  4. файловый указатель.

Эти функции возвращают количество успешно прочитанных или записанных данных. Т.е. можно "заказать" считывание 50 элементов данных, а получить только 10. Ошибки при этом не возникнет.

Пример использования функций fread() и fwrite() :

Здесь осуществляется попытка чтения из первого файла 50-ти символов. В n сохраняется количество реально считанных символов. Значение n может быть равно 50 или меньше. Данные помещаются в строку. То же самое происходит со вторым файлом. Далее первая строка присоединяется ко второй, и данные сбрасываются в третий файл.

Необходимо из файла получить значения переменных.

Т.е. есть переменные

char str1[15];
DWORD m_dw1;
DWORD m_dw2;
char str1[20];

Есть файл: "1234567890123454545 "
Как получить данные из файла?

Здравствуйте, Smok_er, Вы писали:

SE>Необходимо из файла получить значения переменных.

SE>Т.е. есть переменные

SE>char str1[15];
SE>DWORD m_dw1;
SE>DWORD m_dw2;
SE>char str1[20];

SE>Есть файл: "1234567890123454545 "
SE>Как получить данные из файла?
А можно подробнее что ты хочешь получить? а то не совсем понятно как делить цифирки между m_dw1 и m_dw2

Из такого файла можно получить как все переменные, так и одну str1.
Если эти переменные запихать в одну структуру, а файл двоичный, то прочесть можно так

hFile = CreateFile(
ReadFile(hFile, &struc, sizeof(struc), .

ну и записать также, только WriteFile

А если текстовый, то удобней разбить переменные на строки, н-р так

[Options]
str1=1234
m_dw1=567890
m_dw2=12345
str2=4545

и юзать GetPrivateProfileString / WritePrivateProfileString

Здравствуйте, Anatoliy Elsukov, Вы писали:

AE>Здравствуйте, Smok_er, Вы писали:

SE>Необходимо из файла получить значения переменных.

SE>Т.е. есть переменные

SE>char str1[15];
SE>DWORD m_dw1;
SE>DWORD m_dw2;
SE>char str1[20];

SE>Есть файл: "1234567890123454545 "
SE>Как получить данные из файла?

AE>А можно подробнее что ты хочешь получить? а то не совсем понятно как делить цифирки между m_dw1 и m_dw2

Да, конечно. Мы знаем, что первые 15 символов — str1, 16,17 — m_dw1, 18,19 — m_dw2, 20..39 — str2

хочется из строки получить эти значения. sscanf не подходит, т.к. символ пробела принимается за разделитель, а str1 может состоять только из пробелов

Здравствуйте, Clickmaker, Вы писали:

C>Из такого файла можно получить как все переменные, так и одну str1.
Нет, "разложить" на составляющие

C>Если эти переменные запихать в одну структуру, а файл двоичный, то прочесть можно так

C>hFile = CreateFile(
C>ReadFile(hFile, &struc, sizeof(struc), .

C>ну и записать также, только WriteFile

а что произойдет, если считать нужно больше, чем исходная строка?
в принципе идеальный вариант — это просто отмена присваивания каким-либо членам структуры.

C>А если текстовый, то удобней разбить переменные на строки, н-р так

C>[Options]
C>str1=1234
C>m_dw1=567890
C>m_dw2=12345
C>str2=4545

C>и юзать GetPrivateProfileString / WritePrivateProfileString

Это не подходит, т.к. файл будет шифроваться, в общем двоичный — единственно возвожных вариант.

Здравствуйте, Smok_er, Вы писали:

SE>Да, конечно. Мы знаем, что первые 15 символов — str1, 16,17 — m_dw1, 18,19 — m_dw2, 20..39 — str2

SE>хочется из строки получить эти значения. sscanf не подходит, т.к. символ пробела принимается за разделитель, а str1 может состоять только из пробелов

Единственное нужно ещё помнить про необходимость нуль-терминала в str1 и str2 (если он там конечно нужен )

В интернете приведено очень много способов хранения настроек программы, но все они как-то разбросаны, поэтому я решил их собрать вместе и расписать, как этим пользоваться.

На хабре уже была посвящена этому тема, поэтому… перейти

Информация о Properties.Settings

Организация Properties.Settings — это обычный xml файл, который можно найти в папке пользователя:

С:\ Users \ [user name] \ AppData \ Local \ [ (Project Name) or (AssemblyCompany) ] \ [name project_cashBuild] \ [AssemblyVersion] \ user.config

Для начала нам нужно создать такие переменные для Properties.Settings. Перейдем в Properties -> Settings.settings:



Я создал 3-и переменные и выбрал область их использования: 2- область пользователь и 1- приложение.

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

Вернемся к переменным:

  • Version — версия нашей программы. Определил ее строкой и областью приложение. Т.к. версия может содержать буквы (например, b — от beta). А область выбрал, чтоб не менялась наша версия приложения (т.к. AssemblyVersion редко кто использует).
  • Save_text — это переменная, куда мы будем сохранять наш текст.
  • open_sum — сколько раз мы открыли программу.

Результаты работы программы

Первый запуск, мы видим, что кол-во запусков равно 1. И теста в richTextBox1 нет.


Теперь напишем и сохраним текст.


При втором запуске мы видим, что текст сохранен, и кол-во запусков уже 2-ва.


Очень удобно использовать этот объект, если надо работать в разных областях видимости в одном проекте. Метод хорош, когда вам не надо, чтоб рядовой пользователь рылся в файлах настройки программы.

С ini-файлами все на оборот, они лежат в папке рядом с программой, что позволяет пользователю изменить настройки вне-программы. Данный способ хорош, если настройки программы заносятся вручную. Например, эмулятор для запуска игры без лицензии (тотже revLoader).

Теперь перейдем к нашей теме. Для работы с таким типом файлов, нам нужно создать класс по работе с ним. Создаем класс, например «IniFile», подключаем пространство имен, которых нет:


А теперь разбираем по-порядку:

Теперь переходим в основную программу.

Результаты работы программы

При первом запуска, у нас нет файла config.ini. Поэтому при проверке возвращаются fasle и мы приравниваем окно к минимальным параметрам.


Меняем параметры окна и жмем «Применить»


Редактируем файл config.ini руками и жмем загрузить.


На этом все, в следующий раз опишу работу с xml файлами и с бинарными файлами.

Общие режимы профиля:

<configuration>
<configSections> // Область объявления раздела конфигурации, включая раздел конфигурации и объявление пространства имен
<section> // Оператор раздела конфигурации
<sectionGroup> // Определение группы раздела конфигурации
<section> Оператор раздела конфигурации в группе раздела конфигурации
<appSettings> // Предварительно определенный раздел конфигурации
<Пользовательский элемент для раздела конфигурации> // Область настройки раздела конфигурации

Ниже приведен пример наиболее распространенного файла конфигурации приложения, содержащего только раздел appSettings:

В предопределенном разделе appSettings (обратите внимание на случай) есть много элементов, все имена которых - «добавить», а два атрибута - «ключ» и «значение».

Примечание. Теперь в Net FrameWork 2.0 четко указано, что этот атрибут ConfigurationSettings устарел, и его рекомендуется изменить на ConfigurationManager или WebConfigurationManager.

После добавления ссылки вы можете использовать ConfigurationManager.AppSettings ["Key"] для чтения соответствующего значения.

Однако свойство ConfigurationManager.AppSettings доступно только для чтения и не поддерживает изменение значений свойств. Это связано с тем, что Microsoft не рекомендует динамически записывать файл app.config, но рекомендует после ручной настройки только статический доступ во время работы программы.

Если вам действительно нужно внести изменения в программу, то есть написать App.Config, продолжайте читать.

Во-вторых, операции чтения и записи раздела конфигурации appSettings.

Метод чтения раздела appSettings файла App.config относительно прост. Доступ к нему можно получить с помощью вышеупомянутого метода System.Configuration.ConfigurationManager.AppSettings ["Key"], но, как упоминалось ранее, этот метод не обеспечивает запись.

Если вы хотите написать файл конфигурации, вы можете использовать объект ConfigurationManager для выполнения операции открытия файла конфигурации, будет возвращен объект конфигурации, и операция может быть выполнена с использованием этого объекта (добавление, удаление, изменение и проверка все возможно).

Код реализации приведен ниже (добавьте ссылку на использование пространства имен System.Configuration)

1. Доступ к элементу <add> на основе несуществующего значения Key или даже использование метода remove () для удаления несуществующего элемента не вызовет исключения, первый вернет null.

2. Добавление существующего элемента <add> не вызовет исключения, но объединит существующее значение и новое значение, разделенные знаком «,», например: «olldvalue, newvalue».

3. После компиляции проекта под файлом bin \ Debuge в рабочем каталоге появятся два файла конфигурации, один с именем «ProjectName.exe.config», а другой с именем «ProjectName.vshost.exe.config». Первый файл - это файл конфигурации, фактически используемый проектом, и все изменения, внесенные во время работы программы, будут сохранены здесь; второй файл на самом деле является файлом синхронизации «App.config» в исходном коде, то есть не изменится.

4. Обратите особое внимание на регистр (файлы XML чувствительны к регистру), например, в разделе конфигурации appSettings.

Читайте также: