I would like to get some advice on an issue I've encountered once working on small adjustments to an existing program.
The program itself has to:
- Open a file and read it line-by-line preferably
- Pack the lines into
istringstream
and then split to 2 strings on a':'
separator - Insert those 2 strings
line1
andline2
into an existingstd::map
container - Than I can do more stuff with the
map
and the data from it.
My code looks like that:
int main()
{
FILE *fpFile;
map<string, string>mapOfPci;
std::string tempBuff="";
std::string line1="", line2="";
fpFile = fopen(PCI_MAPPING_PATH, "r");
if(!fpFile)
return false;
while(getline(fpFile, tempBuff)){
istringstream iSs(tempBuff);
iSs >> line1;
iSs.ignore(numeric_limits<std::streamsize>::max(), ':');
iSs >> line2;
mapOfPci.insert(make_pair(line1, line2));
}
for(const auto &m : mapOfPci){
cout << m.first << " : " << m.second << "\n";
}
fclose(fpFile);
return (0);
}
Now what I'm getting in my compiler feedback is:
mismatched types 'std::basic_istream<_CharT, _Traits>' and 'FILE* {aka _iobuf*}'
while(getline(fpFile, tempBuff))
At this point I presume that this is due to the usage of FILE*
file handling method.
I might not be able to use the C std::ifstream
, std::fstream
, so is there any method to move this further with the current FILE*
usage?
CodePudding user response:
std::getline()
expects an std::istream
-derived class, like std::ifstream
, so you simply can't pass your own FILE*
to it (unless you wrap it inside of a custom std::streambuf
-derived object assigned to a standard std::istream
object. std::ifstream
uses std::filebuf
, which uses FILE*
internally, but you can't supply it with your own FILE*
).
Otherwise, you can use C's getline()
function instead, but it doesn't work with std::string
, as it allocates its own output char[]
buffer which you will then have to free afterwards (you can assign the contents of that buffer to a std::string
, though), eg:
#include <iostream>
#include <sstream>
#include <string>
#include <utility>
#include <limits>
#include <cstdio>
using namespace std;
int main()
{
FILE *fpFile = fopen(PCI_MAPPING_PATH, "r");
if (!fpFile)
return false;
map<string, string> mapOfPci;
char *tempBuff = nullptr;
size_t size = 0;
int nRead;
while ((nRead = getline(&tempBuff, &size, fpFile)) != -1){
istringstream iSs(string(tempBuff, nRead));
string line1, line2;
iSs >> line1;
iSs.ignore(numeric_limits<streamsize>::max(), ':');
iSs >> line2;
mapOfPci.insert(make_pair(line1, line2));
free(tempBuff); tempBuff = nullptr;
size = 0;
}
free(tempBuff);
for(const auto &m : mapOfPci){
cout << m.first << " : " << m.second << "\n";
}
fclose(fpFile);
return 0;
}
But, since you are using other C standard classes, there really is no good reason not to use std::ifstream
instead, eg:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <utility>
#include <limits>
using namespace std;
int main()
{
ifstream fpFile(PCI_MAPPING_PATH);
if (!fpFile.is_open())
return false;
map<string, string> mapOfPci;
string tempBuff;
while (getline(fpFile, tempBuff)){
istringstream iSs(tempBuff);
string line1, line2;
iSs >> line1;
iSs.ignore(numeric_limits<streamsize>::max(), ':');
iSs >> line2;
mapOfPci.insert(make_pair(line1, line2));
}
for(const auto &m : mapOfPci){
cout << m.first << " : " << m.second << "\n";
}
return 0;
}