I need to find a way of reading in the last 6 lines of data from a file.
For example if I have
1
2
3
4
5
6
7
8
9
10
I need to read be able to get
10, 9, 8, 7, 6, 5, 4.
These need to then be put into variables or strings to be outputted later. Currently I have managed to read in the last line of the file but I have no idea how to then read in the other 5 numbers.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main()
{
std::ifstream in("test.txt");
if (in.is_open())
{
std::vector<std::string> lines_in_reverse;
std::string line, line2;
while (std::getline(in, line))
{
// Store the lines in reverse order.
lines_in_reverse.insert(lines_in_reverse.begin(), line);
}
cout << line << endl;
while (std::getline(in, line2))
{
// Store the lines in reverse order.
lines_in_reverse.insert(lines_in_reverse.begin(), line2);
}
cout << line2 << endl;
}
cin.get();
return 0;
}
Can anyone advise a way to this? I do not know of any functions or methods that can help.
EDIT
This method outputs the last 6 numbers from the file however they are backwards and I need a way to reverse them and get rid of the whitespace it prints out.
I'm unsure on how to use reverse and which arguments are required from this - http://en.cppreference.com/w/cpp/algorithm/reverse
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
char x;
ifstream f("test.txt", ios::ate);
streampos size = f.tellg();
for (int var = 1; var <= size; var++){
f.seekg(-var, ios::end);
f.get(x);
reverse(x);
cout << x;
}
cin.get();
return 0;
}
Alot of the responses show me how to reverse the text file using vectors but not the last 6 numbers which is the only information I need.
Regards
It's not a good idea to store all the lines you read in, because there can be e.g. a billion lines.
You only need to store the last 6.
The following code is designed to produce those lines in reverse order, as the question indicates that is a requirement:
#include <iostream>
#include <string>
#include <deque>
using namespace std;
auto main() -> int
{
string line;
deque<string> last_lines;
while( getline( cin, line ) )
{
if( last_lines.size() == 6 )
{
last_lines.pop_back();
}
last_lines.push_front( line );
}
for( auto const& s : last_lines )
{
cout << s << endl;
}
}
The output here is not exactly the question's example
” 10, 9, 8, 7, 6, 5, 4
because that's 7 lines, contradicting the 6 that's stated in the first sentence.
How to read a file and print it reverse, in only three statements of code (excluding declarations and other boilerplate):
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
void read_and_print_reverse_n(std::istream& is, const int n)
{
std::vector<std::string> v;
// This call reads all whitespace-delimited "words" from the input stream
// and appends them to the vector
std::copy(std::istream_iterator<std::string>(is),
std::istream_iterator<std::string>(),
std::back_inserter(v));
// Output the last `n` lines from the input
for (const auto i = v.rbegin();
i < v.rend() && i < v.rbegin() + n;
++i)
{
std::cout << *i << '\n';
}
}
int main()
{
read_and_print_reverse_n(std::cin, 6);
}
References
std::copy
std::istream_iterator
std::back_inserter
I think the answer here would solve the purpose where you store the lines in a vector and iterate the vector from the end.
As you are looking for some direct method to read the file, you can read the file character by character starting from the end using seekg and tellg.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main()
{
char x;
ifstream f("filename.txt",ios::ate);
streampos size = f.tellg();
for(int var=1;var<=size;var++){
f.seekg(-var,ios::end);
f.get(x);
printf("%c",x);
}
return 0;
}
You can also keep a count of \n to keep a track of the number of lines read from the end.
Related
How do I accept an unknown number of lines in c++? Each line has two strings in it separated by a space. I tried the solutions mentioned in This cplusplus forum, but none of the solutions worked for me. One of the solutions works only when Enter is pressed at the end of each line. I am not sure if the \n char will be given at the end of my input lines. What are my options?
My current attempt requires me to press Ctrl+Z to end the lines.
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
using namespace std;
int main(){
string line;
while(cin>>line and cin.eof()==false){
cout<<line<<'\n';
}
return 0;
}
I would like to take an unknown number of strings as shown below:
cool toolbox
aaa bb
aabaa babbaab
Please don't flag this as a duplicate, I really tried all I could find! I tried the following solution on the above given link by m4ster r0shi (2201), but it did not work for me.
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<string> words;
string word;
string line;
// get the whole line ...
getline(cin, line);
// ... then use it to create
// a istringstream object ...
istringstream buffer(line);
// ... and then use that istringstream
// object the way you would use cin
while (buffer >> word) words.push_back(word);
cout << "\nyour words are:\n\n";
for (unsigned i = 0; i < words.size(); ++i)
cout << words[i] << endl;
}
And this other solution also did not work: other soln, and I tried this SO post too: Answers to similar ques. This one worked for my example, but when I pass only one line of input, it freezes.
// doesn't work for single line input
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
using namespace std;
int main(){
string line ="-1";
vector<string>data;
while(1){
cin>>line;
if(line.compare("-1")==0) break;
data.push_back(line);
line = "-1";
}
for(int i =0;i<data.size();i+=2){
cout<<data[i]<<' '<<data[i+1]<<'\n';
}
return 0;
}
If each line has two words separated by whitespace, then perhaps you should have a Line struct which contains two std::strings and overloads the >> operator for std::istream.
Then you can just copy from std::cin into the vector.
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
struct Line {
std::string first;
std::string second;
};
std::istream& operator>>(std::istream& i, Line& line) {
return i >> line.first >> line.second;
}
int main() {
std::vector<Line> lines;
std::copy(
std::istream_iterator<Line>(std::cin),
std::istream_iterator<Line>(),
std::back_inserter(lines)
);
for (auto &[f, s] : lines) {
std::cout << f << ", " << s << std::endl;
}
return 0;
}
A test run:
% ./a.out
jkdgh kfk
dfgk 56
jkdgh, kfk
dfgk, 56
So I am trying to read string data from a file into a dynamically allocated array, but I cannot seem to get the correct code for doing so. I have below a code using an array of a preset size but that would not be efficient, hence why I want to use dynamic memory allocation. I know I have to use pointers but I am fairly new to the concept so any help would be greatly appreciated.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <algorithm>
#include <cctype>
#include <string>
#define SIZE 100
using namespace std;
void loadData();
int main()
{
loadData();
return 0;
{
string fileName;
std::string wordArray[SIZE];
cout << "Please enter the name of the text file you want to process followed by '.txt': " << endl;
cin >> fileName;
ifstream dataFile(fileName);
if (dataFile.fail()) {
cerr << fileName << " could not be opened." << endl; //error message if file opening fails
exit(-1);
}
while (!dataFile.eof()) {
for (int i = 0; i < SIZE; i++) {
dataFile >> wordArray[I];
for (std::string& s : wordArray) //this for loop transforms all the words in the text file into lowercase
std::transform(s.begin(), s.end(), s.begin(),
[](unsigned char c) { return std::tolower(c); });
}
}
dataFile.close();
}
}
The below program show how you can store the strings read from the input.txt file and store them in lowercase in a std::vector.
Version 1: Stores word by word(in lowercase) into the vector
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <sstream>
int main()
{
std::ifstream inputFile("input.txt");
//create vector that will contain the words in the file in lowercase
std::vector<std::string> wordVec;
std::string line, individualWord;
if(inputFile)
{
while(std::getline(inputFile, line, '\n'))
{
std::istringstream ss(line);
while(ss >> individualWord)//word by word
{
std::transform(individualWord.begin(), individualWord.end(), individualWord.begin(),
[](unsigned char c)
{ return std::tolower(c);
});
wordVec.push_back(individualWord);
}
}
}
else
{
std::cout<<"file could not be opened"<<std::endl;
}
inputFile.close();
//lets print out the elements of the vector to check if elements are correctly stored in lowercase
for(const std::string &elem: wordVec)
{
std::cout<<elem<<std::endl;
}
return 0;
}
The output of version 1 can be seen here.
Version 2: Stores a complete single line(in lowercase) into the vector
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
int main()
{
std::ifstream inputFile("input.txt");
//create vector that will contain the words in the file in lowercase
std::vector<std::string> wordVec;
std::string line;
if(inputFile)
{
while(std::getline(inputFile, line, '\n'))
{
std::transform(line.begin(), line.end(), line.begin(),
[](unsigned char c)
{ return std::tolower(c);
});
wordVec.push_back(line);
}
}
else
{
std::cout<<"file could not be opened"<<std::endl;
}
inputFile.close();
//lets print out the elements of the vector to check if elements are correctly stored in lowercase
for(const std::string &elem: wordVec)
{
std::cout<<elem<<std::endl;
}
return 0;
}
The output of the above(version 2) program can be seen here.
The difference between version 1 and 2 is that version 1 reads a complete line and then read word by word and store those words(in lowercase) into the std::vector while version 2 reads a complete line(which ends with '\n') and store that line(in lowercase) into the std::vector.
Sometime life could be easy. By using modern C++ elements, the implementation will be really simple in the end.
I am not so sure what I should explain for 3 lines of code. It is basically visible with the comments in the code.
Please see the first solution:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
#include <cctype>
int main() {
// Open the input file and check, if it could be opened
if (std::ifstream inputStream{ "r:\\input.txt" }; inputStream) {
// Define a vector and read all words from the file
std::vector words(std::istream_iterator<std::string>(inputStream), {});
// Show result to the user
std::copy(words.begin(), words.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
}
}
Then next solution converts the word into lower case. So, I had to write 4 statements. Please see the below second solution.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
#include <cctype>
int main() {
// Open the input file and check, if it could be opened
if (std::ifstream inputStream{ "r:\\input.txt" }; inputStream) {
std::vector<std::string> words{};
// Read all words from the file and convert to lower case
std::transform(std::istream_iterator<std::string>(inputStream), {}, std::back_inserter(words),
[](std::string w) { for (char& c : w) c = std::tolower(c); return w; });
// Show result to the user
std::copy(words.begin(), words.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
}
}
If data does not need to be stored, we can come up with a 2-statement version.
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <iterator>
#include <cctype>
int main() {
// Open the input file and check, if it could be opened
if (std::ifstream inputStream{ "r:\\input.txt" }; inputStream) {
// Read all words from the file and convert to lower case and output it
std::transform(std::istream_iterator<std::string>(inputStream), {}, std::ostream_iterator<std::string>(std::cout, "\n"),
[](std::string w) { for (char& c : w) c = std::tolower(c); return w; });
}
}
Sometime teachers want the students to learn dynamic memory management using pointers.
But the usage of pointers for owned memory is strongly discouraged. The std::vector has been invented for that reason over a decade ago.
Anyway, I will also show a solution using new. It works, but you should not use it.
int main() {
// Open the input file and check, if it could be opened
if (std::ifstream inputStream{ "r:\\input.txt" }; inputStream) {
// Do some initial allocation of memory
std::string* words = new std::string[1]{};
unsigned int numberOfAvaliableSlotsInDynamicArray{1};
// Now we want to read words. We want also to count the words,so that we can allocate appropriate memory
std::string word{};
unsigned int wordCounter{};
// Read all words in a loop
while (inputStream >> word) {
// Check, if we still have enough space in our dynamic array
if (wordCounter >= numberOfAvaliableSlotsInDynamicArray) {
// Oh, we are running out of space. Get more memory
numberOfAvaliableSlotsInDynamicArray *= 2;
std::string* temp = new std::string[numberOfAvaliableSlotsInDynamicArray]{};
// Copy all existing data into new array
for (unsigned int i{}; i < wordCounter; ++i)
temp[i] = words[i];
// Delete old memory
delete[] words;
// And assign new storage to words
words = temp;
}
// STore the recently read word at the end of the array
words[wordCounter] = word;
// Count words. Now we have one word more
++wordCounter;
}
// Now we have read all words from the file. Show output
for (unsigned int i{}; i < wordCounter; ++i)
std::cout << words[i] << '\n';
// Release memory
delete[] words;
}
}
And even smart pointers, which shall be used as pointers if at all, are not nice.
Also the following should not be used.
#include <iostream>
#include <fstream>
#include <string>
#include <memory>
int main() {
// Open the input file and check, if it could be opened
if (std::ifstream inputStream{ "r:\\input.txt" }; inputStream) {
// Do some initial allocation of memory
std::unique_ptr<std::string[]> words = std::unique_ptr<std::string[]>(new std::string[1]);
unsigned int numberOfAvaliableSlotsInDynamicArray{ 1 };
// Now we want to read words. We want also to count the words,so that we can allocate appropriate memory
std::string word{};
unsigned int wordCounter{};
// Read all words in a loop
while (inputStream >> word) {
// Check, if we still have enough space in our dynamic array
if (wordCounter >= numberOfAvaliableSlotsInDynamicArray) {
// Oh, we are running out of space. Get more memory
numberOfAvaliableSlotsInDynamicArray *= 2;
std::unique_ptr<std::string[]> temp = std::unique_ptr<std::string[]>(new std::string[numberOfAvaliableSlotsInDynamicArray]);
// Copy all existing data into new array
for (unsigned int i{}; i < wordCounter; ++i)
temp[i] = std::move(words[i]);
// And assign new storage to words
words = std::move(temp);
}
// STore the recently read word at the end of the array
words[wordCounter] = word;
// Count words. Now we have one word more
++wordCounter;
}
// Now we have read all words from the file. Show output
for (unsigned int i{}; i < wordCounter; ++i)
std::cout << words[i] << '\n';
}
}
Conclusion: Use a std::vector.
I'm working on something simple, and i want it to be able to take everything within a vector and put it into a .CSV file, where every row would be a new vector and the columns being each position within the vector.
This is my current code, however whenever I open the CSV file it is completely empty.
Any help would be greatly appreciated!
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main()
{
ofstream myfile;
myfile.open("test.csv");
vector<int> arrayOne = { 10, 20, 30, 40, 50 };
for (int i = 0; i < arrayOne.size(); i++)
{
myfile << arrayOne.at(i) << ",";
}
cin.ignore();
cin.ignore();
return 0;
}
As the marked answer is totally correct in the function it demands from OP, but is derivatives in the code drastically. Which can result in an undebugable code or alter the behavior OP intended. pls consider this code:
#include <iostream>
#include <fstream>
#include <vector>
// removed "using namespace std"
int main()
{
std::ofstream myfile; // added "std::"
myfile.open("test.csv");
std::vector<int> arrayOne { 10, 20, 30, 40, 50 };
for (int i = 0; i < arrayOne.size(); i++) { // added "{"
myfile << arrayOne.at(i) << ",";
} // added "{"
myfile.close(); // <- note this correction!!
std::cin.ignore(); // added this
std::cin.ignore(); // added this
return 0;
}
consider not using using namespace std. This namespace includes hundreds of thousand of functions. you may collide with one of them and this is a pain to debug.
The marked answer removes the parentheses {} at the for-loop. NEVER do that, you may run into undebugable problems, when you add one line to your for-loop. This line is no executed in the loop.
The answer also remove vital code from the OP twice: std::cin.ignore();
Close your file like this:
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main()
{
ofstream myfile;
myfile.open("test.csv");
vector<int> arrayOne = { 10, 20, 30, 40, 50 };
for (int i = 0; i < arrayOne.size(); i++)
myfile << arrayOne.at(i) << ",";
myfile.close();
return 0;
}
The point here is, output streams are often buffered. When you close the file, close() function ensures, any pending output sequence is written to the file.
I am trying to read all integers from a file and put them into an array. I have an input file that contains integers in the following format:
3 74
74 1
1 74
8 76
Basically, each line contains a number, a space, then another number.
I know in Java I can use the Scanner method nextInt() to ignore the spacing, but I have found no such function in C++.
#include <fstream>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> arr;
std::ifstream f("file.txt");
int i;
while (f >> i)
arr.push_back(i);
}
Or, using standard algorithms:
#include <algorithm>
#include <fstream>
#include <iterator>
#include <vector>
int main()
{
std::vector<int> arr;
std::ifstream f("file.txt");
std::copy(
std::istream_iterator<int>(f)
, std::istream_iterator<int>()
, std::back_inserter(arr)
);
}
int value;
while (std::cin >> value)
std::cout << value << '\n';
In general, stream extractors skip whitespace and then translate the text that follows.
// reading a text file the most simple and straight forward way
#include <iostream>
#include <fstream>
#include <string>
#include <conio.h>
using namespace std;
int main () {
int a[100],i=0,x;
ifstream myfile ("example.txt");
if (myfile.is_open()) // if the file is found and can be opened
{
while ( !myfile.eof() ) //read if it is NOT the end of the file
{
myfile>>a[i++];// read the numbers from the text file...... it will automatically take care of the spaces :-)
}
myfile.close(); // close the stream
}
else cout << "Unable to open file"; // if the file can't be opened
// display the contents
int j=0;
for(j=0;j<i;j++)
{//enter code here
cout<<a[j]<<" ";
}
//getch();
return 0;
}
I have a text file with 2 columns and many rows. each column is separated by spaces. i need to read them to a 2D array for further calculations.
my data file looks like
0.5 0.479425539
1 0.841470985
1.5 0.997494987
2 0.909297427
2.5 0.598472144
3 0.141120008
3.5 -0.350783228
4 -0.756802495
4.5 -0.977530118
5 -0.958924275
And my feeble attempt is
#include <iostream>
#include <fstream>
#include <string>
#include <conio.h>
#include <ctype.h>
using namespace std;
int main () {
char line,element;
std::ifstream myfile ("C:\\Users\\g\\Desktop\\test.txt");
if (myfile.is_open())
{
while ( myfile.good() )
{
getline(myfile,line);
cout << line<<endl;
_getch();
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
The problem is I'm not able to read them correctly.... its either reading the whole line... if I specify the delimiter as 'space' then, its not reading the next row.
Pls point out whats wrong. and what should i do to store the data into 2d array for further calculations.
Thank you
#include <fstream>
#include <string>
#include <sstream>
#include <iostream>
#include <vector>
int main(int argc, char** argv) {
std::ifstream f(argv[1]);
std::string l;
std::vector<std::vector<double> > rows;
while(std::getline(f, l)) {
std::stringstream s(l);
double d1;
double d2;
if(s >> d1 >> d2) {
std::vector<double> row;
row.push_back(d1);
row.push_back(d2);
rows.push_back(row);
}
}
for(int i = 0; i < rows.size(); ++i)
std::cout << rows[i][0] << " " << rows[i][1] << '\n';
}
The last for loop shows how to use the values in the "array". The variable rows is strictly speaking not an array, but a vector of vectors. However, a vector is much safer than c-style arrays, and allows access to its elements using [].
[As I posted this I saw a very similar program posted as a response. I wrote mine independently.]
You can read the whole line into a std::string, then use std::istringstream to extract the values from the line.
A complete working program:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
int main()
{
std::ifstream file("C:\\Users\\g\\Desktop\\test.txt");
std::string line;
// Read a line of input from the file
while (std::getline(file, line))
{
// `istringstream` behaves like a normal input stream
// but can be initialized from a string
std::istringstream iss(line);
float value;
// The input operator `>>` returns the stream
// And streams can be used as a boolean value
// A stream is "true" as long as everything is okay
while (iss >> value)
{
std::cout << "Value = " << value << '\t';
}
// Flush the standard output stream and print a newline
std::cout << std::endl;
}
}
Given the contents in the file being as in the question, the first three lines of output should be:
Value = 0.5 Value = 0.479425539
Value = 1 Value = 0.841470985
Value = 1.5 Value = 0.997494987
For a 2d-array, I would use a std::vector of std::array:
#include <vector>
#include <array>
...
std::vector<std::array<float, 2>> array;
...
float value1, value2;
if (iss >> value1 >> value2)
{
std::cout << "Values = " << value1 << ", " << value2;
array.emplace_back(std::array<int, 2>{{value1, value2}});
}
Now the first line values are array[0][0] and array[0][1], and the last lines values are array[array.size() - 1][0] and array[array.size() - 1][1].
As C++ has evolved over the years, below is a Modern C++ version.
It uses auto where possible
Uses std::pair to hold 2 values (A std::pair is a specific case of a std::tuple with two elements)
Does not close file (destructor does that at end of block)
Does not read line by line, as the stream uses <space> and <enter> as delimiters
The variables have meaningful names, so the program "reads" easily,
Uses a range for loop to output the data.
Doesn't bring the whole std namespace into the code - Why is “using namespace std” considered bad practice?
.
#include <fstream>
#include <iostream>
#include <vector>
#include <utility>
int main( int argc, char** argv )
{
if ( argc < 1 )
return -1;
const auto fileName = argv[ 1 ];
std::ifstream fileToRead( fileName );
typedef std::pair< double, double > DoublesPair;
std::vector< DoublesPair > rowsOfDoublesPair;
DoublesPair doublePairFromFile;
while ( fileToRead >> doublePairFromFile.first >> doublePairFromFile.second )
{
rowsOfDoublesPair.push_back( doublePairFromFile );
}
for ( const auto row : rowsOfDoublesPair )
std::cout << row.first << " " << row.second << '\n';
}