Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
Hi my professor posted this example to her website giving an example of ifstreams, how come I cant open any .txt file?
#include <iostream>
#include <iomanip> // for setw
#include <fstream> // for ifstream, ofstream
using namespace std;
int main()
{
char filename[25]; // a string for filename entry
int val; // for reading integers from file
int sum = 0, count = 0;
double average;
ifstream in1; // create an input file stream
do
{
in1.clear();
cout << "Please enter the name of the input file.\n";
cout << "Filename: ";
cin >> setw(25) >> filename;
in1.open(filename);
if (!in1)
cout << "That is not a valid file. Try again!\n";
} while (!in1);
// PROCESS THE INPUT FILE
// Read all integer values and compute average
while (!in1.eof()) // while not end of file
{
in1 >> val; // read an integer from file
if (!in1.fail()) // in case last call failed to read an int
{ // due to trailing white space at end of file
count++;
sum += val;
}
}
average = static_cast<double>(sum) / count;
cout << "There were " << count << " numbers in the file\n";
cout << "Sum = " << sum << "\t\tAverage = " << average << "\n\n";
in1.close();
return 0;
}
This is extremely aggravating! Is it a problem with my computer or something?
Blockquote
Let me make two assumptions: you are using some IDE and you are using relative paths.
IDEs often execute your binary from a directory different than the project main dir. Try using absolute paths, find the right directory or run the file yourself.
The first thing you should start do do, is to write code to understand the error. It's not only for you now, to debug, but also for users later on when they will encounter problems:
....
if (!in1) { // replace this bloc
cout << filename << " is not a valid file\n"; // print filename to find out any issues (truncated name, etc...)
cout << "Error code: " << strerror(errno)<<endl; // Get some system info as to why
char cwd[512]; // print current working directory.
getcwd(cwd, sizeof(cwd)); // in case your path is relative
cout << "Current directory is " << cwd << endl;
cout << "Try again !\n";
}
Please note that getcwd() works as under linux, but in windows, you'll have to use _getcwd() instead.
IMPORTANT REMARK:
The following is not causing your error, but it might cause problems later on:
while (!in1.eof()) { // while not end of file
in1 >> val; // read an integer from file
...
prefer the following:
while (in1 >> val) { // while read of file works
...
Browse arround on SO: there are lots of questions/answers that explain why.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
This is what I tried. I tried strcpy, substituting the value and using in_file again 3 of them can't work. This program is supposed to use the data in a input file and then does functions 1-4 selected by user.
List all products
Search the price of a product
Update the price of a product
Exit
If the user chooses to exit, the program will write the updated data in the array of structures to the file.
The product information includes product number, description and price.
#include <iomanip>
#include <fstream>
#include <cstring>
using namespace std;
typedef struct
{
char product_num[5];
char product_des[29];
float price;
}PRODUCT_TYPE;
int main()
{
ifstream in_file("input practical 12 part d.txt");
if (!in_file)
{
cout << "Error opening input file" << endl;
}
else
{
PRODUCT_TYPE product[50];
int index = -1;
int choice;
in_file >> product[++index].product_num;
cout << "Succesful run" << endl;
cout << "Menu (Type number for the function)" << endl;
cout << "1. List all products\n2.Search the price of a product\n3.Update the price of a product\n4.Exit\n";
cin >> choice;
if (choice == 1)
{
cout << setw(18) << left << "Product Index" << setw(35) << left << "Product Description" << "Price" << endl;
}
else if (choice == 3)
{
cout << "Enter the product number to change its price: ";
cin >> product[index].product_num;
cout << "Enter the new price of the product: ";
cin >> product[index].price;
}
else if (choice == 4)
{
cout << setw(18) << left << "Product Index" << setw(35) << left << "Product Description" << "Price" << endl;
}
while (in_file)
{
in_file >> product[index].product_des >> product[index].price;
if (choice == 1)
{
cout << setw(18) << left << product[index].product_num << setw(35) << left << product[index].product_des << product[index].price << endl;
}
else if (choice == 2)
{
cout << "Type the product number to get the price" << endl;
cout << "Product Number: ";
cin >> product[index].product_num;
cout << "Price: ";
cout << product[index].price << endl;
}
else if (choice == 4)
{
cout << setw(18) << left << product[index].product_num << setw(35) << left << product[index].product_des << product[index].price << endl;
}
in_file >> product[++index].product_num;
}
in_file.close();
out_file.close();
}
return 0;
}```
Unfortunately changes in existing files are not that easy. The problem is that data are stored byte after byte in a file on a disk (sometimes even not that). So, if you have data in your file (always one byte) like the below
Position in file: 0 1 2 3 4 5 9 7 8 9 . . .
Bytes as decimal: . . . 49 50 51 61 62 63 . . .
Bytes as character: . . . 1 2 3 A B C . . .
And you want to update 1 2 3 at position 3 by 1 2 3 4 5 then you would need to shift all folowing bytes in the file by 2 characters, because 12345 is 2 bytes longer than 123. Nobody can do that. And it will not be done automatically.
So, there are basically 2 approaches to solve such problems.
Open the source file -> Read all data into memory -> Close source file -> Do the modifications in memory -> Open source file in overwrite mode -> Write new data.
Use a temporary file. -> Open the source file for input -> Open a temporary file for output -> Read source file line by line -> Do modifications for each read line immediately -> Write result to temp file -> After all source file data have been read, close both files -> Delete the original source file. Rename the tempfile to the old source file name.
(3. If the length of the data, that you want to modifiy, is the same than the old data, then you could move the file write pointer and overwrite the old data. But you need always the same length. So, most often not feasible)
There are of course more solutions, but those 2 approaches are often used.
Please see some pure example codes. Just plain example, unrelated to your code. No productive code. No error checking. Just to give you an idea, how it could work.
Method 1
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
std::vector<std::string> readFile(const std::string& filename) {
// Here we will store all the data from the file
std::vector<std::string> fileData;
// Open the source file
std::ifstream fileStream(filename);
// Read line by line and add it to our fileData
std::string line;
while (std::getline(fileStream, line)) {
fileData.push_back(line);
}
return fileData;
}
void writeFile(std::vector<std::string>& fileData, const std::string& filename) {
// Open file for output
std::ofstream fileStream(filename);
// Write all data to file
for (const std::string& line : fileData)
fileStream << line << '\n';
}
int main() {
// Aproach with read complete file to local variable, modify and the store again
const std::string dataFileName("r:\\test.txt");
// Get file content
std::vector<std::string> data = readFile(dataFileName);
// Now go through all records and do something
for (std::string& line : data) {
// If some condition is met then do something, for example modify
if (line == "Line1") line += " modified";
}
// And then write the new data to the file
writeFile(data, dataFileName);
return 0;
}
Method 2:
#include <iostream>
#include <fstream>
#include <string>
#include <cstdio>
int main() {
// Aproach with temp file, remove and rename, and on the fly change
const std::string dataFileName("r:\\test.txt");
const std::string tempFileName("r:\\temp.txt");
{
// Open the source file with data
std::ifstream dataFileStream(dataFileName);
// Open the temporary file for output
std::ofstream tempFileStream(tempFileName);
// Now read the source file line by line with a simple for loop
std::string line;
while (std::getline(dataFileStream, line)) {
// Identify the line that should be deleted and do NOT write it to the temp file
if (line != "SearchString") { // Or any other condition
// Write only, if the condition is not met
tempFileStream << line << '\n';
}
}
} // The end of the scope for the streams, will call their destructor and close the files
// Now, remove and rename
std::remove(dataFileName.c_str());
std::rename(tempFileName.c_str(), dataFileName.c_str());
return 0;
}
Disclaimer: I am a beginner to programming, so what I say might sound really stupid
I have to make a "Telephone Directory" for school. The program isn't complete, but there are some things that I need to fix before moving on. The array TelephoneNumbers either isn't storing the numbers from the file correctly, or isn't displaying them. For the SeaerchRecords function, the first number in the file is displayed correctly, the second is displayed as "2147483647," and the rest of the numbers display as "0." The modify function also doesn't change the number, and I confirmed this with the while in the function. The string array works perfectly fine, however. May someone explain what I'm doing incorrectly?
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
string TelephoneNames[100];
int TelephoneNumbers[100];
void ModifyRecords(); //Function to Modify Records
void SearchRecords(); //Function to Search Records
void DeleteRecords(); //Function to Delete Records
int main()
{
fstream inputFile;
fstream outputFile;
char choice;
inputFile.open("Telephone Names.txt"); //To store
for (int count=0;count<100;count++) //file names
{ //into a
inputFile >> TelephoneNames[count]; //string
}
inputFile.close();
inputFile.open("Telephone Numbers.txt");//To store
for (int count=0;count<100;count++) //file #'s
{ //into a
inputFile >> TelephoneNumbers[count];//string
}
inputFile.close();
//Display options available
cout << " Hello, do you want to:\n";
cout << " ======================\n";
cout << "-Modify Records|Enter M\n";
cout << "-Search Records|Enter S\n";
cout << "-Delete Records|Enter D\n";
//Store choice
cin >> choice;
//Send to different function
if (choice=='M'||choice=='m')
{
ModifyRecords();
}
if (choice=='S'||choice=='s')
{
SearchRecords();
}
return 0;
}
void ModifyRecords()
{
string name;
string newname;
int newnumber;
int count=0;
cout << "Enter the name of the person: ";
cin >> name;
for (count=0;TelephoneNames[count]!=name;count++)//To determine where in the strings the new numbers need to be
{
}
cout << "Enter the new name of the person: ";
cin >> newname;
cout << "Enter the new number of the person: ";
cin >> newnumber;
TelephoneNames[count]={newname};
TelephoneNumbers[count]={newnumber};
count=0;
while (count<6)
{
cout << TelephoneNames[count] << endl;
cout << TelephoneNumbers[count] << endl;
cout << endl;
count++;
}
}
void SearchRecords()
{
string name;
int count=0;
cout << "Enter the name of the person you would like to find: ";
cin >> name;
for (count=0;TelephoneNames[count]!=name;count++)//To determine where in the strings the new numbers need to be
{
}
cout << "Name: " << TelephoneNames[count] << endl;
cout << "Number: " << TelephoneNumbers[count] << endl;
}
Since there is no any answer still and I don't see exactly the problem at this point I'll provide some suggestions how you can find a problem in your code.
In any programming situation when you can't find a bug, first task is to locate it as much precisely as you can and check all input data and assumptions. Usually, debugger is used for such purposes, but you can just output text in console before creating final version of your program.
To start with, you must check that you really received names and telephones from your file:
inputFile.open("Telephone Names.txt"); //To store
for (int count=0;count<100;count++) //file names
{ //into a
inputFile >> TelephoneNames[count]; //string
cout << TelephoneNames[count] << endl; //WE MUST SEE WHAT IS REALLY STORED IN TelephoneNames
}
inputFile.close();
inputFile.open("Telephone Numbers.txt");//To store
for (int count=0;count<100;count++) //file #'s
{ //into a
inputFile >> TelephoneNumbers[count];//string
cout << TelephoneNumbers[count] << endl; //WE MUST SEE WHAT IS REALLY STORED IN TelephoneNumbers
}
inputFile.close();
Ok, when it is checked and you are defenitely sure there is no problem in your data we can move to SeaerchRecords function doing the same procedure. We must check what is happening while you are searching:
for (count=0;TelephoneNames[count]!=name;count++)//To determine where in the strings the new numbers need to be
{
cout << "Search step: " << count << " name " << name << " found name " << TelephoneNames[count] << " number " << TelephoneNumbers[count] << endl;
}
Doing so you will locate your bug rather quickly. The problem can be in input files format, in difference of "name" and stored names format etc.
I'll provide several additional suggestion how you can improve your code.
1) Try to use const declarations for such commonly used things as number of records (const int NUMBER_OF_RECORDS = 100; insted of just putting '100' everywhere), it will reduce the amout of work and possible bugs. 2) Try to check all possible problems that you program can encounter if someting is wrong with data. What will happen if you have less than 100 records in your files now? Program crush or silent reading of unappropriate data which is even worse. Check that you haven't reach file end on any step of reading along with current check that you've reached you number of records and do something in case of unappropriate data.
3) Check the possible problems with conditions in your cycles not to run them infinite number of times. Now your condition for(count=0;TelephoneNames[count]!=name;count++)
will execute forever if there is no such name or just crush the program on count 100 or more. You should check that count doesn't exceed that value. Good luck!
I posted something on this last night, but I have decided to change my approach slightly as I wasn't fully understanding the code I was trying to use.
I apologise as I know this topic has been done to death but I'd like a little help with the code I've written.
I'm loading a .txt file from my computer with 100 integers in. They are each on new lines.
This is my code so far:
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
using namespace std;
int main ()
{
ifstream fout;
ifstream fin;
string line;
ifstream myfile ("100intergers.txt");
if (myfile.is_open())
{
while ( getline(myfile,line) )
{
cout << line << '\n';
}
// Closes my file
myfile.close();
// If my file is still open, then show closing error
if (myfile.is_open())
cerr << "Error closing file" << endl;
exit(1);
}
int y = 0;
int z = 0;
int sum = 0;
double avg = 0.0;
avg = sum/(y+z);
cout << endl << endl;
cout << "sum = " << sum << endl;
cout << "average = " << avg << endl;
// checking for error
if (!myfile.eof())
{
cerr << "Error reading file" << endl;
exit(2);
}
// close file stream "myfile"
myfile.close();
return(0);
}
When I run it I get exit code 1 (as well as a list of my 100 integers).
Which means my if clause isn't the right choice, what's a better alternative?
If I delete that bit completely, it fails to run do to an arithmetic error which I think is 0/0*0
Also I think the code I've written for the .txt file is for words, not numbers, but when I change string to int it really bugs and tells me I have more problems than without.
Finally - after this I want to make an array to calc variance - any tips?
Cheers
Jack
You're reading lines from the file, which you output.
Then you do arithmetic with some variables, all of which have the value zero.
These variables have no connection to the file's contents.
I'll help with the basic loop structure by showing a way to count the numbers in the file:
int main()
{
int value = 0;
int count = 0;
ifstream myfile("100intergers.txt");
while (myfile >> value)
{
count++;
}
cout << "There were " << count << " numbers." << endl;
}
Summing and the rest is left as an exercise.
I'm trying to solve this issue where when i try and search for a certain module name in my .dat file, it doesn't show the info of some module like module name, module code.
Example: if I search CSCI124, it shows all of the needed info i need in the output.
However if i try searching for CSCI114 or MATH121, it doesn't show any info except for "Subject Code not found.."
I have tried playing around with not putting in the while loop however it doesn't work as well.
It would be awesome if you guys could help me out, just started learning about c++
Subject subjectDB;
char subCode[MAX];
int printOnce = 0;
int position = 0;
cout << "Enter Subject Code: ";
cin >> subCode;
// Open binary file
ifstream fin("Subject.dat", ios::out | ios::binary);
if (!fin)
{
cout << "\nError opening database..\n"
<< "\tQuitting System..";
exit(-1);
}
cin.clear();
cin.ignore(100, '\n');
while(fin.read(reinterpret_cast<char*>(&subjectDB), sizeof(Subject)))
{
if (!(strcmp(subCode, subjectDB.subjectCode) == 0))
{
// Print this section once
if (printOnce == 0)
{
cout << "Subject Code not found..\n";
printOnce++;
}
}
else
{
// Print this section once
if (printOnce == 0)
{
cout << "\nSubject Code: "
<< subjectDB.subjectCode
<< "\nSubject Name: "
<< subjectDB.subjectName
<< "\n"
<< endl;
cout << "Task\t"
<< "Title\t\t"
<< "Weight\t"
<< "Upon\t"
<< "Mark\t"
<< "Obtained\n";
// PrintOnce++ : 1 != 0
// So it only prints once
printOnce++;
}
cout << position + 1
<< "\t"
<< subjectDB.assessment[position].title
<< "\t"
<< subjectDB.assessment[position].weight
<< "\t"
<< subjectDB.assessment[position].upon
<< "\t"
<< subjectDB.assessment[position].taskMark
<< "\t"
<< "testing\n";
position++;
}
}
Writing a struct to a file or reading a struct from a file is totally non-portable. Compile the same code on two different compilers, or on the same compiler with different settings, and what you wrote and what you read might be very different. That's not necessarily your problem, but it will be your problem one day.
Your display code logic is flawed.
Explanation:
If the subject code is in the first record you read, you'll get the correct answer. However as soon as your fist record does not match, the "Not found" message is displayed, printOnce is incremented. If the matching subject coe is found later in the file printOnce is no longer 0 and it' will not be displayed.
Solution:
Organise your loop in the opposite way:
while (...) {
if (strcmp(..)==0) {
// your code to display the found item here
printOnce++;
break; // ?? optional: you could stop the loop at first found occurence unless you suppose there could be duplicates
}
}
and once the loop is finished, check OUTSIDE OF THE LOOP if you've found something:
if (printOnce==0) { // nothing was found in the loop
// display that nothing was found !
}
Remark:
Reading directly from file as you do has limitations. It can only work with plain old data (POD), not with more advanced types using string members or containters. For learning it's a good start but I'd suggest to foresee a Subject member function that loads the data from a stream. This proves to be more flexible when your data structure evolves: the member function could ealsily read each member data and sub-objects using the most apporpriate way.
Thanks for your help! I managed to get the function to compare properly against user input and struct file by creating a function that checks the .dat file if the subject is existing or not.
int row = checkNumberOfData(fileName);
if (row > 0)
exist = doesSubjectExist(file, fileName, code); // checks input
if (!exist)
{
file.open(fileName, ios::out | ios::app | ios::binary);
if (!file)
{
cout << "Error opening database..\n"
<< "\tQuitting System ..\n";
exit(-1);
}
strcpy(subjectDB.code, code);
cout << "Subject Name: ";
cin.getline(subjectDB.name, MAX);
cout << "No of assessment tasks: ";
cin >> subjectDB.num;
cout << endl;
.... etc
}
I was asked to write a program to open a txt.doc and find the: number of numbers in the list, the sum and the avg. With I compile the code my valves equal zero. I cant find out where I went wrong.
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <fstream>
using namespace std;
int main()
{
ifstream inputFile;
string filename;
int valve;
int aNumber = 0;
int numbers = 0;
double sum = 0.0;
double average = 0.0;
// get file from user
cout << "enter the filename\n";
cin >> filename;
cout << "_________________________________________\n";
// open file
inputFile.open(filename.c_str());
// if loop(if the file successfully opened, process it.)
if (inputFile)
{
while (inputFile >> valve)
{
cout << valve << endl;
}
}
else
{
//display an error message
cout << "Error opening the file\n";
}
cout << "\n";
while (inputFile >> aNumber)
{
numbers++;
sum += aNumber;
}
if (numbers > 0)
average = sum / numbers;
else
average = 0.0;
cout << "Number of numbers: " << numbers << "\n";
cout << "Sum is: " << sum << "\n";
cout << "Average is: " << average;
inputFile.close();
return 0;
}
I don't know why my "numbers" "sum" "average" = zero.
The problem with your code is that you try to read the same file multiple times without getting it off the end: once the stream converts to false it will stay in this state until the stream state is cleared and ignore any real file operations. Also, even if you clear() the file's state it would go immediately back into failure state when an attempt to read data is made because either the next value is misformatted or the end of the stream is reached. You could clear() the state and seekg() to the beginning of the file, though (although I'm not recommending this approach):
while (inputFile >> value) {
...
}
inputFile.clear(); // clear any state flags
inputFile.seekg(0, std::ios_base::beg);
Reading files is generally fairly expensive, not to mention that some sources for "files" can't be read multiple times (for example, a named pipe looks like a file but can be only read once). The cost comes from both the need to access the physical media and the, if that access is fast, the conversion internal to the program. Thus, you are best off to read the file just once and do all of the relevant calculations in the same pass. If combining these operations is deemed unreasonable, you might want to load the content into a container and then operated on the container:
std::vector<double> values{ std::istream_iterator<double>(inputFile),
std::istream_iterator<double>() };
// now use values
In case you'd argue that the file is large: in this case you actually do not want to read the file more than once nor do you want to store it in a container, i.e., you'd process the file in a single pass. For the task at hand doing so is fairly trivial and certainly quite feasible.