Open Two Files Using Same In Stream

Hello! I am working on a lab for my class, and I am having trouble with File I/O. I need to open two files, "datafile1.txt" and "datafile2.txt", and pass them to a function that will get the first line as an int variable. An example text file (datafile1.txt) is:
4
Dana Smith F
River Jones M
Jordan Pollic F
Liska Fanta M

So I pass my stream to my function, and I don't know where to go from here in terms of differentiating between the two functions. This is what I have right now and I know it's not right, but I'm not sure how to fix it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int main()  {
    // Declare variables
    dataRecord record;
    // Open files for input
    std::ifstream inFile1;
    std::ifstream inFile2;
    if(!inFile1.is_open())   {
        std::cout << "Sorry, could not open file." << std::endl;
        exit (0);
        }
    if(!inFile2.is_open())   {
        std::cout << "Sorry, could not open file." << std::endl;
        exit (0);
        }
    inFile1 = inFile1.open("datafile1.txt");
    inFile2 = inFile2.open("datafile2.txt");

    // Make function calls to get size to use in new statement to create dynamic array
    int numRecordsInFile1 = readHeader(inFile1);
    int numRecordsInFile2 = readHeader(inFile2);
    
    // Get dynamic memory
    int totalRecord = numRecordsInFile1 + numRecordsInFile2;
    record * ArrayPtr = new dataRecord[totalRecord];


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int readHeader(std::ifstream inFile)    {
    int NumRecordsInFile1 = 0;
    int NumRecordsInFile2 = 0;
    if(inFile == inFile1)    {
        inFile >> numRecordsInFile1;
        return numRecordsInFile1;
        }
    if(inFile == inFile2)    {
        inFile >> numRecordsInFile2;
        return numRecordsInFile2;
        }
    else    {
        exit(0);
        }
    }

Last edited on
Streams do not like being copied. Passing by reference is fine. Hence:
1
2
3
4
5
6
int readHeader( std::istream & in )
{
  int numRecords {};
  in >> numRecords;
  return numRecords;
}



PS. Why do you test for "open" before you do open()? That seems like an auto-fail.
How do I differentiate the numRecords between the two files though? My main problem is passing the two files since I am supposed to pass both files to the same function to return the numRecords? Does what you're saying to do do that automatically?

PS. I did that because I'm bad at programming, I will fix it. Thank you for pointing that out
Last edited on
What do you do on lines 19-20 of your program?

On each you call the function with one stream as argument and store the result in a variable.

The function reads an int from a stream. If you call it with stream foo, the function will read from stream foo. Isn't that what you want it to do?
Hello JM567,

For what you are asking you would have to do this:

In main:
1
2
3
4
int numRecordsInFile1{};
int numRecordsInFile2{};

readHeader(inFile1, inFile2,  numRecordsInFile1,  numRecordsInFile2);


And the function would be:
 
void readHeader(std::ifstream& inFile1,readHeader(std::ifstream& inFile2, int& numRecordsInFile1, int&numRecordsInFile2)

This way you have access to both of the file streams and both int variables. With the "int" variables any change in the function will be reflected back in "main".

The if statements in the function I believe will not work because "inFile1" and "inFile2" are not defined in the function and have no way of knowing what is defined outside the function, in this case what was defined in "main". And I know of know way to tell if "inFile" came from "inFile1" or "inFile2".

Since a function can only return one item passing the variables by reference is the best way to make changes to these "int" variables. There are other ways to return more than one variable, but that may be ahead of where you are.

Another option is two functions one for each file stream. This way you could return a single variable.

Looking back I realized that sometimes I go off in the wrong direction based on trying to fix what I see. keskiverto's suggestion is the simplest approach and will work fine.

Hope this is something to think about,

Andy
To: keskiverto
Yes that is. I understand now, thank you.

To: Handy Andy
I am not allowed to change my function headers, they were defined for us by the instructor when given the program.
How do I properly define inFile1 and inFile2? I understand the pass by reference but I get an error in the declaration lines 15 and 16
http://www.cplusplus.com/reference/fstream/ifstream/ifstream/
http://www.cplusplus.com/reference/fstream/ifstream/open/

You either declare and open:
1
2
std::ifstream foo;
foo.open( "bar" );
or open in the declaration:
std::ifstream foo( "bar" );
How do I differentiate the numRecords between the two files though?

I think you misunderstand how parameters and local variables inside of functions work.

Each time you call a function, it creates a new set of local variables and parameters. When the function returns, that set is destroyed. So here is keskiverto's function:
1
2
3
4
5
6
int readHeader( std::istream & in )
{
  int numRecords {};
  in >> numRecords;
  return numRecords;
}

When you call it with int numRecordsInFile1 = readHeader(inFile1);:
- The parameter in gets created and becomes a synonym for inFile1
- The function creates numRecords, reads from in into numRecords, and returns numRecords.
- That return value gets copied to numRecordsInFile1.

Next, when you call it with int numRecordsInFile2 = readHeader(inFile2);:
- The parameter in gets created and becomes a synonym for inFile2
- The function creates numRecords, reads from in into numRecords, and returns numRecords. Note that this numRecords variable is a completely new one, unrelated to the numRecords variable from the previous call.
The new return value gets copied to numRecordsInFile2.

Hello JM567,

How do I properly define inFile1 and inFile2?
"inFile1" and "infile2" are already defined on lines 5 and 6. Lines 15 and 16 only need to open the file streams. The "inFile1 = " is not needed. The same for line 16.

Your original post was lacking some important information, so I guessed for now.

With everything that has been said and using keskiverto's suggestion this is what I have come up with:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
#include <string>
#include <fstream>
#include <chrono>
#include <thread>

struct dataRecord
{
	std::string s_fName;
	std::string s_lName;
	std::string s_mI;
};

// Proto Types
int readHeader(std::ifstream& inFile);

int main()
{
	// Declare variables
	int numRecordsInFile1{};
	int numRecordsInFile2{};
	int totalRecord{};

	dataRecord record;

	// Open files for input
	std::ifstream inFile1;
	std::ifstream inFile2;

	inFile1.open("datafile1.txt");  // <--- Moved open here so the if statements would work.
	inFile2.open("datafile2.txt");

	if (!inFile1.is_open())
	{
		std::cout << "Sorry, could not open file." << std::endl;
		// <--- Added next line or you may not be able to see the message.
		std::this_thread::sleep_for(std::chrono::seconds(3));  // Requires header files "chrono" and "thread"
		exit(0);
	}
	if (!inFile2.is_open())
	{
		std::cout << "Sorry, could not open file." << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(3));  // Requires header files "chrono" and "thread"
		exit(0);
	}

	// Make function calls to get size to use in new statement to create dynamic array
	numRecordsInFile1 = readHeader(inFile1);
	numRecordsInFile2 = readHeader(inFile2);

	// Get dynamic memory
	totalRecord = numRecordsInFile1 + numRecordsInFile2;

	dataRecord* ArrayPtr = new dataRecord[totalRecord];  // <---Changed. Needs the name of the struct not the variable name.
	
	// <--- Added. Used for testing.
	std::cout << "\n Number of records in file1 = " << numRecordsInFile1 << "\n Number of records in file2 = " << numRecordsInFile2 << std::endl;

	// The next line may not be needed. If you have to press enter to see the prompt it is not needed.
	//std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
	std::cout << "\n\n Press Enter to continue";
	std::cin.get();

	delete[] ArrayPtr;  // <--- need to delete what you created.

	return 0;
}


int readHeader(std::ifstream& inFile)  // <--- Works with one file stream only.
{
	int NumRecordsInFile{};

	inFile >> NumRecordsInFile;

	return NumRecordsInFile;
}


In the above code I had to guess at the header files you might have used plus the others I added for code I added.

I do not know if you used a class or a struct, so I used a struck for now The variables are just a guess for now.

The section for "Proto Types" is needed when the function follows "main". If the function was before "main" this section would not be needed.

It may be my preference, but I like to put the variable definitions at the beginning of a function so I know where they are. Defining variables just before they are needed can make them hard to find.

You will see that I moved the open statements before the if statements that check to see if they are open. This allows the if statements to have something to check. I also corrected the open statements to the way they should be used.

As explained by dhayden lines 48 and 49 each call the function which returns the number of records in the file. In the future I would write a function that reads these files that gets the information.

Line 54 is the proper way to do this. The comments explains why.

Lines 57 to 66 I added. You may not need all of this and line 57 can be commented out when finished using it.

It would be helpful to have the full code so everyone can be working with the same information. The same is true for the data files.

Hope that helps,

Andy
Topic archived. No new replies allowed.