I have an assignment of saving some objects data in a specific order of its data members, I'll try to simplfy . Consider this Base class constructor from a binary file. (Please note that it was not my choice to use char *) .
Base(ifstream & in_file) {
int n;
in_file.read((char *)&n, sizeof(n));
m_var = new char[n + 1];
in_file.read(m_var, n);
m_var[n] = '\0';
in_file.read((char *)&m_intvar, sizeof(m_intvar));
}
It has to initialize m_var (char *) and another integer variable. This code works, though it requiers to save the length of the char * for me to allocate the memory.
The problem starts here. I was instructed not to save the size of the string, but to only enter a \n after each value i write to the file. So I need some how to read the file, and get the string until the \n character.
I was thinking about reading char by char, but couldn't find a way to do it, I assume there is an istream function that offers that. Some similar function to >> of a text file would also be good I assume.
After consulting cppreference.com I end up as follows:
#include <fstream>
#include <iostream>
#include <cstring>
class Base
{
public:
Base(std::istream & in_file) { // NOTE: changed to istream to allow reading from any stream not just files
in_file.read((char *)&n, sizeof(n));
char buffer[1024];
in_file.get(buffer, sizeof(buffer), '\n');
size_t gcount = in_file.gcount();
if (in_file.get() != '\n')
{
throw std::runtime_error("binary string to long"); // you may want to implement a loop here using peek() to check for newline
}
m_var = new char[gcount];
std::copy(buffer, buffer + gcount, m_var);
}
Base(int num, const char* strg)
: n(num)
, m_var(strdup(strg))
{
}
bool operator == (const Base& rhs)
{
return n == rhs.n && strcpy(m_var, rhs.m_var);
}
void write(std::ostream& out)
{
out.write((char*)&n, sizeof(n));
out.write(m_var, strlen(m_var));
out.write("\n", 1);
}
int n;
char* m_var = nullptr;
~Base()
{
delete m_var;
}
};
int main(int, char**)
{
Base b1(10, "Hello Word!");
{
std::ofstream out("testfile.bin");
b1.write(out);
}
std::ifstream in("testfile.bin");
Base b2(in);
if (b1 == b2)
{
std::cout << "read ok!" << std::endl;
}
else
{
std::cout << "read failed!" << std::endl;
}
return 0;
}
4 years later but I was having a similar problem and found this post.
You can read char by char as you mention, with a loop.
int i;
for(i=0;;i++){
cout<<i;
in_file.read(&buffer[i],sizeof(char));
if buffer[i]=='\n') break;
}
The only problem with the code I came up is it saves the '\n'. But you can and should replace it to the NULL char '\0' after having found the new line '\n'.
(buffer[i]=='\0')
Please correct me if I am mistaken.
Related
I do not understand why my array of pointers is only saving the last line from the file that I am reading from. When I substitute a string literal into the setData() function the code works just fine. All that the "mann" file contains are a bunch of words order alphabetically. Thank you.
#include <iostream>
#include <fstream>
using namespace std;
class orignialData {
char* data;
public:
void setData(char* s) { data = s;}
char* getData() const {return data;}
};
class dataClass {
orignialData** W_;
public:
dataClass(char* filename);
void addData();
void viewAll();
};
dataClass::dataClass(char* filename) {
fstream file;
file.open(filename, ios::in);
if (file.fail()) {
cout << "There was an error reading the file...\n";
}
W_ = 0;
W_ = new orignialData*[5];
for (int i = 0; i < 5; i++)
W_[i] = new orignialData;
char buff[30];
char* temp;
while(file >> buff) {
cout << buff << endl;
static int i = 0;
W_[i] -> setData(buff);
i++;
}
file.close();
}
Instead of data = s, write data = strdup(s) to make a copy of the contents. Otherwise, you will assign the same pointer again and again, and you will overwrite the contents of the memory to which this pointer points again and again. At the end, your temporary buffer will contain the last line of your file, and all the pointers will point to exactly this buffer. That's what you are observing...
I have an example that I've been looking over and I'm trying to figure out how to write the .h and .cpp files by looking at the main file and the output
I have a class called Flex:
#include <iostream>
#include "flex.h"
using namespace std;
int main()
{
Flex a, b("Merry"), c("Christmas");
cout << a << ',' << b << ',' << c << endl;
b.cat(a);
cout << b << endl;
b.cat(c);
cout << b << endl;
c.cat(c);
c.cat(c);
cout << c << endl;
return 0;
}
Execution output is:
* *,*Merry*,*Christmas*
*Merry *
*Merry Christmas*
*ChristmasChristmasChristmasChristmas*
And then, the declaration/definition files should look like this:
#include <iostream>
using namespace std;
class Flex
{
friend ostream& operator<< (ostream& s, const Flex& f);
public:
Flex(); // default constructor
Flex(const char *); // constructor with parameters
~Flex(); // destructor (not specifically required)
void cat(const Flex & f); // cat function -- concatenation
private:
char * str; // variable length string
int size;
};
and
#include <iostream>
#include <cstring>
#include "flex.h"
using namespace std;
ostream& operator<< (ostream& s, const Flex& f)
{
s << '*' << f.str << '*';
return s;
}
Flex::Flex()
{
size = 1; // size doesn't include null char
str = new char[size+1]; // allocate +1 for null char
strcpy(str," ");
}
Flex::Flex(const char * s)
{
size = strlen(s);
str = new char[size+1];
strcpy(str,s);
}
Flex::~Flex()
// not specifically required by the specs, but a good idea to have this
{
delete [] str;
}
void Flex::cat(const Flex & f)
// this function can also be made easier through the use of the
// strcat library function for concatenating strings.
// dyanamic reallocation still required, though.
{
int newsize = size + strlen(f.str);
char * temp = new char[newsize+1]; // allocate with room for '\0'
strcpy(temp,str); // copy this string to temp
for (int i = 0; i <= f.size; i++)
temp[size+i] = f.str[i]; // concatenate f.str to temp,
// including '\0'
delete [] str; // delete old array
str = temp; // set str to new one
size = newsize; // update size tracker
}
This question might be hard to explain, but how does one look at the main program and immediately knows what class he has to write?
I need to do this for a class that involves stats. I do not have a main program yet, but what would we be different since I wouldn't use chars anymore ?
How would I go about representing a stats class just by looking at a main file and output ?
Operator << sends '*' << f.str << '*'(Where f.str it`s your, Flex object, str value ) You have constructor of class Flex
Flex::Flex()
{
size = 1; // size doesn't include null char
str = new char[size+1]; // allocate +1 for null char
strcpy(str," ");
}
Flex::Flex(const char * s)
{
size = strlen(s);
str = new char[size+1];
strcpy(str,s);
}
When your initialize object like Flex a("Test"). Your a.str == "Test". When Flex a(), then a.str == "". Function cat is concatanation 2 value. If b.cat(a) it`s mean that b.str = b.str + a.str
The C fprintf() function returns the number of characters printed. Is there similar functionality in C++ when writing to a file with ofstream? I am interested in a solution that is compatible with C++03 if possible.
For example:
ofstream file("outputFile");
file << "hello";
// Here would I like to know that five characters were printed.
file << " world";
// Here I would like to know that six characters were printed.
What you're looking for is tellp().
You could use it like so:
ofstream file("outputFile");
auto pos1 = file.tellp();
file << "hello";
auto pos2 = file.tellp();
std::cout << pos2 - pos1 << std::endl;
Seek operations are rather expensive (primarily because they need to prepare streams to potentially switch between reading and writing). I'd personally rather use a filtering stream buffer which provides the counts, e.g.:
class countbuf: public std::streambuf {
std::streambuf* sbuf;
std::size_t count;
char buffer[256];
int overflow(int c) {
if (c != std::char_traits<char>::eof()) {
*this->pptr() = c;
this->pbump(1);
}
return this->sync() == -1
? std::char_traits<char>::eof()
: std::char_traits<char>::not_eof(c);
}
int sync() {
std::size_t size(this->pptr() - this->pbase());
this->count += size;
this->setp(this->buffer, this->buffer + 256);
return size == this->sbuf->sputn(this->pbase(), this->pptr() - this->pbase())
? this->sbuf->pubsync(): -1;
}
public:
countbuf(std::streambuf* sbuf): sbuf(sbuf), count() {
this->setp(buffer, buffer + 256);
}
std::size_t count() const { return count + this->pptr() - this->pbase(); }
std::size_t reset() const {
std::size_t rc(this->count());
this->sync();
this->count = 0;
return rc;
}
};
Once you got this stream buffer, you could just install into an std::ostream (and possibly package the construction into a custom stream class):
countbuf sbuf(std::cout.rdbuf()); // can't seek on this stream anyway...
std::ostream out(&sbuf);
out << "hello!\n" << std::flush;
std::cout << "count=" << out.reset() << '\n';
I would like to know if it is possible to inherit from std::ostream, and to override flush() in such a way that some information (say, the line number) is added to the beginning of each line. I would then like to attach it to a std::ofstream (or cout) through rdbuf() so that I get something like this:
ofstream fout("file.txt");
myostream os;
os.rdbuf(fout.rdbuf());
os << "this is the first line.\n";
os << "this is the second line.\n";
would put this into file.txt
1 this is the first line.
2 this is the second line.
flush() wouldn't be the function to override in this context, though you're on the right track. You should redefine overflow() on the underlying std::streambuf interface. For example:
class linebuf : public std::streambuf
{
public:
linebuf() : m_sbuf() { m_sbuf.open("file.txt", std::ios_base::out); }
int_type overflow(int_type c) override
{
char_type ch = traits_type::to_char_type(c);
if (c != traits_type::eof() && new_line)
{
std::ostream os(&m_sbuf);
os << line_number++ << " ";
}
new_line = (ch == '\n');
return m_sbuf.sputc(ch);
}
int sync() override { return m_sbuf.pubsync() ? 0 : -1; }
private:
std::filebuf m_sbuf;
bool new_line = true;
int line_number = 1;
};
Now you can do:
linebuf buf;
std::ostream os(&buf);
os << "this is the first line.\n"; // "1 this is the first line."
os << "this is the second line.\n"; // "2 this is the second line."
Live example
James Kanze's classic article on Filtering Streambufs has a very similar example which puts a timestamp at the beginning of every line. You could adapt that code.
Or, you could use the Boost tools that grew out of the ideas in that article.
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/array.hpp>
#include <cstring>
#include <limits>
// line_num_filter is a model of the Boost concept OutputFilter which
// inserts a sequential line number at the beginning of every line.
class line_num_filter
: public boost::iostreams::output_filter
{
public:
line_num_filter();
template<typename Sink>
bool put(Sink& snk, char c);
template<typename Device>
void close(Device&);
private:
bool m_start_of_line;
unsigned int m_line_num;
boost::array<char, std::numeric_limits<unsigned int>::digits10 + 4> m_buf;
const char* m_buf_pos;
const char* m_buf_end;
};
line_num_filter::line_num_filter() :
m_start_of_line(true),
m_line_num(1),
m_buf_pos(m_buf.data()),
m_buf_end(m_buf_pos)
{}
// put() must return true if c was written to dest, or false if not.
// After returning false, put() with the same c might be tried again later.
template<typename Sink>
bool line_num_filter::put(Sink& dest, char c)
{
// If at the start of a line, print the line number into a buffer.
if (m_start_of_line) {
m_buf_pos = m_buf.data();
m_buf_end = m_buf_pos +
std::snprintf(m_buf.data(), m_buf.size(), "%u ", m_line_num);
m_start_of_line = false;
}
// If there are buffer characters to be written, write them.
// This can be interrupted and resumed if the sink is not accepting
// input, which is why the buffer and pointers need to be members.
while (m_buf_pos != m_buf_end) {
if (!boost::iostreams::put(dest, *m_buf_pos))
return false;
++m_buf_pos;
}
// Copy the actual character of data.
if (!boost::iostreams::put(dest, c))
return false;
// If the character copied was a newline, get ready for the next line.
if (c == '\n') {
++m_line_num;
m_start_of_line = true;
}
return true;
}
// Reset the filter object.
template<typename Device>
void line_num_filter::close(Device&)
{
m_start_of_line = true;
m_line_num = 1;
m_buf_pos = m_buf_end = m_buf.data();
}
int main() {
using namespace boost::iostreams;
filtering_ostream myout;
myout.push(line_num_filter());
myout.push(std::cout);
myout << "this is the first line.\n";
myout << "this is the second line.\n";
}
I'm attempting to create a custom std::streambuf which acts as a sub-stream to a parent stream. This is an adaptation of the implementation outlined in this SO thread answer.
In this example below I am attempting to simply read the first 5 characters "Hello," of the stream. However, when I call ifstream.read() into the buffer, the buffer is filled with "ello, ", as though it is off by one.
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
stringstream ss;
ss << "Hello, World!";
substreambuf asd(ss.rdbuf(), 0, 5);
istream istream(&asd);
char buffer[6] = { '\0' };
istream.read(buffer, sizeof(buffer));
cout << buffer << endl; //prints "ello, "
}
I am new to streambufs and I feel like I'm missing something obvious here. Any help would be appreciated.
Here is the definition for substreambuf:
#include <iostream>
#include <sstream>
namespace std
{
struct substreambuf : public streambuf
{
explicit substreambuf(streambuf* sbuf, streampos pos, streampos len) :
m_sbuf(sbuf),
m_pos(pos),
m_len(len),
m_read(0)
{
m_sbuf->pubseekpos(pos);
setbuf(nullptr, 0);
}
protected:
int underflow()
{
if (m_read >= m_len)
{
return traits_type::eof();
}
return m_sbuf->sgetc();
}
int uflow()
{
if (m_read >= m_len)
{
return traits_type::eof();
}
m_read += 1;
return m_sbuf->snextc();
}
streampos seekoff(streamoff off, ios_base::seekdir seekdir, ios_base::openmode openmode = ios_base::in | ios_base::out)
{
if (seekdir == ios_base::beg)
{
off += m_pos;
}
else if (seekdir == ios_base::cur)
{
off += m_pos + m_read;
}
else if (seekdir == ios_base::end)
{
off += m_pos + m_len;
}
return m_sbuf->pubseekpos(off, openmode) - m_pos;
}
streampos seekpos(streampos streampos, ios_base::openmode openmode = ios_base::in | ios_base::out)
{
streampos += m_pos;
if (streampos > m_pos + m_len)
{
return -1;
}
return m_sbuf->pubseekpos(streampos, openmode) - m_pos;
}
private:
streambuf* m_sbuf;
streampos m_pos;
streamsize m_len;
streampos m_read;
};
};
I thought this was strange when I first saw the code.
int uflow()
{
// ...
return m_sbuf->snextc();
}
Why is he returning the result of snextc()? The policy defined for uflow() is "return the next available character and advance the input stream by one character". If snextc() is called, the input sequence will be advanced, and then it will return the next character. The result is that at least 1 character is skipped.
The correct method to call would be sbumpc() because it will cache the next character first, advance the input stream, and then return it.
return m_sbuf->sbumpc();
Here is a demo.