Basic File Handling - Everything correct?

Still learning and doing some basic file handling exercise and was wondering if I wrote this code correct and did I do all the error checking and if statements properly?

(project is unicode and working with chars only)


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
int main()
{

std::wofstream outFile;
outFile.open(L”savelist.txt”, std::ios::out);

if (outFile.is_open())
{
   wchar_t buffer[100];
   std::wcout << L”Please Enter Address \n”;
   std::wcin.getline(buffer, sizeof(buffer));
   
     if (outFile << buffer)
     {
       std::wcout << “File has been written \n”;
       outFile.close();
     }
     else 
     {
       std::wcout << “Write to file failed \n”;
     }

}

else
{
std::wcout << “File could not be opened \n”;
}



}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <fstream>

int main()
{
    const std::size_t N = 100 ;
    wchar_t address[N] {} ;
    std::wcout << L"enter address: " ;
    std::wcin.getline( address, N ) ; // note: N == sizeof(address) / sizeof(wchar_t)
    
    // note: constructor of wofstream would accept a const wchar_t* only if  std::filesystem::path::value_type is wchar_t 
    if( std::wofstream out_file{ "savelist.txt" } ) // if file was opened for output
    {
        if( out_file << address ) std::wcout << L"address was written into file\n" ;
        else std::wcerr << L"write to file failed\n" ;
    } // at end of scope, out_file is automagically closed

    else std::wcerr << L"failed to open file\n" ;
}
Last edited on
A couple of suggestions:

1. Post a complete code example by including headers when possible, it makes it easier for others to paste the code and try to compile it. A short, self-contained & compileable example.

http://www.sscce.org/

2. Proper formatting, indentation and restrained use of whitespace help make looking at code easier to spot minor errors and follow logical blocks of code.

One possible way to do this:
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
#include <iostream>
#include <fstream>
#include <cstdlib>

int main()
{
   const size_t size { 100 };

   std::wofstream outFile("savelist.txt");

   if (!outFile)
   {
      std::wcerr << L"File could not be opened \n";
      return EXIT_FAILURE;
   }

   wchar_t buffer[size];

   std::wcout << L"Please Enter Address \n";
   std::wcin.getline(buffer, size);

   if (outFile << buffer)
   {
      std::wcout << L"File has been written \n";
      
      // not actually needed, the file will close when the program ends
      outFile.close();  
   }
   else
   {
      std::wcerr << L"Write to file failed \n";
   }
}

Personally for something this trivial I'd use std::string instead of a C string and not use wide characters.

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

int main()
{
   std::ofstream outFile("savelist.txt");

   if (!outFile)
   {
      std::cerr << "File could not be opened\n";
      return EXIT_FAILURE;
   }

   std::string buffer;

   std::cout << "Please Enter Address\n";
   std::getline(std::cin, buffer);

   if (outFile << buffer)
   {
      std::cout << "File has been written\n";
   }
   else
   {
      std::cerr << "Write to file failed\n";
   }
}


I hold off using wide characters unless I need to use non-Latin characters.
L11
 
std::wcin.getline(buffer, sizeof(buffer));


No.

This is only correct when the size of the underlying type used by buffer is 1 byte (ie when it's char). In this case buffer has an underlying type of wchar_t (2 bytes). Hence you need:

 
std::wcin.getline(buffer, sizeof(buffer)/sizeof(buffer[0]));


Also note that you are using the 'wrong' double quotes. These need to be '"' and not '”' or '”'.

You don't need to specify ios::out when (w)ofstream is used. This assumes it's an output file and if exists will clear the file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <fstream>
#include <iostream>

int main() {
	std::wofstream outFile;

	outFile.open(L"savelist.txt");

	if (outFile.is_open()) {
		wchar_t buffer[100] {};

		std::wcout << L"Please Enter Address \n";
		std::wcin.getline(buffer, sizeof(buffer)/sizeof(buffer[0]));

		if (outFile << buffer)
			std::wcout << L"File has been written \n";
		else
			std::wcout << L"Write to file failed \n";
	} else
		std::wcout << L"File could not be opened \n";
}

Last edited on
> outFile.open(L”savelist.txt”, std::ios::out);

1
2
>>     // note: constructor of wofstream would accept a const wchar_t* only if  std::filesystem::path::value_type is wchar_t 
>>    if( std::wofstream out_file{ "savelist.txt" } ) // if file was opened for output 



>>> outFile.open(L"savelist.txt");

Quite unsurprisingly, the same holds for std::basic_ofstream<>::open()
1
2
void open( const std::filesystem::path::value_type *filename,
           ios_base::openmode mode = ios_base::out ); // (2)  


Overload (2) is only provided if std::filesystem::path::value_type is not char.
https://en.cppreference.com/w/cpp/io/basic_ofstream/open


Note: std::filesystem::path::value_type is the character type used by the native filesystem;
it is wchar_t on windows, char on unix and compatibles.
Last edited on
I am still kind of confused on this: note: constructor of wofstream would accept a const wchar_t* only if std::filesystem::path::value_type is wchar_t.

What does this really mean? My buffer array type is a wchar_t.

I had a look on MSDN which is quite intimating for me and found the constructor takes a wchar_t*. But what is std::filesystem::path::value_type?:

1
2
3
4
explicit basic_ofstream(
    const wchar_t* _Filename,
    ios_base::openmode _Mode = ios_base::out,
    int _Prot = (int)ios_base::_Openprot);




Thanks everyone!
Last edited on
> But what is std::filesystem::path::value_type?:

std::filesystem::path::value_type is the character type used by the native filesystem;
wchar_t on windows, char on unix and compatibles.


> MSDN which is quite intimating for me and found the constructor takes a wchar_t*

It does accept const wchar_t* on the microsoft (windows) implementation; but the standard does not specify it.

cppreference is correct; the signature should be:
1
2
basic_ofstream( const std::filesystem::path::value_type* filename,
                      std::ios_base::openmode mode = ios_base::out ); // (3) 

https://en.cppreference.com/w/cpp/io/basic_ofstream/basic_ofstream

On a non-windows platform (where std::filesystem::path::value_type is not wchar_t):

1
2
3
4
5
6
7
8
9
#include <iostream>
#include <fstream>

int main()
{
    // *** error *** : no matching function for call to 'std::basic_ofstream<char>::basic_ofstream(const wchar_t [9])'
    // *** error *** : no matching constructor for initialization of 'std::ofstream' 
    std::ofstream test( L"xyz" ) ;
}

http://coliru.stacked-crooked.com/a/6f2df9b8be9abc38


Also, strongly favour limiting the scope of variables (and avoiding needless verbiage).
Use if( std::wofstream out_file{ "savelist.txt" } ) {
not
1
2
3
std::wofstream outFile;
outFile.open("savelist.txt");
if (outFile.is_open()) {


Use std::vector<char> vec( str.begin(), str.end() ) ;
not
1
2
3
std::vector<char> vec ;
vec.resize( str.size() ) ;
std::copy( str.begin(), str.end(), vec.begin() ) ;
Last edited on
> My buffer array type is a wchar_t

An overload of the file stream constructor accepts std::filesystem::path for the file name.
std::filesystem::path can be constructed from a wide variety of character sequences.

This would work on all conforming C++ implementations:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <filesystem>
#include <fstream>

int main()
{
    const wchar_t file_name[] = L"savelist.txt" ;

    if( std::wofstream out_file{ std::filesystem::path(file_name) } ) // if file was opened for output
    {
         // use out_file
         out_file << L"abcd\nefgh\nijkl\n" ;
    }

    else { /* error: failed to open output file */ }
}

http://coliru.stacked-crooked.com/a/fe698c8c706f151a
Topic archived. No new replies allowed.