C++17 <filesystem> Doesn't output what I expect?

I'm following this tutorial:
https://www.bfilipek.com/2017/08/cpp17-details-filesystem.html

I'm using Visual Studio 2019 and C++17.

The tutorial's code uses:
1
2
3
4
5
6
7
8
9
10
11
namespace fs = std::experimental::filesystem;

fs::path pathToShow(/* ... */);
cout << "exists() = " << fs::exists(pathToShow) << "\n"
     << "root_name() = " << pathToShow.root_name() << "\n"
     << "root_path() = " << pathToShow.root_path() << "\n"
     << "relative_path() = " << pathToShow.relative_path() << "\n"
     << "parent_path() = " << pathToShow.parent_path() << "\n"
     << "filename() = " << pathToShow.filename() << "\n"
     << "stem() = " << pathToShow.stem() << "\n"
     << "extension() = " << pathToShow.extension() << "\n";

exists() = 1
root_name() = C:
root_path() = C:\
relative_path() = Windows\system.ini
parent_path() = C:\Windows
filename() = system.ini
stem() = system
extension() = .ini


My Code:
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
#include <iostream>
#include <iostream>
#include <string>
#include <filesystem>

namespace fs = std::filesystem;


void openRecipes(std::string ver) {

	// Determines proper file path
	std::string fullPath = "recipes/" + ver + '/';
	fs::path pathToShow(fullPath);
	std::cout << "exists() = " << fs::exists(pathToShow) << "\n"
		<< "root_name() = " << pathToShow.root_name() << "\n"
		<< "root_path() = " << pathToShow.root_path() << "\n"
		<< "relative_path() = " << pathToShow.relative_path() << "\n"
		<< "parent_path() = " << pathToShow.parent_path() << "\n"
		<< "filename() = " << pathToShow.filename() << "\n"
		<< "stem() = " << pathToShow.stem() << "\n"
		<< "extension() = " << pathToShow.extension() << "\n";
}


int main() {
	std::string version = "1.13";
	openRecipes(version);

	std::cin.get();
	return 0;
}

exists() = 1
root_name() = ""
root_path() = ""
relative_path() = "recipes/1.13/"
parent_path() = "recipes/1.13"
filename() = ""
stem() = ""
extension() = ""


I don't understand why my output doesn't include everything the tutorial's output does.

Here's what the file system looks like (for the file path stated):
https://gyazo.com/1c725a763b3682a343415b2e8e84ee6f

Help would be greatly appreciated. Thank you!
Last edited on
I cannot test this myself, but,
https://en.cppreference.com/w/cpp/filesystem/path/root_name
https://en.cppreference.com/w/cpp/filesystem/path/root_path
https://en.cppreference.com/w/cpp/filesystem/path/path
root_name wrote:
If the path (in generic format) does not include root name, returns path().

path() meaning the default constructor for a path object, which is an empty path. So it's conforming to the documentation, since your fullPath variable does not include the root name.

It looks like the tutorial's example of C:/temp uses an absolute path, and therefore it "includes the root name", so it is able to print C: as the root name.

I think the reasoning here is that, given a relative path "foo/bar", it has no idea if you're referring to C:/foo/bar, D:/foo/bar, or some other combination of subfolders.
Last edited on
Ganado wrote:
I cannot test this myself, but,
https://en.cppreference.com/w/cpp/filesystem/path/root_name
https://en.cppreference.com/w/cpp/filesystem/path/root_path
https://en.cppreference.com/w/cpp/filesystem/path/path
root_name wrote:
If the path (in generic format) does not include root name, returns path().

path() meaning the default constructor for a path object, which is an empty path. So it's conforming to the documentation, since your fullPath variable does not include the root name.

It looks like the tutorial's example of C:/temp uses an absolute path, and therefore it "includes the root name", so it is able to print C: as the root name.

I think the reasoning here is that, given a relative path "foo/bar", it has no idea if you're referring to C:/foo/bar, D:/foo/bar, or some other combination of subfolders.

Thank you for the fast reply! You were correct. Also your explanation makes total sense!

Also I tried using current_path() but had an issue:
std::cout << "current_path() = " << fs::current_path() << '\n';
current_path() = "C:\\Users\\Tom\\Desktop\\filesystem_test\\cpp17\\cpp17"

Any idea why there are two slashes each..? And how to make it correct?
https://en.cppreference.com/w/cpp/filesystem/current_path

Looking forward to your response, thanks!

Edit: It mentions the double slash on this page: https://en.cppreference.com/w/cpp/filesystem/path/path but appears to have outdated or wrong code. It shows an example of source code then it's output but when I actually run the code (on their site) it does not give the output they said in the post. You can see the example I'm referring to at the very bottom of the page (of link provided).

My latest output:
exists() = 1
root_name() = "C:"
root_path() = "C:/"
relative_path() = "Users/Tom/Desktop/filesystem_test/cpp17/cpp17/recipes/1.13/acacia_boat.json"
parent_path() = "C:/Users/Tom/Desktop/filesystem_test/cpp17/cpp17/recipes/1.13"
filename() = "acacia_boat.json"
stem() = "acacia_boat"
extension() = ".json"
current_path() = "C:\\Users\\Tom\\Desktop\\filesystem_test\\cpp17\\cpp17"

C:\Users\Tom\Desktop\filesystem_test\cpp17\Debug\cpp17.exe (process 18008) exited with code 0.
Last edited on
The current_path() output looks like:
C:\\Users\\Tom\\Desktop\\filesystem_test\\cpp17\\cpp17


Even though it should look like: (I think)
C:/Users/Tom/Desktop/filesystem_test/cpp17/cpp17


I tried fixing the current_path() output like so:
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 <string>
#include <filesystem>

namespace fs = std::filesystem;

int main() {
	std::string version = "1_13";

	// Sets file path
	fs::path filePath(fs::current_path() /= version);
	// Should replace all \'s with / in the path:
	for (char c : filePath) {
		if (c == "\\") {
			c = '/';
		}
	}
	std::cout << filePath;

	/*
	// ------------- Also, this doesn't work and I can't figure out why. --------------
	// Will iterate through every file in the directory of the path stated and print the file names.
	for (const auto& entry : fs::directory_iterator(filePath)) {
		std::cout << entry.path() << std::endl;
	}
	*/

	return 0;
}

Errors: https://gyazo.com/1f877cba44c8ed98c67aaec5c64295f4
^ Does not include the commented out part of code.

How can I fix this? My end goal is to able to use current_path() /= version to access a directory of files. And I'm using current_path() so if I shared the program with other people, they could use it on their own computer without having to modify the path.
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <filesystem>
#include <string>
#include <iomanip>

int main()
{
    const std::experimental::filesystem::path p = "C:\\Users\\Tom\\Desktop\\filesystem_test\\cpp17\\cpp17" ;
    
    std::wcout << p << '\n' // C:\Users\Tom\Desktop\filesystem_test\cpp17\cpp17
               << std::quoted( p.wstring() ) << L"\n\n" // "C:\\Users\\Tom\\Desktop\\filesystem_test\\cpp17\\cpp17"
                   
               << p.native() << '\n' // C:\Users\Tom\Desktop\filesystem_test\cpp17\cpp17
               << std::quoted( p.native() ) << L"\n\n" // "C:\\Users\\Tom\\Desktop\\filesystem_test\\cpp17\\cpp17"

               << p.generic_wstring() << '\n' // C:/Users/Tom/Desktop/filesystem_test/cpp17/cpp17
               << std::quoted( p.generic_wstring() ) << '\n' ; // "C:/Users/Tom/Desktop/filesystem_test/cpp17/cpp17"
}

https://rextester.com/VIERD30077
JLBorges wrote:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <filesystem>
#include <string>
#include <iomanip>

int main()
{
    const std::experimental::filesystem::path p = "C:\\Users\\Tom\\Desktop\\filesystem_test\\cpp17\\cpp17" ;
    
    std::wcout << p << '\n' // C:\Users\Tom\Desktop\filesystem_test\cpp17\cpp17
               << std::quoted( p.wstring() ) << L"\n\n" // "C:\\Users\\Tom\\Desktop\\filesystem_test\\cpp17\\cpp17"
                   
               << p.native() << '\n' // C:\Users\Tom\Desktop\filesystem_test\cpp17\cpp17
               << std::quoted( p.native() ) << L"\n\n" // "C:\\Users\\Tom\\Desktop\\filesystem_test\\cpp17\\cpp17"

               << p.generic_wstring() << '\n' // C:/Users/Tom/Desktop/filesystem_test/cpp17/cpp17
               << std::quoted( p.generic_wstring() ) << '\n' ; // "C:/Users/Tom/Desktop/filesystem_test/cpp17/cpp17"
}
https://rextester.com/VIERD30077


Thank you, that was very helpful!

Edit: Why did you use std::wcout instead of std::cout? I read that I should only be using one or the other in my program:
"A program should not mix output operations on wcout with output operations on cout (or with other narrow-oriented output operations on stdout): Once an output operation has been performed on either, the standard output stream acquires an orientation (either narrow or wide) that can only be safely changed by calling freopen on stdout."
- http://www.cplusplus.com/reference/iostream/wcout/

I also read wcout supports Unicode I think(?) but why would I need unicode?

My program uses std::cout elsewhere so I need to use std::cout I think for this.

Also I see that you use: L"\n\n" and I'm not sure what that does or if it's possible to use with std::cout.
---------------------------------
To be clear, I tried adding your provided code to my program just to see how it works when using current_path(). And it gave this error in Visual Studio:
https://gyazo.com/043872eb06522129355cd405a6a26100

Code for this file:
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 <iostream>
#include <string>
#include <fstream>
#include <filesystem>

namespace fs = std::filesystem;


void openRecipes(std::string &ver) {
    std::ifstream iFile;

    // Determines proper file path
	//std::string fullPath = "C:/Users/Tom/Desktop/filesystem_test/cpp17/cpp17/recipes/" + ver + '/';
	//std::string pathContents = "../recipes/" + ver + '/';
    //fs::path pathVar(fullPath);
	//for (const auto &entry : fs::directory_iterator(pathVar)) {
	//    std::cout << entry.path() << std::endl;

	// Sets file path
	fs::path filePath(fs::current_path() /= ver + '/');

	std::wcout << filePath << "\n"
		<< std::quoted(filePath.wstring()) << L"\n\n"

		<< filePath.native() << "\n"
		<< std::quoted(filePath.native()) << L"\n\n"

		<< filePath.generic_wstring() << "\n"
		<< std::quoted(filePath.generic_wstring()) << '\n';
}

Last edited on
> Why did you use std::wcout instead of std::cout?

On Windows, the character type used for the native (internal) encoding of file system paths is wchar_t;
the strings returned by the string() and generic_string() members are utf-8 encoded strings (converted from the native wide character encoding).
It is easier to use std::wcout with those; some extra work is required to make the windows console accept utf-8 encoded strings.

This snippet uses std::cout to print std:strings containing the representation of the path in various formats:

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
#include <iostream>
#include <filesystem>
#include <string>
#include <iomanip>
#include <codecvt>
#include <cstdio>
#include <Windows.h>

// convert std::wstring to a utf-8 encoded std::string
std::string to_utf8( const std::wstring& wstr )
{
	// note: though std::wstring_convert is deprecated, it is unlikely to be removed 
	static std::wstring_convert< std::codecvt_utf8<wchar_t> > myconv;
	return myconv.to_bytes(wstr);
}

int main()
{
	// Set console code page to utf-8 and enable buffering on stdout
	::SetConsoleOutputCP(CP_UTF8);
	std::setvbuf( stdout, nullptr, _IOFBF,  1000 );	
	
	const std::experimental::filesystem::path p = "C:\\Users\\Tom\\Desktop\\filesystem_test\\cpp17\\cpp17";

	std::cout << p << '\n' // C:\Users\Tom\Desktop\filesystem_test\cpp17\cpp17
		<< std::quoted( p.string() ) << "\n\n" // "C:\\Users\\Tom\\Desktop\\filesystem_test\\cpp17\\cpp17"

		// note: on windows, the char_type of the native format is wchar_t (utf-16) 
		<< to_utf8( p.native() ) << '\n' // C:\Users\Tom\Desktop\filesystem_test\cpp17\cpp17
		<< std::quoted( to_utf8( p.native() ) ) << "\n\n" // "C:\\Users\\Tom\\Desktop\\filesystem_test\\cpp17\\cpp17"

		<< p.generic_string() << '\n' // C:/Users/Tom/Desktop/filesystem_test/cpp17/cpp17
		<< std::quoted(p.generic_string()) << '\n'; // "C:/Users/Tom/Desktop/filesystem_test/cpp17/cpp17"
}

https://rextester.com/FXEX16287



> Also I see that you use: L"\n\n"

The L prefix specifies that it is a wide character string literal (array of wchar_t )
JLBorges wrote:
> Why did you use std::wcout instead of std::cout?

On Windows, the character type used for the native (internal) encoding of file system paths is wchar_t;
the strings returned by the string() and generic_string() members are utf-8 encoded strings (converted from the native wide character encoding).
It is easier to use std::wcout with those; some extra work is required to make the windows console accept utf-8 encoded strings.

This snippet uses std::cout to print std:strings containing the representation of the path in various formats:
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
#include <iostream>
#include <filesystem>
#include <string>
#include <iomanip>
#include <codecvt>
#include <cstdio>
#include <Windows.h>

// convert std::wstring to a utf-8 encoded std::string
std::string to_utf8( const std::wstring& wstr )
{
	// note: though std::wstring_convert is deprecated, it is unlikely to be removed 
	static std::wstring_convert< std::codecvt_utf8<wchar_t> > myconv;
	return myconv.to_bytes(wstr);
}

int main()
{
	// Set console code page to utf-8 and enable buffering on stdout
	::SetConsoleOutputCP(CP_UTF8);
	std::setvbuf( stdout, nullptr, _IOFBF,  1000 );	
	
	const std::experimental::filesystem::path p = "C:\\Users\\Tom\\Desktop\\filesystem_test\\cpp17\\cpp17";

	std::cout << p << '\n' // C:\Users\Tom\Desktop\filesystem_test\cpp17\cpp17
		<< std::quoted( p.string() ) << "\n\n" // "C:\\Users\\Tom\\Desktop\\filesystem_test\\cpp17\\cpp17"

		// note: on windows, the char_type of the native format is wchar_t (utf-16) 
		<< to_utf8( p.native() ) << '\n' // C:\Users\Tom\Desktop\filesystem_test\cpp17\cpp17
		<< std::quoted( to_utf8( p.native() ) ) << "\n\n" // "C:\\Users\\Tom\\Desktop\\filesystem_test\\cpp17\\cpp17"

		<< p.generic_string() << '\n' // C:/Users/Tom/Desktop/filesystem_test/cpp17/cpp17
		<< std::quoted(p.generic_string()) << '\n'; // "C:/Users/Tom/Desktop/filesystem_test/cpp17/cpp17"
}


https://rextester.com/FXEX16287



> Also I see that you use: L"\n\n"

The L prefix specifies that it is a wide character string literal (array of wchar_t )

I'm so sorry for the late reply. I thought I responded, but maybe I forgot to click Submit or something. I don't recall what I meant to respond with but in short:
Thank you for responding! And I've learned how to use filesystem as desired. :)

I will mark this as solved. Please Note: I probably won't check this again.
Topic archived. No new replies allowed.