服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C++实现ini文件读写的示例代码

C++实现ini文件读写的示例代码

2022-11-24 11:22求则得之,舍则失之 C/C++

这篇文章主要介绍了C++如何实现读写ini配置文件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

介绍

一般的ini配置文件由节、键、值组成。

【参数】(键=值),例如 :key=value;

【节】:所有的参数都是以节(section)为单位结合在一起的。所有的section名称都是独占一行,并且section名字都被方括号包围着([XXX])。在section声明后的所有parameters都属于该section。

例如:[section1]

所以一个包含节,键,值的简单ini配置文件,例如:

[port]
portName=port1
port=123

1.使用INIReader.h头文件

1.INIReader.h

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
// Read an INI file into easy-to-access name/value pairs.
 
// inih and INIReader are released under the New BSD license (see LICENSE.txt).
// Go to the project home page for more info:
//
// https://github.com/benhoyt/inih
/* inih -- simple .INI file parser
inih is released under the New BSD license (see LICENSE.txt). Go to the project
home page for more info:
https://github.com/benhoyt/inih
*/
 
#ifndef __INI_H__
#define __INI_H__
 
/* Make this header file easier to include in C++ code */
#ifdef __cplusplus
extern "C" {
#endif
 
#include <stdio.h>
 
/* Typedef for prototype of handler function. */
typedef int (*ini_handler)(void* user, const char* section,
                           const char* name, const char* value);
 
/* Typedef for prototype of fgets-style reader function. */
typedef char* (*ini_reader)(char* str, int num, void* stream);
 
/* Parse given INI-style file. May have [section]s, name=value pairs
   (whitespace stripped), and comments starting with ';' (semicolon). Section
   is "" if name=value pair parsed before any section heading. name:value
   pairs are also supported as a concession to Python's configparser.
   For each name=value pair parsed, call handler function with given user
   pointer as well as section, name, and value (data only valid for duration
   of handler call). Handler should return nonzero on success, zero on error.
   Returns 0 on success, line number of first error on parse error (doesn't
   stop on first error), -1 on file open error, or -2 on memory allocation
   error (only when INI_USE_STACK is zero).
*/
int ini_parse(const char* filename, ini_handler handler, void* user);
 
/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
   close the file when it's finished -- the caller must do that. */
int ini_parse_file(FILE* file, ini_handler handler, void* user);
 
/* Same as ini_parse(), but takes an ini_reader function pointer instead of
   filename. Used for implementing custom or string-based I/O. */
int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
                     void* user);
 
/* Nonzero to allow multi-line value parsing, in the style of Python's
   configparser. If allowed, ini_parse() will call the handler with the same
   name for each subsequent line parsed. */
#ifndef INI_ALLOW_MULTILINE
#define INI_ALLOW_MULTILINE 1
#endif
 
/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
   the file. See http://code.google.com/p/inih/issues/detail?id=21 */
#ifndef INI_ALLOW_BOM
#define INI_ALLOW_BOM 1
#endif
 
/* Nonzero to allow inline comments (with valid inline comment characters
   specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match
   Python 3.2+ configparser behaviour. */
#ifndef INI_ALLOW_INLINE_COMMENTS
#define INI_ALLOW_INLINE_COMMENTS 1
#endif
#ifndef INI_INLINE_COMMENT_PREFIXES
#define INI_INLINE_COMMENT_PREFIXES ";"
#endif
 
/* Nonzero to use stack, zero to use heap (malloc/free). */
#ifndef INI_USE_STACK
#define INI_USE_STACK 1
#endif
 
/* Stop parsing on first error (default is to keep parsing). */
#ifndef INI_STOP_ON_FIRST_ERROR
#define INI_STOP_ON_FIRST_ERROR 0
#endif
 
/* Maximum line length for any line in INI file. */
#ifndef INI_MAX_LINE
#define INI_MAX_LINE 200
#endif
 
#ifdef __cplusplus
}
#endif
 
/* inih -- simple .INI file parser
inih is released under the New BSD license (see LICENSE.txt). Go to the project
home page for more info:
https://github.com/benhoyt/inih
*/
 
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
 
#include <stdio.h>
#include <ctype.h>
#include <string.h>
 
#if !INI_USE_STACK
#include <stdlib.h>
#endif
 
#define MAX_SECTION 50
#define MAX_NAME 50
 
/* Strip whitespace chars off end of given string, in place. Return s. */
inline static char* rstrip(char* s)
{
    char* p = s + strlen(s);
    while (p > s && isspace((unsigned char)(*--p)))
        *p = '\0';
    return s;
}
 
/* Return pointer to first non-whitespace char in given string. */
inline static char* lskip(const char* s)
{
    while (*s && isspace((unsigned char)(*s)))
        s++;
    return (char*)s;
}
 
/* Return pointer to first char (of chars) or inline comment in given string,
   or pointer to null at end of string if neither found. Inline comment must
   be prefixed by a whitespace character to register as a comment. */
inline static char* find_chars_or_comment(const char* s, const char* chars)
{
#if INI_ALLOW_INLINE_COMMENTS
    int was_space = 0;
    while (*s && (!chars || !strchr(chars, *s)) &&
           !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
        was_space = isspace((unsigned char)(*s));
        s++;
    }
#else
    while (*s && (!chars || !strchr(chars, *s))) {
        s++;
    }
#endif
    return (char*)s;
}
 
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
inline static char* strncpy0(char* dest, const char* src, size_t size)
{
    strncpy(dest, src, size);
    dest[size - 1] = '\0';
    return dest;
}
 
/* See documentation in header file. */
inline int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
                     void* user)
{
    /* Uses a fair bit of stack (use heap instead if you need to) */
#if INI_USE_STACK
    char line[INI_MAX_LINE];
#else
    char* line;
#endif
    char section[MAX_SECTION] = "";
    char prev_name[MAX_NAME] = "";
 
    char* start;
    char* end;
    char* name;
    char* value;
    int lineno = 0;
    int error = 0;
 
#if !INI_USE_STACK
    line = (char*)malloc(INI_MAX_LINE);
    if (!line) {
        return -2;
    }
#endif
 
    /* Scan through stream line by line */
    while (reader(line, INI_MAX_LINE, stream) != NULL) {
        lineno++;
 
        start = line;
#if INI_ALLOW_BOM
        if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
                           (unsigned char)start[1] == 0xBB &&
                           (unsigned char)start[2] == 0xBF) {
            start += 3;
        }
#endif
        start = lskip(rstrip(start));
 
        if (*start == ';' || *start == '#') {
            /* Per Python configparser, allow both ; and # comments at the
               start of a line */
        }
#if INI_ALLOW_MULTILINE
        else if (*prev_name && *start && start > line) {
 
#if INI_ALLOW_INLINE_COMMENTS
        end = find_chars_or_comment(start, NULL);
        if (*end)
            *end = '\0';
        rstrip(start);
#endif
 
            /* Non-blank line with leading whitespace, treat as continuation
               of previous name's value (as per Python configparser). */
            if (!handler(user, section, prev_name, start) && !error)
                error = lineno;
        }
#endif
        else if (*start == '[') {
            /* A "[section]" line */
            end = find_chars_or_comment(start + 1, "]");
            if (*end == ']') {
                *end = '\0';
                strncpy0(section, start + 1, sizeof(section));
                *prev_name = '\0';
            }
            else if (!error) {
                /* No ']' found on section line */
                error = lineno;
            }
        }
        else if (*start) {
            /* Not a comment, must be a name[=:]value pair */
            end = find_chars_or_comment(start, "=:");
            if (*end == '=' || *end == ':') {
                *end = '\0';
                name = rstrip(start);
                value = lskip(end + 1);
#if INI_ALLOW_INLINE_COMMENTS
                end = find_chars_or_comment(value, NULL);
                if (*end)
                    *end = '\0';
#endif
                rstrip(value);
 
                /* Valid name[=:]value pair found, call handler */
                strncpy0(prev_name, name, sizeof(prev_name));
                if (!handler(user, section, name, value) && !error)
                    error = lineno;
            }
            else if (!error) {
                /* No '=' or ':' found on name[=:]value line */
                error = lineno;
            }
        }
 
#if INI_STOP_ON_FIRST_ERROR
        if (error)
            break;
#endif
    }
 
#if !INI_USE_STACK
    free(line);
#endif
 
    return error;
}
 
/* See documentation in header file. */
inline int ini_parse_file(FILE* file, ini_handler handler, void* user)
{
    return ini_parse_stream((ini_reader)fgets, file, handler, user);
}
 
/* See documentation in header file. */
inline int ini_parse(const char* filename, ini_handler handler, void* user)
{
    FILE* file;
    int error;
 
    file = fopen(filename, "r");
    if (!file)
        return -1;
    error = ini_parse_file(file, handler, user);
    fclose(file);
    return error;
}
 
#endif /* __INI_H__ */
 
 
#ifndef __INIREADER_H__
#define __INIREADER_H__
 
#include <map>
#include <set>
#include <string>
 
// Read an INI file into easy-to-access name/value pairs. (Note that I've gone
// for simplicity here rather than speed, but it should be pretty decent.)
class INIReader
{
public:
    // Empty Constructor
    INIReader() {};
 
    // Construct INIReader and parse given filename. See ini.h for more info
    // about the parsing.
    explicit INIReader(const std::string& filename);
 
    // Construct INIReader and parse given file. See ini.h for more info
    // about the parsing.
    explicit INIReader(FILE *file);
 
    // Return the result of ini_parse(), i.e., 0 on success, line number of
    // first error on parse error, or -1 on file open error.
    int ParseError() const;
 
    // Return the list of sections found in ini file
    const std::set<std::string>& Sections() const;
 
    // Get a string value from INI file, returning default_value if not found.
    std::string Get(const std::string& section, const std::string& name,
                    const std::string& default_value) const;
 
    // Get an integer (long) value from INI file, returning default_value if
    // not found or not a valid integer (decimal "1234", "-1234", or hex "0x4d2").
    long GetInteger(const std::string& section, const std::string& name, long default_value) const;
 
    // Get a real (floating point double) value from INI file, returning
    // default_value if not found or not a valid floating point value
    // according to strtod().
    double GetReal(const std::string& section, const std::string& name, double default_value) const;
 
    // Get a single precision floating point number value from INI file, returning
    // default_value if not found or not a valid floating point value
    // according to strtof().
    float GetFloat(const std::string& section, const std::string& name, float default_value) const;
  
    // Get a boolean value from INI file, returning default_value if not found or if
    // not a valid true/false value. Valid true values are "true", "yes", "on", "1",
    // and valid false values are "false", "no", "off", "0" (not case sensitive).
    bool GetBoolean(const std::string& section, const std::string& name, bool default_value) const;
 
protected:
    int _error;
    std::map<std::string, std::string> _values;
    std::set<std::string> _sections;
    static std::string MakeKey(const std::string& section, const std::string& name);
    static int ValueHandler(void* user, const char* section, const char* name,
                            const char* value);
};
 
#endif  // __INIREADER_H__
 
 
#ifndef __INIREADER__
#define __INIREADER__
 
#include <algorithm>
#include <cctype>
#include <cstdlib>
 
inline INIReader::INIReader(const std::string& filename)
{
    _error = ini_parse(filename.c_str(), ValueHandler, this);
}
 
inline INIReader::INIReader(FILE *file)
{
    _error = ini_parse_file(file, ValueHandler, this);
}
 
inline int INIReader::ParseError() const
{
    return _error;
}
 
inline const std::set<std::string>& INIReader::Sections() const
{
    return _sections;
}
 
inline std::string INIReader::Get(const std::string& section, const std::string& name, const std::string& default_value) const
{
    std::string key = MakeKey(section, name);
    return _values.count(key) ? _values.at(key) : default_value;
}
 
inline long INIReader::GetInteger(const std::string& section, const std::string& name, long default_value) const
{
    std::string valstr = Get(section, name, "");
    const char* value = valstr.c_str();
    char* end;
    // This parses "1234" (decimal) and also "0x4D2" (hex)
    long n = strtol(value, &end, 0);
    return end > value ? n : default_value;
}
 
inline double INIReader::GetReal(const std::string& section, const std::string& name, double default_value) const
{
    std::string valstr = Get(section, name, "");
    const char* value = valstr.c_str();
    char* end;
    double n = strtod(value, &end);
    return end > value ? n : default_value;
}
 
inline float INIReader::GetFloat(const std::string& section, const std::string& name, float default_value) const
{
    std::string valstr = Get(section, name, "");
    const char* value = valstr.c_str();
    char* end;
    float n = strtof(value, &end);
    return end > value ? n : default_value;
}
 
inline bool INIReader::GetBoolean(const std::string& section, const std::string& name, bool default_value) const
{
    std::string valstr = Get(section, name, "");
    // Convert to lower case to make string comparisons case-insensitive
    std::transform(valstr.begin(), valstr.end(), valstr.begin(), ::tolower);
    if (valstr == "true" || valstr == "yes" || valstr == "on" || valstr == "1")
        return true;
    else if (valstr == "false" || valstr == "no" || valstr == "off" || valstr == "0")
        return false;
    else
        return default_value;
}
 
inline std::string INIReader::MakeKey(const std::string& section, const std::string& name)
{
    std::string key = section + "=" + name;
    // Convert to lower case to make section/name lookups case-insensitive
    std::transform(key.begin(), key.end(), key.begin(), ::tolower);
    return key;
}
 
inline int INIReader::ValueHandler(void* user, const char* section, const char* name,
                            const char* value)
{
    INIReader* reader = (INIReader*)user;
    std::string key = MakeKey(section, name);
    if (reader->_values[key].size() > 0)
        reader->_values[key] += "\n";
    reader->_values[key] += value;
    reader->_sections.insert(section);
    return 1;
}
 
#endif  // __INIREADER__

2.test.ini

C++实现ini文件读写的示例代码

3.INIReaderTest.cpp

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Example that shows simple usage of the INIReader class
 
#include <iostream>
#include <sstream>
#include "INIReader.h"
 
std::string sections(INIReader &reader)
{
    std::stringstream ss;
    std::set<std::string> sections = reader.Sections();
    for (std::set<std::string>::iterator it = sections.begin(); it != sections.end(); ++it)
        ss << *it << ",";
    return ss.str();
}
 
int main()
{
    INIReader reader("test.ini");
 
    if (reader.ParseError() < 0) {
        std::cout << "Can't load 'test.ini'\n";
        return 1;
    }
    std::cout << "Config loaded from 'test.ini': found sections=" << sections(reader)
              << " version="
              << reader.GetInteger("protocol", "version", -1) << ", name="
              << reader.Get("user", "name", "UNKNOWN") << ", email="
              << reader.Get("user", "email", "UNKNOWN") << ", multi="
              << reader.Get("user", "multi", "UNKNOWN") << ", pi="
              << reader.GetReal("user", "pi", -1) << ", active="
              << reader.GetBoolean("user", "active", true) << "\n";
    return 0;
}

2.使用ini.h头文件

现代 c++ 的另一个 .ini 解析器(为 cpp17 制作),灵感来自 inih 并进行了扩展。

1.ini.h

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
/**
 * Yet another .ini parser for modern c++ (made for cpp17), inspired and extend
 * from @benhoyt's inih. See project page: https://github.com/SSARCandy/ini-cpp
 */
 
#ifndef __INI_H__
#define __INI_H__
 
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
 
#include <algorithm>
#include <cctype>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <iterator>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <vector>
 
namespace inih {
 
/* Typedef for prototype of handler function. */
typedef int (*ini_handler)(void* user, const char* section, const char* name,
                           const char* value);
 
/* Typedef for prototype of fgets-style reader function. */
typedef char* (*ini_reader)(char* str, int num, void* stream);
 
#define INI_STOP_ON_FIRST_ERROR 1
#define INI_MAX_LINE 2000
#define INI_INITIAL_ALLOC 200
#define MAX_SECTION 50
#define MAX_NAME 50
#define INI_START_COMMENT_PREFIXES ";#"
#define INI_INLINE_COMMENT_PREFIXES ";"
 
/* Strip whitespace chars off end of given string, in place. Return s. */
inline static char* rstrip(char* s) {
    char* p = s + strlen(s);
    while (p > s && isspace((unsigned char)(*--p))) *p = '\0';
    return s;
}
 
/* Return pointer to first non-whitespace char in given string. */
inline static char* lskip(const char* s) {
    while (*s && isspace((unsigned char)(*s))) s++;
    return (char*)s;
}
 
/* Return pointer to first char (of chars) or inline comment in given string,
   or pointer to null at end of string if neither found. Inline comment must
   be prefixed by a whitespace character to register as a comment. */
inline static char* find_chars_or_comment(const char* s, const char* chars) {
    int was_space = 0;
    while (*s && (!chars || !strchr(chars, *s)) &&
           !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
        was_space = isspace((unsigned char)(*s));
        s++;
    }
    return (char*)s;
}
 
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
inline static char* strncpy0(char* dest, const char* src, size_t size) {
    strncpy(dest, src, size - 1);
    dest[size - 1] = '\0';
    return dest;
}
 
/* See documentation in header file. */
inline int ini_parse_stream(ini_reader reader, void* stream,
                            ini_handler handler, void* user) {
    /* Uses a fair bit of stack (use heap instead if you need to) */
    char* line;
    size_t max_line = INI_INITIAL_ALLOC;
    char* new_line;
    size_t offset;
    char section[MAX_SECTION] = "";
    char prev_name[MAX_NAME] = "";
 
    char* start;
    char* end;
    char* name;
    char* value;
    int lineno = 0;
    int error = 0;
 
    line = (char*)malloc(INI_INITIAL_ALLOC);
    if (!line) {
        return -2;
    }
 
#if INI_HANDLER_LINENO
#define HANDLER(u, s, n, v) handler(u, s, n, v, lineno)
#else
#define HANDLER(u, s, n, v) handler(u, s, n, v)
#endif
 
    /* Scan through stream line by line */
    while (reader(line, (int)max_line, stream) != NULL) {
        offset = strlen(line);
        while (offset == max_line - 1 && line[offset - 1] != '\n') {
            max_line *= 2;
            if (max_line > INI_MAX_LINE) max_line = INI_MAX_LINE;
            new_line = (char*)realloc(line, max_line);
            if (!new_line) {
                free(line);
                return -2;
            }
            line = new_line;
            if (reader(line + offset, (int)(max_line - offset), stream) == NULL)
                break;
            if (max_line >= INI_MAX_LINE) break;
            offset += strlen(line + offset);
        }
 
        lineno++;
 
        start = line;
        if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
            (unsigned char)start[1] == 0xBB &&
            (unsigned char)start[2] == 0xBF) {
            start += 3;
        }
        start = lskip(rstrip(start));
 
        if (strchr(INI_START_COMMENT_PREFIXES, *start)) {
            /* Start-of-line comment */
        } else if (*start == '[') {
            /* A "[section]" line */
            end = find_chars_or_comment(start + 1, "]");
            if (*end == ']') {
                *end = '\0';
                strncpy0(section, start + 1, sizeof(section));
                *prev_name = '\0';
            } else if (!error) {
                /* No ']' found on section line */
                error = lineno;
            }
        } else if (*start) {
            /* Not a comment, must be a name[=:]value pair */
            end = find_chars_or_comment(start, "=:");
            if (*end == '=' || *end == ':') {
                *end = '\0';
                name = rstrip(start);
                value = end + 1;
                end = find_chars_or_comment(value, NULL);
                if (*end) *end = '\0';
                value = lskip(value);
                rstrip(value);
 
                /* Valid name[=:]value pair found, call handler */
                strncpy0(prev_name, name, sizeof(prev_name));
                if (!HANDLER(user, section, name, value) && !error)
                    error = lineno;
            } else if (!error) {
                /* No '=' or ':' found on name[=:]value line */
                error = lineno;
            }
        }
 
        if (error) break;
    }
 
    free(line);
 
    return error;
}
 
inline int ini_parse_file(FILE* file, ini_handler handler, void* user) {
    return ini_parse_stream((ini_reader)fgets, file, handler, user);
}
 
inline int ini_parse(const char* filename, ini_handler handler, void* user) {
    FILE* file;
    int error;
 
    file = fopen(filename, "r");
    if (!file) return -1;
    error = ini_parse_file(file, handler, user);
    fclose(file);
    return error;
}
 
#endif /* __INI_H__ */
 
#ifndef __INIREADER_H__
#define __INIREADER_H__
 
// Read an INI file into easy-to-access name/value pairs. (Note that I've gone
// for simplicity here rather than speed, but it should be pretty decent.)
class INIReader {
   public:
    // Empty Constructor
    INIReader(){};
 
    // Construct INIReader and parse given filename. See ini.h for more info
    // about the parsing.
    INIReader(std::string filename);
 
    // Construct INIReader and parse given file. See ini.h for more info
    // about the parsing.
    INIReader(FILE* file);
 
    // Return the result of ini_parse(), i.e., 0 on success, line number of
    // first error on parse error, or -1 on file open error.
    int ParseError() const;
 
    // Return the list of sections found in ini file
    const std::set<std::string> Sections() const;
 
    // Return the list of keys in the given section
    const std::set<std::string> Keys(std::string section) const;
 
    const std::unordered_map<std::string, std::string> Get(
        std::string section) const;
 
    template <typename T = std::string>
    T Get(const std::string& section, const std::string& name) const;
 
    template <typename T>
    T Get(const std::string& section, const std::string& name,
          T&& default_v) const;
 
    template <typename T = std::string>
    std::vector<T> GetVector(const std::string& section,
                             const std::string& name) const;
 
    template <typename T>
    std::vector<T> GetVector(const std::string& section,
                             const std::string& name,
                             const std::vector<T>& default_v) const;
 
    template <typename T = std::string>
    void InsertEntry(const std::string& section, const std::string& name,
                     const T& v);
 
    template <typename T = std::string>
    void InsertEntry(const std::string& section, const std::string& name,
                     const std::vector<T>& vs);
 
    template <typename T = std::string>
    void UpdateEntry(const std::string& section, const std::string& name,
                     const T& v);
 
    template <typename T = std::string>
    void UpdateEntry(const std::string& section, const std::string& name,
                     const std::vector<T>& vs);
 
   protected:
    int _error;
    std::unordered_map<std::string,
                       std::unordered_map<std::string, std::string>>
        _values;
    static int ValueHandler(void* user, const char* section, const char* name,
                            const char* value);
 
    template <typename T>
    T Converter(const std::string& s) const;
 
    const bool BoolConverter(std::string s) const;
 
    template <typename T>
    std::string V2String(const T& v) const;
 
    template <typename T>
    std::string Vec2String(const std::vector<T>& v) const;
};
 
#endif  // __INIREADER_H__
 
#ifndef __INIREADER__
#define __INIREADER__
 
inline INIReader::INIReader(std::string filename) {
    _error = ini_parse(filename.c_str(), ValueHandler, this);
    ParseError();
}
 
inline INIReader::INIReader(FILE* file) {
    _error = ini_parse_file(file, ValueHandler, this);
    ParseError();
}
 
inline int INIReader::ParseError() const {
    switch (_error) {
        case 0:
            break;
        case -1:
            throw std::runtime_error("ini file not found.");
        case -2:
            throw std::runtime_error("memory alloc error");
        default:
            throw std::runtime_error("parse error on line no: " +
                                     std::to_string(_error));
    }
    return 0;
}
 
/**
 * @brief Return the list of sections found in ini file
 * @return The list of sections found in ini file
 *
 *
 */
inline const std::set<std::string> INIReader::Sections() const {
    std::set<std::string> retval;
    for (auto const& element : _values) {
        retval.insert(element.first);
    }
    return retval;
}
 
/**
 * @brief Return the list of keys in the given section
 * @param section The section name
 * @return The list of keys in the given section
 */
inline const std::set<std::string> INIReader::Keys(std::string section) const {
    auto const _section = Get(section);
    std::set<std::string> retval;
    for (auto const& element : _section) {
        retval.insert(element.first);
    }
    return retval;
}
 
inline const std::unordered_map<std::string, std::string> INIReader::Get(
    std::string section) const {
    auto const _section = _values.find(section);
    if (_section == _values.end()) {
        throw std::runtime_error("section '" + section + "' not found.");
    }
    return _section->second;
}
 
/**
 * @brief Return the value of the given key in the given section
 * @param section The section name
 * @param name The key name
 * @return The value of the given key in the given section
 */
template <typename T>
inline T INIReader::Get(const std::string& section,
                        const std::string& name) const {
    auto const _section = Get(section);
    auto const _value = _section.find(name);
 
    if (_value == _section.end()) {
        throw std::runtime_error("key '" + name + "' not found in section '" +
                                 section + "'.");
    }
 
    std::string value = _value->second;
 
    if constexpr (std::is_same<T, std::string>()) {
        return value;
    } else if constexpr (std::is_same<T, bool>()) {
        return BoolConverter(value);
    } else {
        return Converter<T>(value);
    };
}
 
/**
 * @brief Return the value of the given key in the given section, return default
 * if not found
 * @param section The section name
 * @param name The key name
 * @param default_v The default value
 * @return The value of the given key in the given section, return default if
 * not found
 */
template <typename T>
inline T INIReader::Get(const std::string& section, const std::string& name,
                        T&& default_v) const {
    try {
        return Get<T>(section, name);
    } catch (std::runtime_error& e) {
        return default_v;
    }
}
 
/**
 * @brief Return the value array of the given key in the given section.
 * @param section The section name
 * @param name The key name
 * @return The value array of the given key in the given section.
 *
 * For example:
 * ```ini
 * [section]
 * key = 1 2 3 4
 * ```
 * ```cpp
 * const auto vs = ini.GetVector<std::vector<int>>("section", "key");
 * // vs = {1, 2, 3, 4}
 * ```
 */
template <typename T>
inline std::vector<T> INIReader::GetVector(const std::string& section,
                                           const std::string& name) const {
    std::string value = Get(section, name);
 
    std::istringstream out{value};
    const std::vector<std::string> strs{std::istream_iterator<std::string>{out},
                                        std::istream_iterator<std::string>()};
    try {
        std::vector<T> vs{};
        for (const std::string& s : strs) {
            vs.emplace_back(Converter<T>(s));
        }
        return vs;
    } catch (std::exception& e) {
        throw std::runtime_error("cannot parse value " + value +
                                 " to vector<T>.");
    }
}
 
/**
 * @brief Return the value array of the given key in the given section, return
 * default if not found
 * @param section The section name
 * @param name The key name
 * @param default_v The default value
 * @return The value array of the given key in the given section, return default
 * if not found
 *
 * @see INIReader::GetVector
 */
template <typename T>
inline std::vector<T> INIReader::GetVector(
    const std::string& section, const std::string& name,
    const std::vector<T>& default_v) const {
    try {
        return GetVector<T>(section, name);
    } catch (std::runtime_error& e) {
        return default_v;
    };
}
 
template <typename T>
inline void INIReader::InsertEntry(const std::string& section,
                                   const std::string& name, const T& v) {
    if (_values[section][name].size() > 0) {
        throw std::runtime_error("duplicate key '" + std::string(name) +
                                 "' in section '" + section + "'.");
    }
    _values[section][name] = V2String(v);
}
 
template <typename T>
inline void INIReader::InsertEntry(const std::string& section,
                                   const std::string& name,
                                   const std::vector<T>& vs) {
    if (_values[section][name].size() > 0) {
        throw std::runtime_error("duplicate key '" + std::string(name) +
                                 "' in section '" + section + "'.");
    }
    _values[section][name] = Vec2String(vs);
}
 
template <typename T>
inline void INIReader::UpdateEntry(const std::string& section,
                                   const std::string& name, const T& v) {
    if (!_values[section][name].size()) {
        throw std::runtime_error("key '" + std::string(name) +
                                 "' not exist in section '" + section + "'.");
    }
    _values[section][name] = V2String(v);
}
 
template <typename T>
inline void INIReader::UpdateEntry(const std::string& section,
                                   const std::string& name,
                                   const std::vector<T>& vs) {
    if (!_values[section][name].size()) {
        throw std::runtime_error("key '" + std::string(name) +
                                 "' not exist in section '" + section + "'.");
    }
    _values[section][name] = Vec2String(vs);
}
 
template <typename T>
inline std::string INIReader::V2String(const T& v) const {
    std::stringstream ss;
    ss << v;
    return ss.str();
}
 
template <typename T>
inline std::string INIReader::Vec2String(const std::vector<T>& v) const {
    if (v.empty()) {
        return "";
    }
    std::ostringstream oss;
    std::copy(v.begin(), v.end() - 1, std::ostream_iterator<T>(oss, " "));
    oss << v.back();
 
    return oss.str();
}
 
template <typename T>
inline T INIReader::Converter(const std::string& s) const {
    try {
        T v{};
        std::istringstream _{s};
        _.exceptions(std::ios::failbit);
        _ >> v;
        return v;
    } catch (std::exception& e) {
        throw std::runtime_error("cannot parse value '" + s + "' to type<T>.");
    };
}
 
inline const bool INIReader::BoolConverter(std::string s) const {
    std::transform(s.begin(), s.end(), s.begin(), ::tolower);
    static const std::unordered_map<std::string, bool> s2b{
        {"1", true},  {"true", true},   {"yes", true}, {"on", true},
        {"0", false}, {"false", false}, {"no", false}, {"off", false},
    };
    auto const value = s2b.find(s);
    if (value == s2b.end()) {
        throw std::runtime_error("'" + s + "' is not a valid boolean value.");
    }
    return value->second;
}
 
inline int INIReader::ValueHandler(void* user, const char* section,
                                   const char* name, const char* value) {
    INIReader* reader = (INIReader*)user;
    if (reader->_values[section][name].size() > 0) {
        throw std::runtime_error("duplicate key '" + std::string(name) +
                                 "' in section '" + section + "'.");
    }
    reader->_values[section][name] = value;
    return 1;
}
#endif  // __INIREADER__
 
#ifndef __INIWRITER_H__
#define __INIWRITER_H__
 
class INIWriter {
   public:
    INIWriter(){};
    inline static void write(const std::string& filepath,
                             const INIReader& reader) {
        if (struct stat buf; stat(filepath.c_str(), &buf) == 0) {
            throw std::runtime_error("file: " + filepath + " already exist.");
        }
        std::ofstream out;
        out.open(filepath);
        if (!out.is_open()) {
            throw std::runtime_error("cannot open output file: " + filepath);
        }
        for (const auto& section : reader.Sections()) {
            out << "[" << section << "]\n";
            for (const auto& key : reader.Keys(section)) {
                out << key << "=" << reader.Get(section, key) << "\n";
            }
        }
        out.close();
    }
};
}
#endif /* __INIWRITER_H__ */

2.config.ini

C++实现ini文件读写的示例代码

3.example.cpp

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
#include <string>
#include <typeinfo>
#include <boost/core/demangle.hpp>
 
#include "ini/ini.h"
using namespace inih;
 
namespace bc = boost::core;
 
int main() {
    INIReader r{"./test/fixtures/config.ini"};
 
    const auto& v1 = r.Get<std::string>("section1", "any");
    const auto& v2 = r.Get<int>("section1", "any");
    const auto& v3 = r.Get<double>("section1", "any");
    const auto& v4 = r.GetVector<float>("section2", "any_vec");
    const auto& v5{r.GetVector<std::string>("section2", "any_vec")};
 
    /** output
     * v1 = "1"             type: std::string
     * v2 = 1               type: int
     * v3 = 1.0             type: double
     * v4 = [1, 2, 3]       type: std::vector<float>
     * v5 = ["1", "2", "3"] type: std::vector<std::string>
     */
 
    std::cout << "v1 = " << v1 << ", which is type: " << bc::demangle(typeid(v1).name()) << std::endl;
    std::cout << "v2 = " << v2 << ", which is type: " << bc::demangle(typeid(v2).name()) << std::endl;
    std::cout << "v3 = " << v3 << ", which is type: " << bc::demangle(typeid(v3).name()) << std::endl;
    std::cout << "v4 = "; for (auto& v : v4) std::cout << v << " "; std::cout << ", which is type: " << bc::demangle(typeid(v4).name()) << std::endl;
    std::cout << "v5 = "; for (auto& v : v5) std::cout << v << " "; std::cout << ", which is type: " << bc::demangle(typeid(v5).name()) << std::endl;
 
    // section exist, key not exist
    r.InsertEntry("section1", "my_custom_key", "hello world");
 
    // section&key not exist
    r.InsertEntry("new_section", "key1", 5);
 
    // Dump ini to file
    INIWriter::write("output.ini", r);
 
    return 0;
}

3.使用inipp.h头文件

3.1 解析算法

section被设置为空字符串

从文件中读取每一行并从空白处修剪。

  • 如果行为空或以;开始然后什么都没发生。
  • 否则,如果行以 [ 开头,则section将更改为 [ 和 ] 之间的字符串。如果行不以 ] 结尾,则报告错误。
  • 否则,如果行包含 = 符号,则 = 之前的所有字符都被视为变量, = 之后的所有字符都被视为值。两者都被修剪。如果变量之前已经赋值,则会报告错误。否则,将相应的赋值添加到该section。
  • 否则,该行被报告为错误。

3.2 默认section算法

将默认section中的每个变量插入到其他每个section中,而不覆盖现有变量。

3.3 Interpolation算法

1.每个section内部,遇到的每个variable都被{section:variable}代替

2.每个{section:variable}都被它的值代替

3.重复上一步,直到无法再进行替换,或者直到达到递归深度(默认为 10)。

3.4 代码实现

1.inipp.h

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
/*
MIT License
Copyright (c) 2017-2020 Matthias C. M. Troffaes
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
 
#pragma once
 
#include <algorithm>
#include <cctype>
#include <cstring>
#include <functional>
#include <iostream>
#include <list>
#include <vector>
#include <locale>
#include <map>
#include <memory>
#include <sstream>
#include <string>
 
namespace inipp {
 
namespace detail {
 
// trim functions based on http://stackoverflow.com/a/217605
 
template <class CharT>
inline void ltrim(std::basic_string<CharT> & s, const std::locale & loc) {
    s.erase(s.begin(),
                std::find_if(s.begin(), s.end(),
                             [&loc](CharT ch) { return !std::isspace(ch, loc); }));
}
 
template <class CharT>
inline void rtrim(std::basic_string<CharT> & s, const std::locale & loc) {
    s.erase(std::find_if(s.rbegin(), s.rend(),
                             [&loc](CharT ch) { return !std::isspace(ch, loc); }).base(),
                s.end());
}
 
template <class CharT, class UnaryPredicate>
inline void rtrim2(std::basic_string<CharT>& s, UnaryPredicate pred) {
    s.erase(std::find_if(s.begin(), s.end(), pred), s.end());
}
 
// string replacement function based on http://stackoverflow.com/a/3418285
 
template <class CharT>
inline bool replace(std::basic_string<CharT> & str, const std::basic_string<CharT> & from, const std::basic_string<CharT> & to) {
    auto changed = false;
    size_t start_pos = 0;
    while ((start_pos = str.find(from, start_pos)) != std::basic_string<CharT>::npos) {
        str.replace(start_pos, from.length(), to);
        start_pos += to.length();
        changed = true;
    }
    return changed;
}
 
} // namespace detail
 
template <typename CharT, typename T>
inline bool extract(const std::basic_string<CharT> & value, T & dst) {
    CharT c;
    std::basic_istringstream<CharT> is{ value };
    T result;
    if ((is >> std::boolalpha >> result) && !(is >> c)) {
        dst = result;
        return true;
    }
    else {
        return false;
    }
}
 
template <typename CharT>
inline bool extract(const std::basic_string<CharT> & value, std::basic_string<CharT> & dst) {
    dst = value;
    return true;
}
 
template <typename CharT, typename T>
inline bool get_value(const std::map<std::basic_string<CharT>, std::basic_string<CharT>> & sec, const std::basic_string<CharT> & key, T & dst) {
    const auto it = sec.find(key);
    if (it == sec.end()) return false;
    return extract(it->second, dst);
}
 
template <typename CharT, typename T>
inline bool get_value(const std::map<std::basic_string<CharT>, std::basic_string<CharT>>& sec, const CharT* key, T& dst) {
    return get_value(sec, std::basic_string<CharT>(key), dst);
}
 
template<class CharT>
class Format
{
public:
    // used for generating
    const CharT char_section_start;
    const CharT char_section_end;
    const CharT char_assign;
    const CharT char_comment;
 
    // used for parsing
    virtual bool is_section_start(CharT ch) const { return ch == char_section_start; }
    virtual bool is_section_end(CharT ch) const { return ch == char_section_end; }
    virtual bool is_assign(CharT ch) const { return ch == char_assign; }
    virtual bool is_comment(CharT ch) const { return ch == char_comment; }
 
    // used for interpolation
    const CharT char_interpol;
    const CharT char_interpol_start;
    const CharT char_interpol_sep;
    const CharT char_interpol_end;
 
    Format(CharT section_start, CharT section_end, CharT assign, CharT comment, CharT interpol, CharT interpol_start, CharT interpol_sep, CharT interpol_end)
        : char_section_start(section_start)
        , char_section_end(section_end)
        , char_assign(assign)
        , char_comment(comment)
        , char_interpol(interpol)
        , char_interpol_start(interpol_start)
        , char_interpol_sep(interpol_sep)
        , char_interpol_end(interpol_end) {}
 
    Format() : Format('[', ']', '=', ';', '$', '{', ':', '}') {}
 
    const std::basic_string<CharT> local_symbol(const std::basic_string<CharT>& name) const {
        return char_interpol + (char_interpol_start + name + char_interpol_end);
    }
 
    const std::basic_string<CharT> global_symbol(const std::basic_string<CharT>& sec_name, const std::basic_string<CharT>& name) const {
        return local_symbol(sec_name + char_interpol_sep + name);
    }
};
 
template<class CharT>
class Ini
{
public:
    using String = std::basic_string<CharT>;
    using Section = std::map<String, String>;
    using Sections = std::map<String, Section>;
 
    Sections sections;
    std::list<String> errors;
    std::shared_ptr<Format<CharT>> format;
 
    static const int max_interpolation_depth = 10;
 
    Ini() : format(std::make_shared<Format<CharT>>()) {};
    Ini(std::shared_ptr<Format<CharT>> fmt) : format(fmt) {};
 
    void generate(std::basic_ostream<CharT>& os) const {
        for (auto const & sec : sections) {
            os << format->char_section_start << sec.first << format->char_section_end << std::endl;
            for (auto const & val : sec.second) {
                os << val.first << format->char_assign << val.second << std::endl;
            }
            os << std::endl;
        }
    }
 
    void parse(std::basic_istream<CharT> & is) {
        String line;
        String section;
        const std::locale loc{"C"};
        while (std::getline(is, line)) {
            detail::ltrim(line, loc);
            detail::rtrim(line, loc);
            const auto length = line.length();
            if (length > 0) {
                const auto pos = std::find_if(line.begin(), line.end(), [this](CharT ch) { return format->is_assign(ch); });
                const auto & front = line.front();
                if (format->is_comment(front)) {
                }
                else if (format->is_section_start(front)) {
                    if (format->is_section_end(line.back()))
                        section = line.substr(1, length - 2);
                    else
                        errors.push_back(line);
                }
                else if (pos != line.begin() && pos != line.end()) {
                    String variable(line.begin(), pos);
                    String value(pos + 1, line.end());
                    detail::rtrim(variable, loc);
                    detail::ltrim(value, loc);
                    auto & sec = sections[section];
                    if (sec.find(variable) == sec.end())
                        sec.emplace(variable, value);
                    else
                        errors.push_back(line);
                }
                else {
                    errors.push_back(line);
                }
            }
        }
    }
 
    void interpolate() {
        int global_iteration = 0;
        auto changed = false;
        // replace each "variable"by"{section:variable}"
        for (auto & sec : sections)
            replace_symbols(local_symbols(sec.first, sec.second), sec.second);
        // replace each "${section:variable}" by its value
        do {
            changed = false;
            const auto syms = global_symbols();
            for (auto & sec : sections)
                changed |= replace_symbols(syms, sec.second);
        } while (changed && (max_interpolation_depth > global_iteration++));
    }
 
    void default_section(const Section & sec) {
        for (auto & sec2 : sections)
            for (const auto & val : sec)
                sec2.second.insert(val);
    }
 
    void strip_trailing_comments() {
        const std::locale loc{ "C" };
        for (auto & sec : sections)
            for (auto & val : sec.second) {
                detail::rtrim2(val.second, [this](CharT ch) { return format->is_comment(ch); });
                detail::rtrim(val.second, loc);
            }
    }
 
    void clear() {
        sections.clear();
        errors.clear();
    }
 
private:
    using Symbols = std::vector<std::pair<String, String>>;
 
    const Symbols local_symbols(const String & sec_name, const Section & sec) const {
        Symbols result;
        for (const auto & val : sec)
            result.emplace_back(format->local_symbol(val.first), format->global_symbol(sec_name, val.first));
        return result;
    }
 
    const Symbols global_symbols() const {
        Symbols result;
        for (const auto & sec : sections)
            for (const auto & val : sec.second)
                result.emplace_back(format->global_symbol(sec.first, val.first), val.second);
        return result;
    }
 
    bool replace_symbols(const Symbols & syms, Section & sec) const {
        auto changed = false;
        for (auto & sym : syms)
            for (auto & val : sec)
                changed |= detail::replace(val.second, sym.first, sym.second);
        return changed;
    }
};
 
} // namespace inipp

2.example.ini

C++实现ini文件读写的示例代码

3.example.cpp

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <fstream>
#include "inipp.h"
 
int main() {
    inipp::Ini<char> ini;
    std::ifstream is("example.ini");
    ini.parse(is);
    std::cout << "raw ini file:" << std::endl;
    ini.generate(std::cout);
    ini.default_section(ini.sections["DEFAULT"]);
    ini.interpolate();
    std::cout << "ini file after default section and interpolation:" << std::endl;
    ini.generate(std::cout);
    int compression_level = -1;
    inipp::get_value(ini.sections["bitbucket.org"], "CompressionLevel", compression_level);
    std::cout << "bitbucket.org compression level: " << compression_level << std::endl;
    return 0;
}

到此这篇关于C++实现ini文件读写的示例代码的文章就介绍到这了,更多相关C++读写ini文件内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/weixin_43229348/article/details/124616107

延伸 · 阅读

精彩推荐
  • C/C++C语言实现飞机票务系统

    C语言实现飞机票务系统

    这篇文章主要为大家详细介绍了C语言实现飞机票务系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    bingongzi9942021-08-11
  • C/C++C++ DFS算法实现走迷宫自动寻路

    C++ DFS算法实现走迷宫自动寻路

    这篇文章主要为大家详细介绍了C++ DFS算法实现走迷宫自动寻路,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    白家名12212021-11-08
  • C/C++c++运算符重载基础知识详解

    c++运算符重载基础知识详解

    运算符重载是一种形式的C++多态。运算符重载将重载的概念扩展到运算符上,允许赋予C++运算符多种含义...

    C++教程网6242021-01-17
  • C/C++Qt 实现画线笔锋效果详细原理及示例代码

    Qt 实现画线笔锋效果详细原理及示例代码

    这篇文章主要介绍了Qt 实现画线笔锋效果详细原理及示例代码。文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    luoyayun3618502021-08-30
  • C/C++C++vector的用法你都知道嘛

    C++vector的用法你都知道嘛

    这篇文章主要为大家详细介绍了C++中vector的用法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带...

    菜鸡圣龙进化菜松鼠5632022-09-26
  • C/C++基于条件变量的消息队列 说明介绍

    基于条件变量的消息队列 说明介绍

    本篇文章小编为大家介绍,基于条件变量的消息队列 说明介绍。需要的朋友参考一下...

    C语言之家5312020-11-20
  • C/C++VC实现将网址解析出所有ip地址的实例代码

    VC实现将网址解析出所有ip地址的实例代码

    这篇文章主要介绍了VC实现将网址解析出所有ip地址的实例代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可...

    小道安全10872021-10-29
  • C/C++基于C++实现kinect+opencv 获取深度及彩色数据

    基于C++实现kinect+opencv 获取深度及彩色数据

    本文的主要思想是Kinect SDK 读取彩色、深度、骨骼信息并用OpenCV显示,非常的实用,有需要的小伙伴可以参考下...

    C++教程网6252021-03-18