Filestreams reading and writing to text file, then convert to binary in c++ - file-io

What I am trying to do is fairly elementary however I am having trouble with my project. My project is too large to include everything, so I will just include the two functions that I am writing along with what the txt file looks like. This is in c++.
bookmark.cfg
No Title
0 0 0 0 0 0
No Title
1 1 1 1 1 1
No Title
2 2 2 2 2 2
No Title
3 3 3 3 3 3
No Title
4 4 4 4 4 4
No Title
5 5 5 5 5 5
These are my two functions for writing and reading to the text file and my class's private structure
struct BookMark {
std::string strFilename;
unsigned id;
unsigned bookID;
unsigned chapterNumber;
unsigned pageNumber;
unsigned lineNumber;
unsigned columnNumber;
}; // BookMark
// ----------------------------------------------------------------------------
// readConfigFile()
bool BookManager::readConfigFile() {
using namespace std;
// Just To Be Safe Incase This Function Is Called In Multiple Places
_mBookMarks.clear();
ifstream inFile( _strConfigFilename );
if ( inFile.fail() ) {
throw ExceptionHandler( __FUNCTION__ + std::string( " failed, could not open " ) + _strConfigFilename + std::string( " \nfor reading in book mark information \nInvalid file or file does not exist" ) );
}
// Read In The Book Mark Contents
std::vector<BookMark> vBookMarks;
BookMark bookMark;
string tempString = "";
if ( inFile.is_open() ) {
while ( !inFile.eof() ) {
BookMark bookMark;
getline( inFile, bookMark.strFilename );
inFile >> bookMark.id;
inFile >> bookMark.bookID;
inFile >> bookMark.chapterNumber;
inFile >> bookMark.pageNumber;
inFile >> bookMark.lineNumber;
inFile >> bookMark.columnNumber;
getline( iniFile, tempString );
//_mBookMarks.insert( make_pair( bookMark.id, bookMark ) );
vBookMarks.push_back( bookMark );
}
}
inFile.close();
return true;
} // readConfigFile
// ----------------------------------------------------------------------------
// writeConfigFile()
bool BookManager::writeConfigFile() {
using namespace std;
ofstream outFile;
outFile.open( _strConfigFilename, fstream::out );
if ( outFile.fail() ) {
throw ExceptionHandler( __FUNCTION__ + std::string( " failed, could not open " ) + _strConfigFilename + std::string( " \nfor writing book mark contents to file." ) );
}
// Write Out Book Mark Contents
if ( outFile.is_open() ) {
unsigned i = 0;
for ( i = 0; i < _mBookMarks.size(); i++ ) {
outFile << _mBookMarks.at( i ).strFilename << endl;
outFile << _mBookMarks.at( i ).id << " ";
outFile << _mBookMarks.at( i ).bookID << " ";
outFile << _mBookMarks.at( i ).chapterNumber << " ";
outFile << _mBookMarks.at( i ).pageNumber << " ";
outFile << _mBookMarks.at( i ).lineNumber << " ";
outFile << _mBookMarks.at( i ).columnNumber << endl << endl;
}
}
outFile.close();
return true;
} // writeConfigFile
The problem I am having is, when I call the write function all the text is being displayed properly in my text file. The first line should be a string that contains the book's title or filename. The second line should be all unsigned ints to specify parameters to know the position of the bookmark's location. As of now I just populated my classes structure with arbitrary data using a for loop and incrementing each bookmarks parameters just to test these functions. Somewhere else in my code I call my write method first to create this text file and write the contents. This seems to be working fine. Then I call my read method to read in the file and populate a temporary vector of my structure to see if the contents being read from the file are valid. Once I get this to work properly I'll then just populate my class's member variable structure instead.
Here I am reading in the first line using getline function then I am using the stream operators to get the rest of the contents. While I am debugging my code going through the read method and checking my temp vector the first element has the correct value with No Title and each of the parameters are 0. When I check the next element there is no string in the next BookMark structure object and all values are 0. Also there should only be 5 elements in my temp vector and it should break out of the loop, but it continues and never breaks out of the loop. Why is the code behaving like this? What is it that I am doing wrong? How can I change this to get the behavior I am looking for?
If you need to see this class in full let me know, but I think the rest of the class is not important as to what I am trying to do, only these two functions should be enough to describe my situation. Once I get this to work properly then I'll just change the read and write methods to work in binary as opposed to text.

I believe I have solved my own problem. In my read method, I had to add a second getline( this fileStream, tempString ); And now my code appears to be working properly. My vector has the correct values and it only has 5 elements and now breaks out of the loop.

Related

why can't equate pointer to nullptr

In the follwing program I was searching of lowest comman ancesstor in a BST.
The main problem here is that !root doesn't works like root!=nullptr.
Here line 1 works perfect. But line 2 gives wrong answer.
Please tell why line 2 desn't works but line 1 does.
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
int small=min(p->val, q->val);
int big=max(p->val, q->val);
while(root!=nullptr){ // line 1
// while(!root){ // line 2
int x=(root->val);
if(x>big){
root=root->left;
}
else if(x<small){
root=root->right;
}
else{
return root;
}
}
return nullptr;
}
};
Short of defining nullptr to be something weird (like 7), there should be no difference between x != nullptr and ! x, for any given pointer x.
It may be worthwhile printing out nullptr and root just inside the loop as well as the comparison results (and pointers, just in case your tree is corrupt), to see if something weird is happening, something like:
while (!root) {
std::cout
<< static_cast<void*>(root) << ' '
<< static_cast<void*>(root->left) << ' '
<< static_cast<void*>(root->right) << ' '
<< static_cast<void*>(nullptr) << ' '
<< (! root) << ' '
<< (root != nullptr) << std::endl;
int x=(root->val);
// ... and so on
The output of that may go a great deal toward showing what's wrong with your situation(a).
(a) One of my favourite mantras is "when in doubt, print it out", right up there with:
Get it working first, then get it working fast.
You can't get any less optimised than "wrong".
:-)

GDAL VSIS3 and GetRasterBand

I'm trying to access some Landsat data from S3 without making local copies of the files. As a test I wanted to run a simple GetRasterBand on the file but I'm not sure how to go about treating a VSILFILE as a GDALDataset without downloading the file.
GDAL API guide states VSILFILE "cannot be used with any functions other than the "VSI*L" family of functions. They aren't "real" FILE objects."
Snip of my code :
VSILFILE *poVs3Dataset;
//GDALDataset *poDataset;
GDALRasterBand *poBand;
char * path = (char *)"/vsis3/landsat-pds/c1/L8/139/045/LC08_L1TP_139045_20170304_20170316_01_T1/LC08_L1TP_139045_20170304_20170316_01_T1_B1.TIF";
GDALAllRegister();
VSIInstallS3FileHandler();
CPLSetConfigOption( "AWS_ACCESS_KEY_ID", "XXX" );
CPLSetConfigOption( "AWS_SECRET_ACCESS_KEY", "XXX" );
poVs3Dataset = VSIFOpenL(path, "r");
poBand = poVs3Dataset->GetRasterBand( 1 );
Which ultimately and understandably fails
g++ -g -L/usr/local/lib -lgdal stats.cpp
error: ‘VSILFILE’ has no member named ‘GetRasterBand’
Are there any good C++ examples out there I could work through?
Thanks!
Setting my environment variables prior to calling the executable seemed to help:
$> env AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=xxx ./a.out /vsis3/landsat-pds/c1/L8/139/045/LC08_L1TP_139045_20170304_20170316_01_T1/LC08_L1TP_139045_20170304_20170316_01_T1_B1.TIF
This is now my test code to prove to myself I can access with both GDALOpenEx & VSIFOpenExL which works in case it helps someone else:
VSILFILE *fpL;
GDALDataset *poDataset;
GDALRasterBand *poBand;
char * path = (char *)"/vsis3/landsat-pds/c1/L8/139/045/LC08_L1TP_139045_20170304_20170316_01_T1/LC08_L1TP_139045_20170304_20170316_01_T1_B1.TIF";
VSIStatBufL sStat;
const char* const apszAllowedDrivers[] = { "GTiff", NULL };
GDALAllRegister();
poDataset = reinterpret_cast<GDALDataset*>(GDALOpenEx(path, GDAL_OF_READONLY | GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR, NULL, NULL, NULL));
if( poDataset == NULL )
{
std::cout << "Couldn't open " << std::endl;
}
poBand = poDataset->GetRasterBand( 1 );
int nXSize = poBand->GetXSize();
int nYSize = poBand->GetYSize();
std::cout << "nXSize : " << nXSize << std::endl;
std::cout << "nYSize : " << nYSize << std::endl;
fpL = VSIFOpenExL(path, "rb", 1);
if( fpL != NULL )
{
....
works!!!

Boost.X3: does not compile with std::optional<std::string>

The following parser does not compile when I use std::optional<std::string> for values of a -lexeme[+alpha] rule: something breaks in the attribute management.
The grammar works fine if instead of std::string I use int as a base type, it also works if I use twice std::string (i.e., no std::optional). However it does not work with boost::optional either. In the real grammar there is a difference between the absence of the string, and an empty string: I want to use std::optional (or its Boost predecessor).
The full example is available on Coliru, but here are the relevant bits:
struct pair_t
{
std::string first;
std::optional<std::string> second;
};
BOOST_FUSION_ADAPT_STRUCT(pair_t, first, second)
const auto pair_rule = lexeme[+alpha] >> -lexeme[+alpha] >> eoi;
for (std::string i: {"ab", "ab cd"})
{
auto res = pair_t{};
auto first = i.cbegin();
auto last = i.cend();
auto r = x3::phrase_parse(first, last, pair_rule, space, res);
if (r && first == last)
std::cout << i << ": " << res << '\n';
else
std::cout << i << ": failed\n";
}
My compiler reports:
clang++-mp-5.0 -std=c++17 -isystem /opt/local/include/ x3-optional.cc && ./a.out
In file included from x3-optional.cc:8:
In file included from /opt/local/include/boost/spirit/home/x3.hpp:14:
In file included from /opt/local/include/boost/spirit/home/x3/auxiliary.hpp:11:
In file included from /opt/local/include/boost/spirit/home/x3/auxiliary/any_parser.hpp:17:
/opt/local/include/boost/spirit/home/x3/support/traits/move_to.hpp:180:9: error: no matching function
for call to 'move_to'
detail::move_to(std::move(src), dest
^~~~~~~~~~~~~~~
/opt/local/include/boost/spirit/home/x3/char/char_parser.hpp:31:29: note: in instantiation of
function template specialization 'boost::spirit::x3::traits::move_to<const char &,
std::__1::basic_string<char> >' requested here
x3::traits::move_to(*first, attr);
^

Making cin take selective inputs [Turbo C++]

Don't hate cause of Turbo, I already hate my school!
I wish to show an error msg if a character is entered instead of an int or float in some file such as age or percentage.
I wrote this function:
template <class Type>
Type modcin(Type var) {
take_input: //Label
int count = 0;
cin>>var;
if(!cin){
cin.clear();
cin.ignore();
for ( ; count < 1; count++) { //Printed only once
cout<<"\n Invalid input! Try again: ";
}
goto take_input;
}
return var;
}
but the output is not desirable:
How do I stop the error msg from being repeated multiple times?
Is there a better method?
NOTE: Please make sure that this is TurboC++ that we are talking about, I tried using the approach in this question, but even after including limits.h, it doesn't work.
Here, a code snippet in C++.
template <class Type>
Type modcin(Type var) {
int i=0;
do{
cin>>var;
int count = 0;
if(!cin) {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
for ( ; count < 1; count++) { //Printed only once
cout<<"\n Invalid input! Try again: ";
cin>>var;
}
}
} while (!cin);
return var;
}
The variables are tailored to match yours' so you can understand better. This code isn't perfect though.
It can't handle cases like "1fff", here you would just get a 1 in return. I tried solving it but then a infinite loop was being encountered, when I'll fix it, I'll update the code.
It also can't function in TurboC++ effectively. I don't know if there are alternatives but the numeric_limits<streamsize>::max() argument gives a compiler error ('undefined symbol' error for numeric_limits & streamsize and 'prototype must be defined' error for max()) in Turbo C++.
So, to make it work in Turbo C++. Replace the numeric_limits<streamsize>::max() argument with some big int value such as 100.
This will make it so that the buffer is only ignored/cleared till 100 characters are reached or '\n' (enter button/newline character) is pressed.
EDIT
The following code can be executed on both Turbo C++ or proper C++. The comments are provided to explain the functioning:
template <class Type> //Data Integrity Maintenance Function
Type modcin(Type var) { //for data types: int, float, double
cin >> var;
if (cin) { //Extracted an int, but it is unknown if more input exists
//---- The following code covers cases: 12sfds** -----//
char c;
if (cin.get(c)) { // Or: cin >> c, depending on how you want to handle whitespace.
cin.putback(c); //More input exists.
if (c != '\n') { // Doesn't work if you use cin >> c above.
cout << "\nType Error!\t Try Again: ";
cin.clear(); //Clears the error state of cin stream
cin.ignore(100, '\n'); //NOTE: Buffer Flushed <|>
var = modcin(var); //Recursive Repeatation
}
}
}
else { //In case, some unexpected operation occurs [Covers cases: abc**]
cout << "\nType Error!\t Try Again: ";
cin.clear(); //Clears the error state of cin stream
cin.ignore(100, '\n'); //NOTE: Buffer Flushed <|>
var = modcin(var);
}
return var;
//NOTE: The '**' represent any values from ASCII. Decimal, characters, numbers, etc.
}

writing output to a file in Graphchi

I wrote a shortest path code in Graphchi and I wanted to print the output of that in a file. I was trying to use the template shown in the examples but I get error if I use the sameway of writing to a file as in other examples.
I have got stuck here. As the output I just want to print (vertex id,its minimum distance from source).
How can i do that.
Here is example how you can output values of all vertices to the console. It is easy to modify it to write the output to a file. Note that if you can handle binary files, GraphChi already has the vertex values in a file: .B.vout, where is sizeof(VertexDataType).
1) You need to define a callback-function, which will take vertex id and value as parameter
class OutputVertexCallback : public VCallback<VertexDataType> {
public:
virtual void callback(vid_t vertex_id, VertexDataType &value) {
std::cout << vertex_id << "=" << value << std::endl;
}
};
2) Then you need to call foreach_vertices() as follows to get the output:
OutputVertexCallback callback;
foreach_vertices<VertexDataType>(filename, 0, engine.num_vertices(), callback);