I need to read parameters from a txt file for my program in Linux. But the result is that some of the parameters read from the txt file have the correct value, but some of them have a wrong value. Somebody has met this problem? I have translated the format of the txt in windows into Linux with the command dos2unix. I need your help, Thanks.
The read function is as follows:
template <class T>int ReadFileVar(ifstream *inClientFile, const char var_name[], T *var)
{
//inClientFile - pointer to the previously opened File stream
//var_name - contains the name of the variable
//var - pointer to a long, the function will return the value of the variable in this
int length_var_name = (int) strlen(var_name);
char line[512];
int i, j;
while (inClientFile->getline(line,512))
{
if (line[0] != '/' && line[1] != '/')
{
i = 0;
while (line[i] != '\0')
{
if (!strncmp(&line[i],var_name,length_var_name))
{
j = i + length_var_name;
while (line[j] != '\0')
{
if ( line[j] >= '0' && line[j] <= '9')
{
*var = (T) atof(&line[j]);
inClientFile->seekg( 0, ios_base::beg ); //back to the beginning of the file
return 0;
}
j++;
}
}
i++;
}
}
}
cerr << var_name << " - cannot be found" << endl;
throw "error reading input data from: ";
return 1; //the specified variable was not found in the file
}
For example:
the parameters in the txt are as follows:,the type of them are long,
nx=100;
ny=100;
nz=100;
ipro=1;
jpro=1;
kpro=1;
but after reading the txt in my program I get these,
nx=100;
ny=100;
nz=15;
ipro=1;
jpro=1;
kpro=100;
I have tested the program under Windows, there it works!
Your code works for me, you must have an error somewhere else or an undefined behavior I didn't spot.
May I suggest a more C++ way to do exactly the same thing :
template <class T>
T ReadFileVar(ifstream& inClientFile, string var_name)
{
string line;
while (getline(inClientFile, line))
{
if (line[0] != '/' && line[1] != '/')
{
size_t pos = line.find(var_name);
if( pos != string::npos) {
pos = line.find('=', pos + 1);
if(pos == string::npos) {
throw std::exception();
}
istringstream iss(line.substr(pos + 1));
T result;
iss >> result;
inClientFile.seekg( 0, ios_base::beg );
return result;
}
}
}
throw std::exception();
}
You could also parse the whole file and store the result in a map instead of searching the whole file for each variable :
map<string, string> ParseFile(ifstream& inClientFile) {
map<string, string> result;
string line;
while (getline(inClientFile, line))
{
if (line[0] != '/' && line[1] != '/')
{
size_t pos = line.find('=');
if(pos == string::npos) {
throw std::exception();
}
string var_name = line.substr(0, pos);
string var_value = line.substr(pos + 1);
result[var_name] = var_value;
}
}
return result;
}
template <class T>
T ReadVar(map<string, string> data, string var_name)
{
map<string, string>::iterator it = data.find(var_name);
if(it == data.end()) {
throw exception();
}
string value = it->second;
istringstream iss(value);
T result;
iss >> result;
return result;
}
Related
I am writing a program which reads, parses, and writes large (~15Gb) text files in parallel. On a single thread, the program works very quickly, but there is a massive performance drop when I run it concurrently on several jobs (much more than to be expected from multithreading overhead).
The main file-reading/writing function takes an "SRA" object, which has two corresponding files associated with it, and the amount of RAM to dedicate, in bytes, as input. The function then reads the files chunk-buffer-wise and writes two new files that omit "error" information. The two files correspond to one another, with the information therein order-dependent. Their structure is not super important, but they look like this:
#SRR1000000.1 cor
ATATTTACCGGGTTATTCGGATTAGTTTTGGGCCCCCC
+
FFFFF:::F:::F:::,FFFF:::::::FFFFF,,,,F
#SRR1000000.2 error
ATTTTTTTTTCCCCCCGGCGGCGCGGCTTCTCGGTTAA
+
FF:FF:::::F::F::,,,,,:FFFFF,,F,F:,FF:F
#SRR1000000.3
ATTTTTTTTTCCCCCCGGCGGCGCGGCTTCTCGGTTAA
+
FF:FF:::::F::F::,,,,,:FFFFF,,F,F:,FF:F
.
.
.
The "header", beginning with "#", is associated with and identifies the next 3 lines of data, and the number after the "." denotes the order. Both files have these headers.
Below is the file reader, parser, writer function mentioned above:
// File read/parse/write function
// Takes SRA object, amount of RAM as input
// Reads objects associated files in chunks according to RAM
// Parses them to remove "errors" while writing to new files
void rem_unfix(SRA sra, long long int ram_b) {
// Get in-file / out-file paths
std::string inFile1Str(sra.get_sra_path_corr().first.c_str());
std::string inFile2Str(sra.get_sra_path_corr().second.c_str());
std::string outFile1Str(std::string(sra.get_sra_path_corr().first.replace_extension("fix.fq").c_str()));
std::string outFile2Str(std::string(sra.get_sra_path_corr().second.replace_extension("fix.fq").c_str()));
// Open streams for file processing
std::ifstream inFile1(inFile1Str);
std::ifstream inFile2(inFile2Str);
std::ofstream outFile1(outFile1Str);
std::ofstream outFile2(outFile2Str);
// Get amount of RAM to dedicate to each file (bytes)
long long int ram_b_per_file = ram_b / 2;
// Allocate space on heap for the file buffers
char * inFile1Data = new char[ram_b_per_file];
char * inFile2Data = new char[ram_b_per_file];
// Algorithmic pointer/size variables to aid in parsing
std::streamsize s1;
std::streamsize s2;
char * currPos1;
char * currPos2;
char * nlPos1;
char * nlPos2;
char * nlPos1Prev;
char * nlPos2Prev;
char * writeStart1;
char * writeStart2;
char * writeEnd1;
char * writeEnd2;
char * inFile1L;
char * inFile2L;
// Strings to ensure ends of buffers are lined up before parsing
std::string readMatch;
std::string read;
// Main loop processes files in RAM-determined chunks
while (!inFile1.eof() || !inFile2.eof()) {
// Fill buffers, count number of bytes read to account for
// end-of-file condition
inFile1.read(inFile1Data, ram_b_per_file);
inFile2.read(inFile2Data, ram_b_per_file);
s1 = inFile1.gcount();
s2 = inFile2.gcount();
currPos1 = inFile1Data;
currPos2 = inFile2Data;
nlPos1 = inFile1Data;
nlPos2 = inFile2Data;
writeStart1 = inFile1Data;
writeStart2 = inFile2Data;
inFile1L = inFile1Data + s1;
inFile2L = inFile2Data + s2;
// Line up the ends of the buffers / ifstreams so that all
// information is "paired", or that there is no piece of
// data in one buffer without its partner data in the other
if (!inFile1.eof() && !inFile2.eof()) {
// Unget/unstream character-wise until one of the buffers/ifstreams
// ends just before a header
while ((inFile1.peek() != '#' && inFile1.peek() != '>') &&
(inFile2.peek() != '#' && inFile2.peek() != '>')) {
if (inFile1.peek() != '#' && inFile1.peek() != '>') {
inFile1.unget();
inFile1Data[s1 - 1] = '\0';
s1--;
}
if (inFile2.peek() != '#' && inFile2.peek() != '>') {
inFile2.unget();
inFile2Data[s2 - 1] = '\0';
s2--;
}
}
// If inFile1's buffer was was first to get into position
// Get its header number, get inFile2's last header number.
// Then unstream accordingly until the two buffers end at the
// same data point in their files.
if (inFile1.peek() == '#' || inFile1.peek() == '>') {
inFile1.get();
inFile1 >> readMatch;
while (inFile1.peek() != '#' && inFile1.peek() != '>') {
inFile1.unget();
}
while (inFile2.peek() != '#' && inFile2.peek() != '>') {
inFile2.unget();
inFile2Data[s2 - 1] = '\0';
s2--;
}
inFile2.get();
inFile2 >> read;
while (inFile2.peek() != '#' && inFile2.peek() != '>') {
inFile2.unget();
}
if (read > readMatch) {
inFile2.unget();
while (read.compare(readMatch) != 0) {
while (inFile2.peek() != '#' && inFile2.peek() != '>') {
inFile2.unget();
inFile2Data[s2 - 1] = '\0';
s2--;
}
inFile2.get();
inFile2 >> read;
while (inFile2.peek() != '#' && inFile2.peek() != '>') {
inFile2.unget();
}
inFile2.unget();
inFile2Data[s2 - 1] = '\0';
s2--;
}
inFile2.get();
}
else if (read < readMatch) {
inFile1.unget();
while (read.compare(readMatch) != 0) {
while (inFile1.peek() != '#' && inFile1.peek() != '>') {
inFile1.unget();
inFile1Data[s1 - 1] = '\0';
s1--;
}
inFile1.get();
inFile1 >> readMatch;
while (inFile1.peek() != '#' && inFile1.peek() != '>') {
inFile1.unget();
}
inFile1.unget();
inFile1Data[s1 - 1] = '\0';
s1--;
}
inFile1.get();
}
else {
// Buffer in position -- do nothing
}
}
// If inFile2's buffer was was first to get into position
// Get its header number, get inFile1's last header number.
// Then unstream accordingly until the two buffers end at the
// same data point in their files.
else {
inFile2.get();
inFile2 >> readMatch;
while (inFile2.peek() != '#' && inFile2.peek() != '>') {
inFile2.unget();
}
while (inFile1.peek() != '#' && inFile1.peek() != '>') {
inFile1.unget();
inFile1Data[s1 - 1] = '\0';
s1--;
}
inFile1.get();
inFile1 >> read;
while (inFile1.peek() != '#' && inFile1.peek() != '>') {
inFile1.unget();
}
if (read > readMatch) {
inFile1.unget();
while (read.compare(readMatch) != 0) {
while (inFile1.peek() != '#' && inFile1.peek() != '>') {
inFile1.unget();
inFile1Data[s1 - 1] = '\0';
s1--;
}
inFile1.get();
inFile1 >> read;
while (inFile1.peek() != '#' && inFile1.peek() != '>') {
inFile1.unget();
}
inFile1.unget();
inFile1Data[s1 - 1] = '\0';
s1--;
}
inFile1.get();
}
else if (read < readMatch) {
inFile2.unget();
while (read.compare(readMatch) != 0) {
while (inFile2.peek() != '#' && inFile2.peek() != '>') {
inFile2.unget();
inFile2Data[s2 - 1] = '\0';
s2--;
}
inFile2.get();
inFile2 >> readMatch;
while (inFile2.peek() != '#' && inFile2.peek() != '>') {
inFile2.unget();
}
inFile2.unget();
inFile2Data[s2 - 1] = '\0';
s2--;
}
inFile2.get();
}
else {
// Buffer in position -- do nothing
}
}
}
// With buffers now aligned, parse them and write non-error
// information into the new files
while (nlPos1 != inFile1L && nlPos2 != inFile2L) {
nlPos1Prev = nlPos1;
nlPos2Prev = nlPos2;
nlPos1 = std::find(nlPos1 + 1, inFile1L, '\n');
nlPos2 = std::find(nlPos2 + 1, inFile2L, '\n');
if (strncmp(nlPos1 - 5, "error", 5) == 0 ||
strncmp(nlPos2 - 5, "error", 5) == 0) {
writeEnd1 = nlPos1Prev;
outFile1.write(writeStart1, writeEnd1 - writeStart1);
writeEnd2 = nlPos2Prev;
outFile2.write(writeStart2, writeEnd2 - writeStart2);
for (int i = 0; i < 3; i++) {
nlPos1 = std::find(nlPos1 + 1, inFile1L, '\n');
nlPos2 = std::find(nlPos2 + 1, inFile2L, '\n');
}
writeStart1 = nlPos1;
writeStart2 = nlPos2;
}
}
outFile1.write(writeStart1, inFile1Data + s1 - writeStart1);
outFile2.write(writeStart2, inFile2Data + s2 - writeStart2);
}
inFile1.close();
inFile2.close();
outFile1.close();
outFile2.close();
}
The function, albeit a bit spaghetti-ish, works fine. I call it into concurrency with the below function, which leverages a "threadPool" object, for which the header, implementation files are at the bottom of the question:
// Concurrency function which starts parallel file-pair-processing
// jobs for each **"SRA"** object in its input vector.
void rem_unfix_bulk(std::vector<SRA> sras, int numThreads, int ram_gb) {
long long int ram_b = stoi(ram_gb) * 1000000000;
long long int ram_b_per_thread = ram_b / numThreads;
// Instantiate thread pool with numThreads threads to handle jobs
threadPool fileCorrPool;
fileCorrPool.start(numThreads);
// Add queue jobs to thread pool
for (auto sra : sras) {
if (fs::exists(sra.get_sra_path_corr_fix().first.c_str())) {
continue;
}
fileCorrPool.queueJob([sra, ram_b_per_thread {rem_unfix_pe(sra, ram_b_per_thread);});
}
fileCorrPool.stop();
}
threadPool object header file (thread_pool.h):
#include <thread>
#include <mutex>
#include <functional>
#include <vector>
#include <queue>
#include <condition_variable>
class threadPool {
public:
void start(int threadNum);
void queueJob(const std::function<void()>& job);
void stop();
bool busy();
private:
void threadLoop();
bool endProc = false;
std::mutex queue_mutex;
std::condition_variable mutex_condition;
std::vector<std::thread> threads;
std::queue<std::function<void()>> jobs;
};
threadPool object implementation file (thread_pool.cpp):
#include "thread_pool.h"
void threadPool::start(int threadNum) {
threads.resize(threadNum);
for (int i = 0; i < threadNum; i++) {
threads.at(i) = std::thread(&threadPool::threadLoop, this);
}
}
void threadPool::threadLoop() {
while (true) {
std::function<void()> job;
{
std::unique_lock<std::mutex> lock(queue_mutex);
mutex_condition.wait(lock, [this] {
return (!jobs.empty() || endProc);
});
if (jobs.empty() && endProc) {
return;
}
job = jobs.front();
jobs.pop();
}
job();
}
}
void threadPool::queueJob(const std::function<void()>& job) {
{
std::unique_lock<std::mutex> lock(queue_mutex);
jobs.push(job);
}
mutex_condition.notify_one();
}
bool threadPool::busy() {
bool poolBusy;
{
std::unique_lock<std::mutex> lock(queue_mutex);
poolBusy = jobs.empty();
}
return poolBusy;
}
void threadPool::stop() {
{
std::unique_lock<std::mutex> lock(queue_mutex);
endProc = true;
}
mutex_condition.notify_all();
for (std::thread& t : threads) {
t.join();
}
threads.clear();
}
Good morning Stack Overflow,
I am having trouble getting some key-value pairs to store in a vector only if they meet certain criteria which I will explain below. Everything is working in my program so far except this.
To begin here is my main:
int main()
{
Records passports;
std::string filename = "test.txt";
std::ifstream inFile(filename);
std::string liNe;
while (!inFile.eof()) {
getline(inFile, liNe);
if (liNe.length() == 0) passports.keyHolder2.push_back(" ");
std::istringstream ss(liNe);
while (ss >> liNe) {
passports.keyHolder2.push_back(liNe);
}
}
inFile.close();
cout << isinRangeTest(passports) << endl;
}
Here is my structure to store all my vectors:
struct Records {
std::vector<string> keyHolder;
std::vector<string> validKeys;
std::vector<string> keyHolder2;
std::vector<string> validKeys2;
};
Here is my function to determine if they have the prefixes like "ecl, byr or iyr" and others:
int validPasstest(Records passports)
{
//cout << passports.keyHolder2.size() << endl;
std::vector<string>::iterator count;
string x, z;
int more = 0;
bool plus = false;
for (count = passports.keyHolder2.begin(); count != passports.keyHolder2.end(); count++) {
//cout << *count << endl;
}
for (int i = 0; i < passports.keyHolder2.size(); i++) {
z = passports.keyHolder2.at(i);
std::size_t found = z.find("byr");
if (found != std::string::npos) more++;
found = z.find("iyr");
if (found != std::string::npos) more++;
found = z.find("hgt");
if (found != std::string::npos) more++;
found = z.find("hcl");
if (found != std::string::npos) more++;
found = z.find("ecl");
if (found != std::string::npos) passports.validKeys2.push_back(z);
found = z.find("pid");
if (found != std::string::npos) more++;
found = z.find("cid");
if (found != std::string::npos) more++;
found = z.find(" ");
if (found != std::string::npos)
{
/*if (more == 7) {
plus++;
}*/
more = 0;
}
}
return plus;
}
Here is my function to display the vector that only has valid key-value pairs:
int isinRangeTest(Records passports)
{
for (int i = 0; i < passports.validKeys2.size(); i++)
{
cout << passports.validKeys2.at(i);
}
return 0;
}
When I try to output validKeys 2 I get a "0" on the output window and nothing else. Here is my textfile and output:
ecl:gry pid:860033327 hcl:#fffffd
byr:1937 iyr:2017 cid:147 hgt:183cm
iyr:2013 ecl:amb cid:350 pid:028048884
hcl:#cfa07d byr:1929
hcl:#ae17e1 iyr:2013 cid:150
eyr:2024
ecl:brn pid:760753108 byr:1931
hgt:179cm
hcl:#cfa07d eyr:2025 pid:166559648
iyr:2011 ecl:brn hgt:59in cid:230
output
In my function validPasstest, I am trying to add 'z' to the vector validKeys2. It is not working. Any suggestions?
In my game I keep track of unlocked levels with a vector std::vector<bool> lvlUnlocked_;.
The simple function to save the progress is this:
void save() {
std::stringstream ss;
std::string stringToSave = "";
std::ofstream ofile("./progress.txt");
if (ofile.good()) {
ofile.clear();
for (std::size_t i = 0; i < levelUnlocked_.size(); ++i) {
ss << "lvl" << i << "=" << (lvlUnlocked_.at(i) ? "1" : "0") << std::endl;
}
stringToSave = ss.str();
ofile << stringToSave;
ofile.close();
}
}
This works and is nice since I can just use a loop to dump the info.
Now to the part where I am stuck, the lower part of my load function (see comment in code below):
void load() {
std::ifstream ifile("./progress.txt");
if (ifile.good()) {
int begin;
int end;
std::string line;
std::string stringKey = "";
std::string stringValue = "";
unsigned int result;
while (std::getline(ifile, line)) {
stringKey = "";
stringValue = "";
for (unsigned int i = 0; i < line.length(); i++) {
if (line.at(i) == '=') {
begin = i + 1;
end = line.length();
break;
}
}
for (int i = 0; i < begin - 1; i++) {
stringKey += line.at(i);
}
for (int i = begin; i < end; i++) {
stringValue += line.at(i);
}
result = static_cast<unsigned int>(std::stoi(stringValue));
// usually I now compare the value and act accordingly, like so:
if (std::strcmp(stringKey.c_str(), "lvl0") == 0) {
lvlUnlocked_.at(0) = true;
} else if (std::strcmp(stringKey.c_str(), "lvl1") == 0) {
lvlUnlocked_.at(1) = true;
} else if (std::strcmp(stringKey.c_str(), "lvl2") == 0) {
lvlUnlocked_.at(2) = true;
}
// etc....
}
}
}
This works fine, but...
the problem is that I have 100+ levels and I want it to be dynamic based on the size of my lvlUnlocked_ vector instead of having to type it all like in the code above.
Is there a way to somehow make use of a loop like in my save function to check all levels?
If you parse your key to extract a suitable integer value, you can just index into the bit-vector with that:
while (std::getline(ifile, line)) {
const size_t eq = line.find('=');
if (eq == std::string::npos)
// no equals sign
continue;
auto stringKey = line.substr(0, eq);
auto stringValue = line.substr(eq+1);
if (stringKey.substr(0,3) != "lvl")
// doesn't begin with lvl
continue;
// strip off "lvl"
stringKey = stringKey.substr(3);
size_t end;
std::vector<bool>::size_type index = std::stoi(stringKey, &end);
if (end == 0 || end != stringKey.length())
// not a valid level number
continue;
if (index >= lvlUnlocked_.size())
// out of range
continue;
// Set it :-)
lvlUnlocked_[index] = stringValue=="1";
}
(I've also updated your parsing for "key=value" strings to more idiomatic C++.)
I have one array like this:
static WCHAR FilesToShow[][100] = { { L"start.cmd" },{ L"image.xml" }, { L"xyz" }};
as you see that there is "xyz" which I have to replace with some unique name. For this I have to read image.xml file.
Please can you tell me how can I do this.
I wrote a method like this:
PRIVATE WCHAR GetSystemName(WCHAR *pName)
{
WCHAR line;
wfstream in("image.xml");
WCHAR tmp;
bool begin_tag = false;
while (getline(in,line))
{
// strip whitespaces from the beginning
for (int i = 0; i < line.length(); i++)
{
if (line[i] == ' ' && tmp.size() == 0)
{
}
else
{
tmp += line[i];
}
}
if (wcswcs(tmp,"<SystemPath>") != NULL)
{
???????? how to get "vikash" from here <SystemPath>C:\Users\rs_user\Documents\RobotStudio\Systems\vikash</SystemPath>
}
else
{
continue;
}
}
return tmp;
}
I'm getting exception for wfstream, getline and line.length() method.
I have included fstream.h header file but I think It's not supported in COM.
Please help me how to solve this issue without parsing xml file.
If your xml-file is simple enough so that there is only a single tag with given name, you could do it like this:
#include <string>
#include <sstream>
#include <iostream>
std::wstring get_value(std::wistream & in, std::wstring const & tagname)
{
std::wstring text = std::wstring(std::istreambuf_iterator<std::wstring::value_type>(in),
std::istreambuf_iterator<std::wstring::value_type>());
std::wstring start_tag = L"<" + tagname + L">";
std::wstring end_tag = L"</" + tagname + L">";
std::wstring::size_type start = text.find(start_tag);
if (start == std::wstring::npos)
{
throw 123;
}
start += start_tag.length();
std::wstring::size_type end = text.find(end_tag);
if (end == std::wstring::npos)
{
throw 123;
}
return text.substr(start, end - start);
}
std::wstring get_substr_after(std::wstring const & str, wchar_t delim)
{
std::wstring::size_type pos = str.rfind(delim);
if (pos == std::wstring::npos)
{
throw 123;
}
return str.substr(pos + 1);
}
void stackoverflow()
{
std::wstring text(L"<foo>\n<bar>abc/def/ghi</bar>\n<baz>123/456/789</baz>\n</foo>\n");
std::wistringstream wiss(text);
std::wcout << text << std::endl;
std::wcout << get_substr_after(get_value(wiss, std::wstring(L"bar")), L'/') << std::endl;
}
The output of this program is:
<foo>
<bar>abc/def/ghi</bar>
<baz>123/456/789</baz>
</foo>
ghi
I hope that answered your question.
you have several issues here.
what you are getting are compiler errors and not exceptions
the header file to include is 'fstream' not 'fstream.h'.
make sure you have a line saying using namespace std;
You are declaring line as a variable of type WCHAR, so it is a single wide character, which surely is not a wstring object. Therefore line.length() is incorrect.
Why are you mixing C (wcswcs()) and C++ (STL) ? maybe you should re-design your function signature.
However, try the below function. I have modified the signature to return a pointer to WCHAR, and place the requested string in the buffer space provided by pName. I added a check to verify that the buffer is large enough to fit the name and the terminating NULL character.
WCHAR* GetSystemName(WCHAR *pName, size_t buflen)
{
wstring line;
wifstream in("image.xml");
WCHAR* tmp = NULL;
while (getline(in,line))
{
// strip whitespaces from the beginning
size_t beg_non_whitespace = line.find_first_not_of(L" \t");
if (beg_non_whitespace != wstring::npos)
{
line = line.substr( beg_non_whitespace );
}
size_t beg_system_path = line.find( L"<SystemPath>" );
if ( beg_system_path != wstring::npos )
{
// strip the tags (assuming closing tag is present)
size_t beg_data = beg_system_path + wstring( L"<SystemPath>" ).length();
size_t range = line.find( L"</SystemPath>" ) - beg_data;
line = line.substr( beg_data, range );
// get file name
size_t pos_last_backslash = line.find_last_of( L'\\' );
if ( pos_last_backslash != wstring::npos )
{
line = line.substr( pos_last_backslash + 1 );
if ( buflen <= line.length() )
{
// ERROR: pName buffer is not large enough to fit the string + terminating NULL character.
return NULL;
}
wcscpy( pName, line.c_str() );
tmp = pName;
break;
}
}
}
return tmp;
}
EDIT: Moreover, if you are using and/or parsing XML in other areas of your program, I strongly suggest using an XML parsing library such as Xerces-C or libXml2.
Thank you all for your answer. Here I got solution of my question.
PRIVATE WCHAR* GetNewSystemName()
{
WCHAR line[756];
WCHAR tempBuffer[100];
CComBSTR path = CurrentFolder.Path();
CComBSTR imagePath1 = L"rimageinfo.xml";
path.AppendBSTR(imagePath1);
std::wfstream in(path);
WCHAR tmp[756];
in.getline(line, 756);
WCHAR* buffer;
buffer = wcswcs(line, L"<SystemPath>");
WCHAR *dest = wcsstr(buffer, L"</SystemPath>");
int pos;
pos = dest - buffer;
unsigned int i = 0;
if (wcswcs(buffer,L"<SystemPath>") != NULL && wcswcs(buffer,L"</SystemPath>") != NULL)
{
for (; i < pos; i++)
{
if (buffer[i] == ' ' && sizeof(tmp) == 0)
{
}
else
{
tmp[i] = buffer[i];
}
}
tmp[i] = NULL;
//break;
}
int j = i;
for (; j > 0; j--)
{
if (tmp[j] == '\\')
{
break;
}
}
j++;
int k = 0;
for (; j < i ; j++)
{
System_Name[k] = tmp[j];
k++;
}
System_Name[k] = NULL;
return System_Name;
I am new to C++, i want to read ini file which has section and key - value pair.
Depending on the section, i want to read the value for corresponding key.
Primarily, i want to read the section which is enclosed in square brackets.
Please help.
Thank you.
For real INI file parsing, I highly suggest the iniparser library. It is excellently documented and easy to use in both C and C++ programs.
If you are only interested in parsing strings of the form [Section name], you could do the following: Find first '[' and last ']' for the string and mark the positions. If both characters have been found, take the section name to be substring between the positions you identified.
Assuming you are using an std::string, you can do the following:
std::string myString = " [Section name] ";
std::size_t start = myString.find_first_of( '[' );
std::size_t end = myString.find_last_of( ']' );
std::string sectionName;
if( start != std::string::npos && end != std::string::npos )
{
sectionName = myString.substr(start + 1, end - 1);
}
std::cout << sectionName << std::endl;
This snippet should show you the basic logic for parsing an ini file and skipping # or ; prefixed lines which are treated as comments
this needs sanity checks for group names, names and values, but should suffice as a demonstration:
#include <iostream>
#include <string>
#include <map>
//
// a simple ini file parser (doesn't check for validity of name field length wise or if it has = char
// to demonstrate basic parsing
//
class IniFile
{
public:
enum { MAX_LINE_LEN = 10*1024 };
class MalformedInputException : public std::exception
{
public:
const char* what() const throw() { return "Input is not a valid or well formed ini file"; }
};
typedef std::map<std::string, std::string> Properties;
IniFile(){}
virtual ~IniFile(){}
std::istream& load(std::istream& in)
{
char lineBuffer[MAX_LINE_LEN];
std::string curGroup = "";
while(!in.eof())
{
in.getline(lineBuffer, MAX_LINE_LEN);
//std::cout<<"line buffer : {"<<lineBuffer<<"}"<<std::endl;
std::string line = trim(lineBuffer);
//std::cout<<"trimmed : {"<<line<<"}"<<std::endl;
// we process only non-empty / non-comment lines
if(line.size() > 0 && line[0] != '#' && line[0] != ';')
{
if(line[0] == '[' && line[line.size() - 1] == ']')
{
curGroup = trim(line.substr(1, line.size() - 2));
}
else if(curGroup.size() > 0)
{
size_t index = line.find_first_of('=');
//todo: needs checks for valid name=value format here
Properties& props = m_props[curGroup]; // this will create new Properties if none exists
props[line.substr(0,index)] = line.substr(index+1);
}
else
{
throw MalformedInputException();
}
}
}
return in;
}
std::ostream& save(std::ostream& os) const
{
std::map<std::string, Properties>::const_iterator iter = m_props.begin();
while(iter != m_props.end())
{
os<<"["<<iter->first<<"]"<<std::endl;
Properties::const_iterator propIter = iter->second.begin();
while(propIter != iter->second.end())
{
os<<propIter->first<<"="<<propIter->second<<std::endl;
propIter++;
}
iter++;
}
return os;
}
std::string trim(const std::string& input)
{
static std::string WHITESPACES = "\r\n \t\b\a";
if(input.size() == 0){ return input; }
else
{
size_t start = 0;
for(size_t index = 0; index < input.size(); index++)
{
if(WHITESPACES.find(input[index]) < WHITESPACES.size())
{
start = index;
}
else
{
break;
}
}
size_t endIndex = input.size() - 1;
if(start == endIndex){ return ""; }
for(; endIndex > start; endIndex--)
{
char c = input.at(endIndex);
if(WHITESPACES.find_first_of(c) >= WHITESPACES.size())
{
break;
}
}
size_t length = endIndex - start + 1;
return input.substr(start, length);
}
}
private:
std::map<std::string, Properties> m_props;
};
inline std::ostream& operator << (std::ostream& os, const IniFile& iniFile)
{
return iniFile.save(os);
}
inline std::istream& operator >> (std::istream& in, IniFile& iniFile)
{
return iniFile.load(in);
}
#include <sstream>
int main(int argc, char** argv)
{
std::ostringstream ss;
ss<<"# sample ini file"<<std::endl;
ss<<"[Group1]"<<std::endl;
ss<<"foo=bar \n"<<std::endl;
ss<<"baz=foz"<<std::endl;
ss<<"; this is another comment"<<std::endl;
ss<<"[Group2]"<<std::endl;
ss<<"blanga=kukoo"<<std::endl;
std::string buf = ss.str();
std::istringstream sin(buf);
IniFile iniFile;
iniFile.load(sin);
iniFile.save(std::cout<<"Ini File Loaded : "<<std::endl);
return 0;
}