-
Problems with fstreams.
In my program, I am reading in a file ("source" - cannot be overwritten) and copying it to another file ("target") by reading and writing one line at a time. I am manipulating the data found in target within the lines, so I need a temp file ("temp_file") to hold the data while I manipulate it and write it back to target. I can copy source to target just fine, but I can't seem to copy target to temp_file. Do I need to reset the EOF flag of target? I am calling target.seekg( 0 ) and temp_file.seekp( 0 ), but I still end up with a blank temp_file, even though target fully has the original data. I am using the same method to copy source to target that I am using to copy target to temp_file. I can paste my entire code if it would help, but I think that might be excessive. Any ideas? I have been making sure to use seekg( 0 ) and seekp( 0 ), almost in excess in some cases.
Thanks in advance!
-
Since you probably originally opened target for output only, target.seekg() may not work.
You can either close the file (target.close()) and reopen for input, or when you originally opened it, open for input and output ( target.open(filename,ios::in | ios::out) ).
One of these two should work.
-
I opened all the files for both input and output, so that's not the problem. Well here goes...
Code:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
void getNewHeader( fstream & );
int getNumLinesHeader( fstream & );
void getNewColumnTitles( fstream &, const int & );
bool isNotInt( const char & );
void transferData( fstream &, fstream & );
void displayHeader( fstream &, int & );
void displayData( fstream &, const int & );
void arrangeData( fstream &, const int &, char [], int & );
int menuChoice();
int getNumColumns( fstream & );
void eraseColumn( fstream &, fstream &, int & );
void switchColumns( fstream &, fstream & );
void quit();
void getPastHeader( fstream & );
void copyFile( fstream &, fstream &, char [] );
int main() {
fstream source;
char sourcename[81];
do {
cout << "Enter data source file: ";
cin >> sourcename;
source.open( sourcename, ios::in );
if( !source )
cout << "Invalid file name: File does not exist." << endl;
} while( !source );
fstream target; // stream to read from target file
bool done = false;
char targetname[81];
while( !done ) {
cout << "Enter data target file: ";
cin >> targetname;
if( sourcename == targetname ) {
cout << "Invalid file name: File already exists or " <<
"source file entered as target file." << endl;
}
else {
target.open( targetname, ios::in | ios::out | ios::nocreate );
if( target.is_open() ) {
cout << "File exists, are you sure you want " <<
"to overwrite the file (y/n)? ";
char choice;
cin >> choice;
if( choice == 'n' ) {
cout << "File will not be overwritten," <<
"please enter a new file name." <<
endl;
target.close();
}
else if( choice == 'y' ) {
cout << "File will be overwritten." <<
endl;
done = true;
}
}
else
done = true;
}
}
target.open( targetname, ios::in | ios::out | ios::noreplace );
// display the header and set the number of lines of the header
int header_lines = 0;
displayHeader( source, header_lines );
// display the data
displayData( source, header_lines );
getNewHeader( target );
int num_columns = getNumColumns( source );
getNewColumnTitles( target, num_columns );
transferData( source, target );
arrangeData( source, header_lines, targetname, num_columns );
source.close();
target.close();
return 0;
}
////////////////////////////////////////////////////////////////////////////////
void displayHeader( fstream &source, int &header_lines ) {
header_lines = getNumLinesHeader( source );
cout << endl;
// display the header
if( header_lines > 0 ) {
cout << "The original header:" << endl;
for( int i = 0; i < header_lines; i++ ) {
string curr_line = "";
getline( source, curr_line );
cout << curr_line << endl;
}
}
else
cout << "Original header not displayed." << endl;
cout << endl;
}
void displayData( fstream &source, const int &header_lines ) {
cout << "How many lines of data would you like to view? ";
int data_lines;
cin >> data_lines;
cout << endl;
if( data_lines > 0 ) {
string curr_line;
getline( source, curr_line );
cout << "The original data:" << endl;
for( int i = header_lines; i < header_lines + data_lines; i++ ) {
getline( source, curr_line );
cout << curr_line << endl;
}
}
else
cout << "Original data not displayed." << endl;
cout << endl;
}
int getNumLinesHeader( fstream &source ) {
source.seekg( 0 );
int lines = 0;
bool done = false;
while( !done ) {
char c;
source >> c;
if( isNotInt( c ) ) {
string temp_line;
getline( source, temp_line );
lines++;
}
else {
source.putback( c );
done = true;
}
}
source.seekg( 0 );
return lines;
}
bool isNotInt( const char &c ) {
int i = static_cast<int>( c );
if( c != '-' && c != '.' && ( i < 48 || i > 57 ) )
return true;
return false;
}
void getNewHeader( fstream &target ) {
char choice = '!';
while( choice != 'y' && choice != 'n' ) {
cout << "Would you like to include a header in the file (y/n)? ";
cin >> choice;
if( choice != 'y' && choice != 'n' )
cout << "Please enter either y or n." << endl;
}
if( choice == 'y' ) {
cout << "When you are done entering text, simply enter a blank" <<
" line." << endl;
string header_line = "!";
getline( cin, header_line );
bool done = false;
while( !done ) {
cout << "> ";
getline( cin, header_line );
if( header_line != "%" )
target << header_line << endl;
else {
target << endl;
done = true;
}
}
}
}
void getNewColumnTitles( fstream &target, const int &num_columns ) {
cout << endl;
cout << "There are " << num_columns << " columns of data." << endl;
cout << "Please enter new column titles..." << endl;
string new_header;
for( int i = 1; i < num_columns; i++ ) {
cout << "Column #" << i << ": ";
cin >> new_header;
target << new_header << " | ";
}
cout << "Column #" << num_columns << ": ";
cin >> new_header;
target << new_header << endl;
}
int getNumColumns( fstream &source ) {
getPastHeader( source );
string line;
// capture a line of data
getline( source, line );
int i = 0, columns = 1;
bool last_space = false;
while( i < static_cast<int>( line.length() ) ) {
if( line[i] == ' ' ) {
if( last_space )
line.erase( i, 1 );
else {
i++;
last_space = true;
}
}
else {
last_space = false;
i++;
}
}
if( line[0] == ' ' )
line.erase( 0, 1 );
if( line[ line.length()-1 ] == ' ' )
line.erase( line.length()-1, 1 );
// count columns
for( i = 0; i < static_cast<int>( line.length() ); i++ )
if( line[i] == ' ' )
columns++;
return columns;
}
void getPastHeader( fstream &source ) {
source.seekg( 0 );
bool done = false;
int curr_line = 0, header_lines = getNumLinesHeader( source );
string line;
while( !done ) {
getline( source, line );
curr_line++;
if( curr_line == header_lines || !source )
done = true;
}
getline( source, line );
}
void transferData( fstream &source, fstream &target ) {
cout << "data transfer";
source.seekg( 0 );
source.seekp( 0 );
target.seekg( 0 );
target.seekp( 0 );
while( !source.eof() ) {
cout << "...";
string line;
getline( source, line );
target << line << endl;
}
cout << endl;
source.seekg( 0 );
source.seekp( 0 );
target.seekg( 0 );
target.seekp( 0 );
}
///////////////////////////////////////////////////////////////////////////
void arrangeData( fstream &target, const int &header_lines,
char targetname[], int &num_columns ) {
int choice = -1;
while( choice != 3 ) {
choice = menuChoice();
if( choice != 3 ) {
fstream temp_file( "temp.dat", ios::in | ios::out );
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
///////// PROBLEM IS IN THE NEXT FUNCTION /////////
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
copyFile( target, temp_file, targetname );
if( choice == 1 )
eraseColumn( target, temp_file, num_columns );
else if( choice == 2 )
switchColumns( target, temp_file );
}
else
cout << "Exiting program..." << endl << endl;
}
}
void copyFile( fstream &target, fstream &temp_file, char targetname[] ) {
transferData( target, temp_file );
target.close();
target.open( targetname, ios::in | ios::out | ios::trunc );
}
int menuChoice() {
cout << endl << "Menu" << endl;
cout << "----------------------" << endl;
cout << "1. Erase a column." << endl;
cout << "2. Switch two columns." << endl;
cout << "3. Quit." << endl;
cout << "----------------------" << endl;
int choice = 0;
while( choice < 1 || choice > 3 ) {
cout << "> ";
cin >> choice;
if( choice < 1 || choice > 3 )
cout << "Please enter a choice 1-3." << endl;
}
return choice;
}
void eraseColumn( fstream &target, fstream &temp_file, int &num_columns ) {
cout << "***ERASE COLUMN()(***" << endl;
bool input_ok = false;
int erase_column;
while( !input_ok ) {
cout << "Please enter the column you would like to erase," <<
" or 0 to exit: ";
cin >> erase_column;
if( erase_column < 0 || erase_column > num_columns )
cout << "Please enter a valid column." << endl;
else
input_ok = true;
}
if( erase_column != 0 ) {
cout << "***GET PAST TARGET HEADER***"<<endl;
string line;
for( int i = 0; i < getNumLinesHeader( temp_file ); i++ ) {
cout << "(loop)" << endl;
getline( temp_file, line );
target << line << endl;
}
cout << "***enter big while***" << endl;
while( !temp_file.eof() ) {
getline( temp_file, line );
int i = 0, cur_col = 0;
bool last_space = true;
while( i < static_cast<int>( line.length() ) ) {
cout << "***in loop***" << endl;
if( last_space && line[i] != ' ' ) {
last_space = false;
cur_col++;
}
else if( !last_space && line[i] == ' ' )
last_space = true;
if( cur_col != erase_column ) {
char c = line[i];
target << c;
}
i++;
}
target << endl;
}
num_columns--;
}
}
-
Code:
>void transferData( fstream &source, fstream &target ) {
>cout << "data transfer";
> source.seekg( 0 );
> source.seekp( 0 );
> target.seekg( 0 );
> target.seekp( 0 );
> while( !source.eof() ) {
>cout << "...";
> string line;
> getline( source, line );
> target << line << endl;
> }
>cout << endl;
// Add source.clear() here
source.clear();
> source.seekg( 0 );
> source.seekp( 0 );
> target.seekg( 0 );
> target.seekp( 0 );
>}
-
Thanks, what does clearing an ifstream do?
-
Also, are there excessive seekg's I can remove? Thanks again! It works!
-
Clearing an ifstream clears any flags which have been set. In this case the eof flag (source.eof()) had been set when you called the function earlier, so when you called the function again, the eof flag was still set). If an error occurs during a read, it also sets a flag. Some examples of flags are: isopen(), good(), bad(), fail(), eof().
-
You should certainly be able to remove the seekg()'s at the end of transferData():
Code:
void transferData( fstream &source, fstream &target ) {
cout << "data transfer";
source.seekg( 0 );
source.seekp( 0 );
target.seekg( 0 );
target.seekp( 0 );
while( !source.eof() ) {
cout << "...";
string line;
getline( source, line );
target << line << endl;
}
cout << endl;
source.clear();
This might even work:
Code:
void transferData( fstream &source, fstream &target ) {
cout << "data transfer";
source.seekg( 0 );
target.seekp( 0 );
while( !source.eof() ) {
cout << "...";
string line;
getline( source, line );
target << line << endl;
}
cout << endl;
source.clear();