I am trying to get this file stream program to work but when I run it all that happens is it outputs "Writing" instead of outputting the file. What am i doing wrong?
#include "stdafx.h"
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
char str[10];
ifstream b_file ( "ioTest.txt" );
b_file>> str;
cout<< str <<"\n";
cin.get();
}
The standard input streams use whitespace as a delimiter for input. If you try extracting to a string, it will extract every character until a whitespace character is found. If you need the entire content of the file, here are a few options:
while (in >> word)
while (b_file >> word)
{
std::cout << word;
}
This method will iterate over each whitespace-separated tokens in the input stream.
std::getline()
while (std::getline(b_file, line))
{
std::cout << line;
}
std::getline() retrieves line-wise input, meaning it will extract every character until it reaches a delimiter. The delimiter by default is the newline but it can be specified as a third argument.
std::istream_iterator<T>
std::copy(std::istream_iterator<std::string>(b_file),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(std::cout, "\n"));
std::istream_iterator is a special-purpose stream iterator class designed to "iterate" over tokens of type T from an input stream.
rdbuf()
std::cout << b_file.rdbuf();
This is more low-level. An overload of std::ostream::operator<<() takes a stream buffer pointer as an argument, and it will extract characters directly from the buffer.
Related
Imagine I want to copy-paste some text in stdin and I want to read it entirely in cpp (including whitespace). How can I do it? If I use cin, it reads tokens delimited by whitespace. If I do:
string text
string s;
while(cin>>s){
text += s;
}
Then it gets indistinguishable whether it was space(" ") or newline("\n") between tokens.
Question is, how can I read the whole string.
If you want something that is quick to code, use std::istream::getc.
std::string text;
char c;
while ( std::cin.getc(c) )
{
text.push_back(c);
}
If you expect the content of stdin to be large, this will be a performance problem. You should consider using std::istream::read for such use cases.
To make the result of the provided while loop approach distinguishable, I had to read it with readline() like this:
string text
string s;
while(readline(cin,s)){
text += s + "\n";
}
This way, it's guaranteed that readline will read the whole line (with spaces) and the given tokens will be only delimited by "\n" (which can be added manually).
From cplusplusreference.com:
As an object of class istream, characters can be retrieved either as
formatted data using the extraction operator (operator>>) or as
unformatted data, using member functions such as read.
cin - C++ Reference
I get:
#include <iostream>
#include <string>
using std::string;
using std::cin;
using std::cout;
using std::endl;
int main()
{
char c;
string text;
while (!cin.read(&c, 1).eof())
s += c;
cout << "string was " << s << endl;
}
On Windows, end it with a <Ctrl-Z> on a line by itself, followed by <Enter>. I tested it, and it does indeed include the end of line characters.
Let's say I read a std::string from std::istream by using std::getline() overload. How to determine how many characters extracted from the stream? std::istream::gcount() does not work as discussed here: ifstream gcount returns 0 on getline string overload
#include <iostream>
#include <sstream>
#include <string>
int main()
{
std::istringstream s( "hello world\n" );
std::string str;
std::getline( s, str );
std::cout << "extracted " << s.gcount() << " characters" << std::endl;
}
Live example
Note, for downvoters - length of the string is not the answer, as std::getline() may or may not extract additional character from the stream.
It would seem the way to do this is not completely straightforward because std::getline may (or may not) read a terminating delimiter and in either case it will not put it in the string. So the length of the string is not enough to tell you exactly how many characters were read.
You can test eof() to see if the delimiter was read or not:
std::getline(is, line);
auto n = line.size() + !is.eof();
It would be nice to wrap it up in a function but how to pass back the extra information?
One way I suppose is to add the delimiter back if it was read and let the caller deal with it:
std::istream& getline(std::istream& is, std::string& line, char delim = '\n')
{
if(std::getline(is, line, delim) && !is.eof())
line.push_back(delim); // add the delimiter if it was in the stream
return is;
}
But I am not sure I would always want that.
I've been trying to read some information in from a .txt file in C++ but it's not all working like I expect. Here is some example code:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
char words[255];
int value = 0;
ifstream input_stream("test.txt");
input_stream >> value;
input_stream.getline(words, 256);
cout << value << endl;
cout << words << endl;
}
And test.txt contains:
1234
WordOne WordTwo
What I expect is for the code to print the two lines contained in the text file, but instead I just get:
1234
I've been reading about getline and istream but can't seem to find any solutions so any help would be appreciated.
Thanks
The newline character remains in the input stream after the read of the integer:
// Always check result to ensure variables correctly assigned a value.
if (input_stream >> value)
{
}
Then, the call to getline() reads the newline character and stops, producing an empty string. To correct, consume the newline character before calling getline() (options include using getline() or ignore()).
Note there is a version std::getline() that accepts a std::string as its argument to avoid using a fixed sized array of char, which is used incorrectly in the posted code.
ifstream's getline method gathers input until one of two options is hit. Either a terminating character or the size passed in is reached. In your case, the newline terminator is encountered before the size is reached.
Use another getline to retrieve the second line of text.
Reference
The problem you are seeing is that the first newline after 1234 is not consumed by input_stream>>(int); so the next getline only reads to the end of that file.
This is a very constructed scenario, commonly found in schoolwork. The more common scenario when reading a textfile is to consider the entire file as linebased text.
In this case the more convenient
string line;
while( std::getline( input_stream, line ) ){
}
is appropriate, and way less error prone.
The textfile would commonly have a predefined format. Perhaps name = value lines, and are parsed as such after the line is read from the file.
Here is a somewhat corrected version of your original code:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
char words[256]; // was 255
int value = 0;
ifstream input_stream("test.txt");
input_stream >> value;
input_stream.ignore(); // skip '\n'
input_stream.getline(words, 256);
cout << value << endl;
cout << words << endl;
}
Also, I would advise you to use a string instead of a char[] and use the other getline function.
stringstream always seems to fail when I call stringstream::ignore(), even if this is done after calling stringstream::clear():
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cassert>
using namespace std;
int main() {
int a, b;
stringstream ss;
string str;
ifstream inFile("file.txt");
if(!inFile) {
cerr << "Fatal: Cannot open input file." << endl;
exit(1);
}
while(getline(inFile, str)) {
ss << str; // read string into ss
ss >> a >> b; // stream fails trying to store string into int
ss.clear(); // reset stream state
assert(ss.good()); // assertion succeeds
ss.ignore(INT_MAX, '\n'); // ignore content to next newline
assert(ss.good()); // assertion fails, why?
}
return 0;
}
file.txt contains the following text:
123 abc
456 def
Why is ss.good() false after ss.ignore()?
std::endl outputs \n and flushes the stream. However, stringstream::flush() is meaningless and does nothing. flush only has meaning when the underlying buffer is tied to an output device like the terminal, however, a stringstream has nowhere to flush the contents to. If you want to clear the contents of a stringstream do ss.str(""); instead. However, I would probably change the code to the following:
while(getline(inFile, str)) {
ss.str(str); // call ss.str() to assign a new string to the stringstream
if(!ss >> a >> b) // check if stream fails trying to store string into int
{
ss.clear(); // Read failed, so reset stream state
}
else
{
// Read successful
}
// Do other stuff
}
Also, if you want to insert a newline into the stringstream, just do ss << '\n'; and do not call std::endl.
It turns out there is no newline at the end of ss. After executing the following statements:
getline(infile, str);
ss << str;
ss will not contain a newline character, because getline() does not add a newline character to the end of the string stored into the second parameter. As a result, when this statement is executed:
ss.ignore(INT_MAX, '\n');
the stream fails because it reaches the end of the stream without finding a newline character to stop at.
ss.ignore() is not necessary if ss.str() is used to store the string, which replaces the entire contents of the stream. Should the stream fail, it should be reset and its contents set to the empty string "". Alternatively, ss.ignore() could be used, but only as long as a newline character is inserted into the stream immediately after the data is read so that it does not cause the stream to fail—but this would be redundant if the contents of the stream is later set to another value using ss.str().
A successful read of the next line of the file can be ensured by calling ss.clear() before the stream is assigned the contents of the next line of the file, since the old contents of the stream are overwritten on ss.str(). The stream state can be reset at the beginning of the loop, and no problems would occur even if the stream fails later in the loop:
while(getline(inFile, str)) {
ss.clear(); // make sure stream is good
ss.str(str); // overwrite contents of stream with str
ss >> a >> b;
// Even if the stream fails after this line, the stream is reset before each
// line is stored into the stream, and no problems should occur while reading
// and parsing subsequent lines in the file.
// Code to validate and store data from file...
}
i have a little problem on writing the string into a file,
How can i write the string into the file and able to view it as ascii text?
because i am able to do that when i set the default value for str but not when i enter a str data
Thanks.
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
int main()
{
fstream out("G://Test.txt");
if(!out) {
cout << "Cannot open output file.\n";
return 1;
}
char str[200];
cout << "Enter Customers data seperate by tab\n";
cin >> str;
cin.ignore();
out.write(str, strlen(str));
out.seekp(0 ,ios::end);
out.close();
return 0;
}
Please use std::string:
#include <string>
std::string str;
std::getline(cin, str);
cout << str;
I'm not sure what the exact problem in your case was, but >> only reads up to the first separator (which is whitespace); getline will read the entire line.
Just note that >> operator will read 1 word.
std::string word;
std::cin >> word; // reads one space seporated word.
// Ignores any initial space. Then read
// into 'word' all character upto (but not including)
// the first space character (the space is gone.
// Note. Space => White Space (' ', '\t', '\v' etc...)
You're working at the wrong level of abstraction. Also, there is no need to seekp to the end of the file before closing the file.
You want to read a string and write a string. As Pavel Minaev has said, this is directly supported via std::string and std::fstream:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ofstream out("G:\\Test.txt");
if(!out) {
std::cout << "Cannot open output file.\n";
return 1;
}
std::cout << "Enter Customer's data seperated by tab\n";
std::string buffer;
std::getline(std::cin, buffer);
out << buffer;
return 0;
}
If you want to write C, use C. Otherwise, take advantage of the language you're using.
I can't believe no one found the problem. The problem was that you were using strlen on a string that wasn't terminated with a null character. strlen will keep iterating until it finds a zero-byte, and an incorrect string length might be returned (or the program might crash - it's Undefined Behavior, who knows?).
The answer is to zero-initialize your string:
char str[200] = {0};
Supplying your own string as the value of str works because those in-memory strings are null-terminated.