Save to file with vector (dynamically)

I have created a programme that does calculations and generates results from those calculations.

The imformation generated is stored in variables for later display. Everything works well when it is displayed to screen and when sent to a file for saving.

Part of the information required is generated dynamically from a vector. The reason is that the number of items vary depending on the requirements to be calculated. As a result I don't have a way of storing other that the vector. There is no difficulty with the display to screen but it does not go to the file because the information is no longer available.

I created a copy of the display function dedicated to saving to file.

When I try to save the information to file with the new function, the file is created but is empty when I include the following code (which is the same as in the original function to screen) :

1
2
3
4
5
6
7
8
 int i =0;
 int count = 1;
          
 for( i = 0; i < fileOut.size()-1; i++)
 {                
     cout << "("	 << count <<  ") = " << fileOut[i] << "    feet" << endl; 
     count = count + 1;				
 }


Please note: fileOut is the vector.

I would be grateful if anyone could assist in finding a solution.
> When I try to save the information to file with the new function, the file is created but is empty
> when I include the following code (which is the same as in the original function to screen) :

You're still outputting to the screen.

Replace the cout with your opened file object.
information that does not change should be avoided if possible. For example, if you have 50,000 lines of text that all look like (x) feet, then you need to know if the file is meant to be read by humans or imported into something like excel where this information is useful. If the only thing that ever reads your file will be your own program, then you can save the 6 bytes per line which is a lot of space... and not just the wasted space, but now your reader needs to either parse the data and do something with it or discard it, extra logic...
Last edited on
I do not know (nor really care) what C++ standard you are building your source to or your compiler....

C++17 added the <filesystem> library that can make dealing with files much easier.

C++20 added the <format> library, making it easier to format data to be displayed to the console/written to a file.

When opening files it is best to check the file actually opened before reading/writing data. Trying to read data from a file that didn't properly open is gonna cause problems.

There are newer and safer ways to do for loops that reduce the possibility of accessing your container's elements going out of bounds.

While this particular problem is easily identifiable, sending your output to the console instead of a file, giving us a self-contained and compilable example makes it easier for us to help you.

The following example doesn't use <filesystem>, requires C++20 or later:
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
#include <fstream>
#include <iostream>
#include <vector>
#include <format>

int main( )
{
   std::vector v { 1.2, 2.3, 4.5, 5.6, 7.8, 9.0 };

   std::ofstream myFile;
   myFile.open( "DataFile.txt", std::ios_base::out );

   if ( myFile.is_open( ) )
   {
      std::cout << "File open successful\n";

      for ( size_t count { }; const auto&  itr: v )
      {
         // duplicate the output to the console and the file to see what it looks like.
         // easier to format the output that way.  Remove the std::cout when
         // no longer needed.
         std::cout << std::format( "({:>10} ) {:.3f} feet\n", count, itr );
         myFile << std::format( "({:>10} ) {:.3f} feet\n", count, itr );
         count++;
      }
      std::cout << '\n';

      std::cout << "Finished writing to file, will close now\n";
      myFile.close( );
   }
   else { std::cerr << "Unable to open file, exiting!\n"; }
}

File open successful
(         0 ) 1.200 feet
(         1 ) 2.300 feet
(         2 ) 4.500 feet
(         3 ) 5.600 feet
(         4 ) 7.800 feet
(         5 ) 9.000 feet

Finished writing to file, will close now


An example using <filesystem>, creating a sub-directory and a file for output:
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
#include <filesystem>
#include <fstream>
#include <iostream>

// for simplicity
using namespace std::filesystem;

int main( )
{
   // Define the path to create directory
   path directorypath = "mydirectory";

   // To check if the directory exist or not, create it if
   // doesn't exist
   if ( !exists( directorypath ) )
   {
      create_directory( directorypath );
      std::cout << "Directory created: " << directorypath << '\n';
   }

   // Define the file path within the directory and
   // combining the directory
   path filepath = directorypath / "myFile.txt";

   // Create and open the file for writing using
   // std::ofstream
   std::ofstream file( filepath );
   if ( file.is_open( ) )
   {
      // Write data to the file
      file << "Hello, FileSystem!";
      file.close( );
      std::cout << "File created: " << filepath << '\n';
   }
   else
   {
      // Handle the case if any error occurred
      std::cerr << "Failed to create file: " << filepath << '\n';
   }
}

Checking the open status of a file for reading is super-critical.
Pleasee accept my sincerest appology for my delayed response. Here is the save function that I have been using. As I indicated before, it works very well except when the vector code is included.(I am using C++ 11)

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
void saveFile(ostream& strm)   
{
    string my_string;
    string filename;
    filename = "string";
    char txt;
    cout << "\n";
    cout << "Enter file name: ";
    cin >> my_string;
    cout << "\n";
    filename = my_string+'.'+"txt";
    ofstream file(filename.c_str());
  
    cout << "File " << filename << " is opened \n\n";
    
    if(!file)
    {
   	    cout << "Cannot open " <<filename<< " file. \n ";
	    return; 
    }   
       
    auto del = [&](streambuf* p){strm.rdbuf(p);};
    unique_ptr<streambuf, decltype(del)> origBuffer(strm.rdbuf(), del);   
	 
    strm.rdbuf(file.rdbuf());
     
    if(file.is_open())
    {
    	cout << "This works\n";
    	
        printOut();
		              
    } 	   
       
    if(filename.size() == 0)
    {   
        cout << "\nFile " <<filename << " is empty \n";
        return ; 
    }
   
    file.clear();
   
    file.close();  
    
 system("pause");
 return;	
}


I have not beenable to make progress from the suggestions provided.
> auto del = [&](streambuf* p){strm.rdbuf(p);};
> unique_ptr<streambuf, decltype(del)> origBuffer(strm.rdbuf(), del);
I would suggest stop trying to be overly clever with low level buffer hackery and do the job in the obvious simple way.

A vector is a composite object. You can't just write it all out as a blob and hope to read it all back in again later as a blob.


A vector is a composite object. You can't just write it all out as a blob and hope to read it all back in again later as a blob.


yes, 'but' ... if you were doing a binary file it can absolutely be treated as a blob. The internal data is ensured to be stored like a C array, in one solid blob of bytes, and you can chuck that to the disk or network and rebuild it on the other side. You only need 1 extra piece of data... the number of records you wrote out ... and you can make a new vector from the blob. Gets ugly if the vector's type isn't friendly to direct writing, but you would have designed it not to be if doing this kind of read/write.

"text" files, ... exactly what you said. I wonder if the OP saw code online for a binary file and did not realize...

baby steps. just loop over the vector and write each record to the file as you would for cout. Get that working. You can get weird with it later once you understand that simple approach.
Last edited on
Coubarrie wrote:
1
2
3
4
5
6
7
int i = 0;
int count = 1;
for( i = 0; i < fileOut.size()-1; i++)
{                
  // Do something with fileOut[i]
  count = count + 1;				
}

Unrelated to the writing:
* Why is the counter i declared outside of the loop?
* What is the purpose of the count variable?
* Why the last element of the vector is not used?
This is some simple C++11 code to write a vector of numbers to a file and then to read and display them.

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
#include <vector>
#include <iostream>
#include <fstream>

int main() {
	const std::vector<int> v1 {1, 3, 5, 7};
	std::ofstream ofs("vf.txt");

	if (!ofs.is_open())
		return (std::cout << "Cannot open output file\n"), 1;

	for (size_t i = 0; i < v1.size(); ++i)
		ofs << v1[i] << ' ';

	ofs.close();

	std::vector<int> v2;
	std::ifstream ifs("vf.txt");

	if (!ifs.is_open())
		return (std::cout << "Cannot open input file\n"), 2;

	for (int i; ifs >> i;)
		v2.push_back(i);

	for (size_t i = 0; i < v2.size(); ++i)
		std::cout << v2[i] << ' ';

	std::cout << '\n';
}

@Keskiverto- response to your questions:-

"* Why is the counter i declared outside of the loop?".
Are you suggesting that the counter is misplaced and is affecting the execution of the code ? ( Please note the compiler does not indicate an objection)

"* What is the purpose of the count variable?".
See line six(6) of my initial presentation in the first item of the conversation. This corrsponds to line five(5) of your comment.

"* Why the last element of the vector is not used?".
Vectors are still begining indexing with 0, even in C++ 11.
Last edited on
@salem c- "I would suggest stop trying to be overly clever with low level buffer hackery and do the job in the obvious simple way.".

Please forgive me if I choose to conform the Standard Library for C++ 11.

By the way I am using the DEV C++ IDE
Last edited on
i outside the loop is not a c++ error. It is a questionable programming structure but perfectly legal. Problems with it include:

performance: keeping i around, the compiler must make actual space for it on the stack and so forth. If its just a loop counter, it may be stuffed into a register and discarded without that extra storage space and time to babysit the space (cache, value updating, etc all become enabled once it 'exists' beyond a register).

bugs: you may forget to reinitialize it when you reuse it later or you may forget what its last value was when it is wearing multiple hats as a temporary.

confusion: its just not done this way without a reason (persistent value needed after loop exits). So if you did it, the reader of your code wants to know why.

soft standard violations: it violates the concept of keeping things scoped only as wide as necessary, which probably has a book name that I have forgotten but it generally seen as an OOP design principle that should also be in play outside of OOP.

but, again, its not WRONG from the compiler's standpoint and it won't cause problems if you don't screw it up. Its just a red flag because its EASY to screw it up in larger programs.

------------------


count is redundant in the first posing because i is directly related to count (its off by 1, so just add 1 to i for the value to print it etc). If you need it in a variable, fine, but you may not need to actually have it because of i being available. In bigger programs, having a distinct count variable is possibly cleaner, depending on the actual code. This would be vector.size() or something else instead of a hands-on counter in cases where you use a vector/container. In your snippet, its inefficient, but its otherwise clean and reasonable.

The problem here is... zenny. If I tell you to not use count, and you start shaving the code down to be less wasteful, that quickly becomes confusing and hard to read. If I tell you its fine, that it makes it easier to follow, you may start using excessive numbers of variables and bloat that make it hard to read and follow due to bulk. There is a happy medium, and you have to find this yourself -- it can't be taught.

------------------------------
Vectors are still begining indexing with 0, even in C++ 11.

there are times when you want to shift so that you access from 1-n, but most of the time this is a beginner's attempt to move the c++ language back to something more familiar. If you have a reason to count from 1-n, do so. If you do not, then use 0 .. n-1 which is what you are expected to do in C or C++ and derived languages. And if you don't use the last location, allocate n-1 slots and don't create that unused spot unless your algorithm depends upon it for something (you can use it as a sentinel or roll up (eg sum of the whole vector) storage slot for some algorithms/reasons). Any sort of unused space is 'bad' in a minor sense (on a full computer). Some small computers (embedded systems) have such limited memory that consistently wasting it on unused items is a big deal. Modern full systems, you can waste an awful lot before it matters, but in large programs, it does matter and is a BIG DEAL to fix when you have half a gig spread over a float here, an int there, ... all over the program.
Last edited on
Registered users can post here. Sign in or register to post.