C++ Learning my way through fstream, but stuck

A little quick background for reference:
I’ve been slow to learn C++ and decided a personal project was what I needed to get me excited about it again. Long story short I got a mean little SBC (Odroid XU4) to turn into a Linux carputer project, one thing led to another and I started writing a simple C++ chatbot .
(I’m of the Knight Rider Generation)

So what I want to do is fully scripted, and this first version works to this point. I have it taking user input to a string and comparing that string to file names. Next I’ll have it read a random response from the file with the name that matches the input string.

The problem is I cannot get it to compare the string to a file in another directory, I want to put the response files in a directory in the working directory called /knowit and then I can make a directory later called /idk for the bot to create blank files for each unrecognized user response so I can fill them out and build the bot’s responses.

I’ve tried for hours and can’t figure it out, so I’m posting it as comparing files in the working directory so you can see where I’m at now. I('m starting to think it’s not possible using fstream.
Hopefully somebody here can be a hero and show me a method of comparing the string against file names in another directory, lol. Here’s the code, BotBrain.cpp.

/*
BotBrain1 needs to do the following:
1 Take input as string -done
2 Compare input string to file names in /knowit directory
3 if found open file and read one line at random
4 If not found compare input string to file names in /idk directory
5 If not found create file with that string as a name in /idk

*/

#include
#include
#include
using namespace std;

std::string input;

int main(){

// Opening statement:
std::cout << “Hello there!\n”;
// Type bye to exit
while (input != “bye”){

// Take user input and save as string
	std::getline (std::cin, input);
// End input string code

//	Begin compare input to file names
	std::ifstream inputFile;
	int value;
	//open file
	inputFile.open(input.c_str());
	// check for success finding and opening opening (need to work on closing file after done with it)
	if(inputFile.fail())
	{
		if(input != "bye"){
		cout << "We've never talked about that before.\n";
		}
	}
	else{
	std::cout << "I've heard of that!\n";
	
	}
// end compare input for file name

}
}

You can’t get it to compare a filename to a string or you can’t open a specific file? If you narrow down the problem to a specific operation there will be less possibilities to consider and easier to search for answers, having defined what you want to know.

If the problem is with opening files, and you’re able to open files in your current directory then you are probably not specifying the path correctly… right? That hints to two things to look into. How is that directory specified, or alternatively, how can the current directory be changed?

You could for example ask another program to do the same thing. How would you ask touch to create/update that file?

I thought touch wss slower than this method, being that it’s doing it with every input from the user this approach made more sense to me.
I did try specifying the path a bunch of different ways to no avail, what I’d really like to find is a good instruction on fstream but none I’ve found discuss looking inside a directory, only creating and reading files in another directory with ofstream and ifstream.

What I’m saying about touch is that you would use that to test whether you’re even specifying the correct directory. You could use any program that opens a file in an observable way, touch being the one that came to mind since it does so in a minimal way.

You’ve already shown that you can use ifstream, whether it’s used in the current directory or another one is not a significant difference. So…no, that’s not what you would look at. What you would look at is whether you’re specifying the right location.

And that you say that you tried a bunch of stuff supports that you are probably trying the wrong things, otherwise you wouldn’t be trying a bunch of stuff, you’d use a correct path, that would be the only thing to try wouldn’t it? But you can use touch from your current directory as a means to test whether you’re specifying the file you meant to specify.
Or something like cat, if there’s content in the file, which would make it print out, probably easier than checking whether touch had an effect.

#include <fstream>

int main() {
    std::ofstream out("/tmp/blahhhh");
    out << "hello\n";
}
$ g++ -std=c++17 -Wall a.cpp && ./a.out
$ cat /tmp/blahhhh
hello

Which shows that opening a file in another directory is not an issue.
Also note that I’m specifying the file the same way to ofstream as to cat.

Thank you for the input it’s truly appreciated, but I tried specifying the path every which way before resorting to asking for direction.
The issue was never opening a file in a different directory, I have done that, it’s comparing a string variable to file names in a different directory.
I’m going to cut my losses and start over with a different method as I’m thoroughly convinced specifying the path doesn’t work with the method I posted.

…which you’re doing by opening the file, except, it’s failing, so

that is the issue

worked fine in the program I posted above, and I imagine that program runs successfully on your end as well. that program is doing the thing that you’re saying you’re not able to do.

the one path you have mentioned is /knowit which, if you touch it, will likely give you permission denied since / isn’t a location where you can create things without elevated privilege, more likely you’d want a path like /home/myusername/somewhere or something relative to your current location which ifstream might or miight not support and if not you’d create an absolute path based on your current location, but for testing there’s nothing stopping you from hard-coding that

it makes no difference if it’s in the same directory or not. it’s just a different name.
if the only thing you’re changing is the name then … you’re probably getting the name wrong.

Hmmm, I tried specifying the absolute path and that does not do what I want, but it does change something

std::ifstream file("");
where I started uses the working directory

std::ifstream file("/home/tom/Desktop/Odroid/bots/experiment/knowit/""");
std::ifstream file("/home/tom/Desktop/Odroid/bots/experiment/knowit");
std::ifstream file("/home/tom/Desktop/Odroid/bots/experiment/knowit/");
find nothing in /knowit and also now the working directory

This is peculiar…

/*
readtest.cpp needs to do the following:
1 Take input as string -done
2 Compare input string to folder names in a directory
3 If not found create folder with that string as a nanme in a different directory
4 if found open directory and read one line at random
*/

#include
#include
#include
using namespace std;

std::string input;

int main(){

// Opening statement:
std::cout << “Hello there!\n”;

// Type “bye” to exit
while (input != “bye”){
// Take input from user and save as string named input
std::getline (std::cin, input);
// End input string code

//	Begin compare input to file names
	//open file
	std::ifstream file("");

	file.open(input.c_str());
	// check for success finding and opening opening (need to work on closing file after done with it)
	if(file.fail())
	{
	// Temporary confirmation responses to be omitted later
		if(input != "bye"){
		cout << "We've never talked about that before.\n";
		}
	}
	else{
	std::cout << "I've heard of that!\n";
	
	}
// end compare input for file name

}
}

If this is a directory
/home/tom/Desktop/Odroid/bots/experiment/knowit

Then none of those are valid paths for a file

they’re all the same path, the first and third strings are identical, the second is the same thing without the trailing slash

to refer to a file in that directory, you would add a basename (what you would consider the name of the file itself) after a separating slash

a relative path is should be fine too - if you can use a path for other commands, like cat or touch or for that matter a text editor, then you can probably use that same path in your program as well.

Here’s a program that recursively lists files from current working directory, and checks whether they exist. Note that the path is stored in a string, and the string is then used to test whether such a file exists. It’s a redundant step but I’m taking the detour to convert to string since that is the type that you start out with. The string is also printed to show what string is used.
Make sure to include -std=c++17 or higher

#include <filesystem>
#include <iostream>

int main() {
  auto here = std::filesystem::current_path();

  // list all files under the current directory and check whether they exist
  for (auto entry : std::filesystem::recursive_directory_iterator(here)) {
    std::string path = entry.path().string();
    bool exists = std::filesystem::exists(path);
    std::cout << "\"" << path << "\" does it exist? -> " << exists << "\n";
  }

  // check some specific directories, for which you'll likely get 0 (false)
  // unless you create them or change the paths
  std::cout << std::filesystem::exists(here / "hello") << "\n";
  std::cout << std::filesystem::exists(here / "subdir" / "somefilename")
            << "\n";
  std::cout << std::filesystem::exists(here / "subdir" / "somefilename");
}

Sorry, I didn’t mean to make light of our help but other things needed my attention and I got distracted from this part of the project.
I tried the program you wrote today and it worked perfectly! I’m studying ifstream tonight, I thought: std::ifstream file(here/“responses”); was going to do it for what I need but, while it compiles it doesn’t work but at least now I have some puzzle pieces to work with.
My compiler (g++8) doesn’t have so I had to do: g+±8 -g -Wall -std=c++17 test1.cpp -lstdc++fs
to get it to compile, looks like I need to update the compiler in all my computers and SBCs.
Thank you for all your help, Tom J.

Sure, I’m using a different library, but fstream doesn’t do things like list files in a directory, which I needed to get their paths, and I needed those paths to show you what paths are valid for your directory.

std::ifstream file(here/"responses"); was going to do it for what I need but

that would work. the path would be implicitly converted to string.

you could switch out std::filesystem::exists with your own function, the part that you’re trying to implement.

bool exists(std::string path) {
  std::ifstream file;
  file.open(path, std::ios_base::in);
  bool canOpen = file.good();
  file.close();
  return canOpen;
}

existing is a slightly different thing from being able to read though, so if you for example remove read permission, then the file would still be visible, would exist, but the function above would return false for it.

Back again, this part of the program kind of went on the back burner for a bit but filesystem did turn out to be the ticket when I came back to it.

So if I"m running a program in a given directory, for instance /home/username/Desktop/program
and in the program I do:

#include
int main(){
auto path = std::filesystem::current_path();
std::filesystem::current_path(“NewFolder”);
}

The program is now working out of /home/username/Desktop/program/NewFolder.

But how does one drop back down a directory without specifying an absolute path?
Like if I want the program to be able to go back to /home/username/Desktop/program?

I’ve read everything on cppreference on filesystem and tried everything I could think of but I’m sure there’s something simple I’ve overlooked.
This silly little chatbot program has been an amazing tool, I’ve learned so much C++ in the last month, even started multithreading so she can play random sounds (cough, sneeze, ect…) like a real person and I’m having fun learning!
Thanks in advance for any pointers on changing a directory back with filesystem!

I went with absolute path for now, but I named the 3 folders with data in them each with the same number of characters for later.
Once it becomes necessary to make it portable to other computers I figure I’ll have it get the absolute path of the current directory, iterate it into a string, count the number of characters, and knock a predetermined number of characters off the end so that string becomes the path to the parent directory.
At least that’s how I imagine it going… but I’m still very noob.