I am having a head-scratcher and need a human more intelligent than I to tell me where I am wrong/ what is going on.
All I am trying to do is open a file, read the number, add one to the number, truncate the file with my new number, and be done. The purpose is so that I can keep a memory even after my (other larger) program is shutdown. Each time I run the function it does weird stuff
#include <iostream>
#include <fstream>
using namespace std;
int getcount(){
int number;
ifstream indata;
ofstream otdata;
indata.open("count.txt");
indata>>number;
number++;
otdata.open("count.txt", ios::trunc);
otdata.close();
return number;
}
int main()
{
int i;
i=getcount();
cout<<i<<endl;
}
my current output looks like this
32575
32655
65536
65536
65536
32622
Is there a better way to do this? Where should I look? Did I typo? I have done stuff just like this before and have read the documentation, my college books, etc, cant find anything revealing. Thank you in advance.
Does count.txt exist? If it does, it looks like you're not storing the number after you've opened it (nothing that writes back the number between otdata.open and otdata.close). Also, you should close indata after you're finished reading it.
Related
I'm making a C++ program to generate a million random numbers (I've generated them as just cout output once so I have the processing power) and I want to write them into a file.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <fstream>
using namespace std;
int main() {
srand(time(NULL));
int value;
ofstream file ("numbers.txt");
file.open ("numbers.txt", ios::out | ios::app );
int i = 0;
while (i < 1000000)
{
value = rand();
file << value;
}
file.close();
}
This is my current code, and I get no errors, but when I run it I see an empty txt file in my file explorer.
Can anyone tell me what's the problem here?
I tried it for only 100 numbers, and I got a blank text file
Don't reopen the same file:
...
ofstream file ("numbers.txt");
file.open ("numbers.txt", ios::out | ios::app ); // Remove this line
int i = 0;
...
That will make it work. However, the program won't ever stop, since you forgot to increment i too!
As said by other users in comments, you have an infinite loop: incrementing your loop control variable solves this problem. Then is not necessary to open and close the file explicitly if you use the standard library.
I would add that generally speaking rand() is not the function you may want to use, because it generates pseudo-random numbers, and even if it is ok for your application you may want to give a seed to it, throught the function srand().
If you want more from you program, have a look a this reference page.
I'm just trying to use the fstream library and I wanna read a given row.
I thought this, but I don't know if is the most efficient way.
#include <iostream>
#include <fstream>
using namespace std;
int main(){
int x;
fstream input2;
string line;
int countLine = 0;
input2.open("theinput.txt");
if(input2.is_open());
while(getline(input2,line)){
countLine++;
if (countLine==1){ //1 is the lane I want to read.
cout<<line<<endl;
}
}
}
}
Is there another way?
This does not appear to be the most efficient code, no.
In particular, you're currently reading the entire input file even though you only care about one line of the file. Unfortunately, doing a good job of skipping a line is somewhat difficult. Quite a few people recommend using code like:
your_stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
...for this job. This can work, but has a couple of shortcomings. First and foremost, if you try to use it on a non-text file (especially one that doesn't contain new-lines) it can waste inordinate amounts of time reading an entire huge file, long after you've read enough that you would normally realize that there must be a problem. For example, if you're reading a "line", that's a pretty good indication that you're expecting a text file, and you can pretty easily set a much lower limit on how long that first line could reasonably be, such as (say) a megabyte, and usually quite a lot less than that.
You also usually want to detect whether it stopped reading because it reached that maximum, or because it got to the end of the line. Skipping a line "succeeded" only if a new-line was encountered before reaching the specified maximum. To do that, you can use gcount() to compare against the maximum you specified. If you stopped reading because you reached the specified maximum, you typically want to stop processing that file (and log the error, print out an error message, etc.)
With that in mind, we might write code like this:
bool skip_line(std::istream &in) {
size_t max = 0xfffff;
in.ignore(max, '\n');
return in.gcount() < max;
}
Depending on the situation, you might prefer to pass the maximum line size as a parameter (probably with a default) instead:
bool skip_line(std::istream &in, size_t max = 0xfffff) {
// skip definition of `max`, remainder identical
With this, you can skip up to a megabyte by default, but if you want to specify a different maximum, you can do so quite easily.
Either way, with that defined, the remainder becomes fairly trivial, something like this:
int main(){
std::ifstream in("theinput.txt");
if (!skip_line(in)) {
std::cerr << "Error reading file\n";
return EXIT_FAILURE;
}
// copy the second line:
std::string line;
if (std::getline(in, line))
std::cout << line;
}
Of course, if you want to skip more than one line, you can do that pretty easily as well by putting the call to skip_line in a loop--but note that you still usually want to test the result from it, and break the loop (and log the error) if it fails. You don't usually want something like:
for (int i=0; i<lines_to_skip; i++)
skip_line(in);
With this, you'd lose one of the basic benefits of assuring that your input really is what you expected, and you're not producing garbage.
I think you can condense your code to this. if (input) is sufficient to check for failure.
#include <iostream>
#include <fstream>
#include <limits>
int main()
{
std::ifstream input("file.txt");
int row = 5;
int count = 0;
if (input)
{
while (count++ < row) input.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::string line;
std::getline(input, line);
std::cout << line;
}
}
Here is my code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string fname,lname;
double pincrease //pay increase percentage,pay;
ifstream infile;
ofstream outfile;
infile.open("C:\\Users\\Connor\\Desktop");
outfile.open("C:\\Users\\Connor\\Desktop");
while(!infile.eof())
{
infile>>lname>>fname>>pay>>pincrease;
pay = pay*(pay*pincrease);
outfile<<fname<<" "<<lname<<" "<<pay<<"\n";
cin.clear();
}
infile.close();
outfile.close();
}
And here are the contents of my infile:
Miller Andrew 65789.87 5
Green Sheila 75892.56 6
Sethi Amit 74900.50 6.1
The information is in the form of Last Name:First Name:Pay:Pay Increase Percentage.
The order swap of the first and last name and the exclusion of the pay percent increase when I write to the outfile is intentional.
I'm trying to read the contents of the infile, modify them, and then write it to an outfile.
However when I execute the code I start what I'm pretty sure is an infinite loop but I'm not sure how to fix it.
Neither of these statements likely open files:
infile.open("C:\\Users\\Connor\\Desktop");
outfile.open("C:\\Users\\Connor\\Desktop");
Rather, they attempt (and likely fail) to open your Desktop folder. Rather, you likely wanted something more like:
infile.open("C:\\Users\\Connor\\Desktop\\infile");
outfile.open("C:\\Users\\Connor\\Desktop\\outfile");
Of course, infile and outfile at the end there should be replaced with actual filenames.
You can test whether your file opens succeeded by checking infile.is_open() and outfile.is_open(). You might add explicit if statements to test this:
if (!infile.is_open())
// report/handle that you couldn't open input file
if (!outfile.is_open())
// report/handle that you couldn't open output file
For your main loop, you shouldn't be testing eof as you do. Rather, use something like this:
while(infile>>lname>>fname>>pay>>pincrease)
{
pay = pay*(pay*pincrease);
outfile<<fname<<" "<<lname<<" "<<pay<<"\n";
cin.clear();
}
Testing for EOF the way you were will try to read one extra record beyond end of file.
The EOF flag only gets set after a failed read attempt. Therefore you should always test for EOF after trying to read.
The standard ifstream is set up in such a way that a typical ifstream input operation (ie. infile >> item) will return a reference to an ifstream object. That's how you can do things like infile >> item1 >> item2 >> item3.
When you place that in the context of a loop control (as above), ifstream has the appropriate operator overloads that cause it to tell while whether to keep looping or not based on whether the reads succeeded.
Others have explained that overload magic well enough elsewhere. More info on the loop termination magic here: Why istream object can be used as a bool expression?
Replace this
infile.open("C:\\Users\\Connor\\Desktop");
outfile.open("C:\\Users\\Connor\\Desktop");
with this
infile.open("C:\\Users\\Connor\\infile.txt");
outfile.open("C:\\Users\\Connor\\outfile.txt");
The code you have posted will not compile for two reasons. One, The variable pay has not been declared and two, you have commented out the termination of the following code.
double pincrease //pay increase percentage,pay;
Try the below code. Hope it helps
int main()
{
string fname,lname;
double pincrease; //pay increase percentage,pay;
double pay;
ifstream infile;
ofstream outfile;
infile.open("C:\\Users\\Connor\\infile.txt");
outfile.open("C:\\Users\\Connor\\outfile.txt");
while(!infile.eof())
{
infile>>lname>>fname>>pay>>pincrease;
pay = pay*(pay*pincrease);
outfile<<std::setprecision(2)<<std::showpoint << std::fixed;;
outfile<<fname<<" "<<lname<<" "<<pay<<"\n";
cin.clear();
}
infile.close();
outfile.close();
}
trying to figure out how to make a little inventory program and I can't for the life figure out why it isn't working.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct record
{
int item_id;
string item_type;
int item_price;
int num_stock;
string item_title;
string item_author;
int year_published;
};
void read_all_records(record records[]);
const int max_array = 100;
int main()
{
record records[max_array];
read_all_records(records);
cout << records[2].item_author;
return 0;
}
void read_all_records(record records[])
{
ifstream invfile;
invfile.open("inventory.dat");
int slot = 0;
for (int count = 0; count<max_array; count++);
{
invfile >> records[slot].item_id >> records[slot].item_type >> records[slot].item_price >> records[slot].num_stock >> records[slot].item_title >> records[slot].item_author >> records[slot].year_published;
slot++;
}
invfile.close();
}
I'm testing it by having it print the second item from records author. When I run it, it doesn't show the authors name at all. The .dat file is located in just about every folder where the project is (I forgot which folder it needs to be in) so it's there.
The issue isn't that the file isn't working. It's the array not printing off anything.
my inv file is basically:
123456
book
69.99
16
title
etc
etc
and repeats for different books/cds etc all on one line, all without spaces. Should just next in.
You should check to see that the file is open.
invfile.open("inventory.dat");
if (!invfile.is_open())
throw std::runtime_error("couldn't open inventory file");
You should check to seen that your file reads are working and breaks when you hit the end of file.
invfile >> records[slot].item_id >> records[slot].item_type ...
if (invfile.bad())
throw std::runtime_error("file handling didn't work");
if (invfile.eof())
break;
You probably want to read each record at time, as it isn't clear from this code how the C++ streams are supposed to differentiate between each field.
Usually you'd expect to use std::getline, split the fields on however you delimit them, and then use something like boost::lexical_cast to do the type parsing.
If I were doing this, I think I'd structure it quite a bit differently.
First, I'd overload operator>> for a record:
std::istream &operator>>(std::istream &is, record &r) {
// code about like you had in `read_all_records` to read a single `record`
// but be sure to return the `stream` when you're done reading from it.
}
Then I'd use an std::vector<record> instead of an array -- it's much less prone to errors.
To read the data, I'd use std::istream_iterators, probably supplying them to the constructor for the vector<record>:
std::ifstream invfile("inventory.dat");
std::vector<record> records((std::istream_iterator<record>(invfile)),
std::istream_iterator<record>());
In between those (i.e., after creating the file, but before the vector) is where you'd insert your error handling, roughly on the order of what #Tom Kerr recommended -- checks for is_open(), bad(), eof(), etc., to figure out what (if anything) is going wrong in attempting to open the file.
Add a little check:
if (!invfile.is_open()) {
cout<<"file open failed";
exit(1);
}
So that way, you don't need to copy your input file everywhere like you do now ;-)
You are reading in a specific order, so your input file should have the same order and required number of inputs.
You are printing 3rd element of the struct records. So you should have at least 3 records. I don't see anything wrong with your code. It would a lot easier if you can post your sample input file.
I created this program:
#include <iostream>
#include <fstream>
using namespace std;
int main () {
fstream file;
file.open("test.bin", ios::in | ios::out | ios::binary);
if(!file.is_open())
{
return -1;
}
int n = 5;
int x;
file.write(reinterpret_cast<char*>(&n), sizeof(n));
file.read(reinterpret_cast<char*>(&x), sizeof(x));
std::cout<<x;
file.close();
std::cin.ignore();
return 0;
}
that's supposed to write an integer "n" into a .bin file "test.bin", then read data from "test.bin" into an integer "x", then displays "x" to the screen.
When I run the program, it displays not 5, but -842150451. Why does this occur, and how can I fix it?
Isn't the file.write() moving the current file pointer when you write it, causing you to read data from the first location AFTER the written data?
Insert file.seekg(0); between the read and write commands.
You have to reposition the file stream to the start of the file after you do the write in order to read the data you just wrote.
You should also check that the write wrote everything you expected it to, and whether the read actually read anything at all. The semi-random number is due to the read failing.
I agree with Jherico. You need a:
file.seekg (0, ios::beg);