Cannot open file with relative path? (C++ ifstream) - c++

I know this seems like a simple question, but I tried everything I can think of to no avail to something that shouldn't have been a problem in the first place.
This is a small C++ program that opens a file. When I open it with its absolute filepath, it works fine. With a relative path, however, it stops working.
Here's the file path of the program and the files I'm trying to read:
C++ program: "/Users/Baggio/C++/Lab0/Lab0/Lab0/main.cpp"
Files: /Users/Baggio/C++/Lab0/Lab0/Lab0/result.txt, /Users/Baggio/C++/Lab0/Lab0/Lab0/dict.txt
Here's the code snippet:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <cstdlib>
using namespace std;
int main(int argc, const char * argv[]) {
// string dict_filename = "/Users/Baggio/C++/Lab0/Lab0/Lab0/dict.txt";
// string result_filename = "/Users/Baggio/C++/Lab0/Lab0/Lab0/result.txt";
string dict_filename_string = "dict.txt";
string result_filename_string = "result.txt";
const char* dict_filename = dict_filename_string.c_str();
const char* result_filename = result_filename_string.c_str();
// open files
ifstream dict_file(dict_filename, ifstream::in);
ifstream result_file(result_filename, ifstream::in);
if (!dict_file || !result_file) {
cerr << "File could not be opened." << endl;
exit(1);
}
}
Result of execution
File could not be opened.
I'm sure I've done all the includes right, and the data types right for the ifstream constructor arguments. The only thing I can think of worth mentioning is the system I'm on: I'm on a Mac and I'm using XCode6 as my IDE.
Also, I've tried to move the files' location (results.txt and dict.txt) to these locations to no avail:
/Users/Baggio/C++/Lab0/Lab0/Lab0/
/Users/Baggio/C++/Lab0/Lab0/
/Users/Baggio/C++/Lab0/
/Users/Baggio/C++/
Thanks for your help guys!! Any suggestions or thoughts appreciated.

Print out your current working directory when you run the program:
char buffer[256];
char *val = getcwd(buffer, sizeof(buffer));
if (val) {
std::cout << buffer << std::endl;
}
This will tell you where you are running your program from and thus why the path doesn't match for relative paths. A relative path is relative to the current working directory, not to where your binary is located.
If you want to make the path relative to the location of the binary then you will have to do that yourself. Many programming languages offer this as an option, but it is not built-in to C++. You can do this by finding the executable using the argv[0] from main. Then you need to drop the file component of the executable path and replace it with the file name that you are interested in.
Since C++17, you can use std::filesystem::current_path() instead of getcwd.
std::cout << std::filesystem::current_path() << std::endl;

Related

How to create folder in %appdata%, create .bat file in it, and then execute it?

I'm creating C++ code that will create some .bat file and store it in the %appdata% folder. I've successfully to created the file, but still fail to create the folder and execute it.
Below is my simple code, it doesn't look simple but it works to create .bat file in %appdata%, maybe someone can help me to find the simple one.
#include <iostream>
#include <stdio.h>
#include <fstream>
#include <sstream>
#include <string>
#include <windows.h>
#include <direct.h>
int main(int argc, char **argv) {
using namespace std;
std::ofstream aaa;
ostringstream aaa;
aaa.open(aaa1.str());
aaa1 << getenv("appdata") << "/"
<< "test.bat";
aaa.open(aaa1.str());
Updater << "#echo on" << endl;
Updater << "echo \"on\"" << endl;
return 0;
}
The code successfully creates the .bat file in %appdata%, but I need to store in new folder in %appdata%, say New Folder, and then execute the .bat file.
Create Directory
1st get the path using _dupenv_s() in string add new folder name "\New Folder"
2nd Create Directory using _mkdir(str.c_str());
3rd Create "test.bat" using std::ofstream outf(str);
#include "stdafx.h"
#include<fstream>
#include<iostream>
#include<conio.h>
#include<direct.h>
using std::cout;
using std::cin;
using std::endl;
int tmain(int argc, TCHAR* argv[])
{
char *pValue;
size_t len;
errno_t err = _dupenv_s(&pValue, &len, "APPDATA");
std::string NewFile = "\\new";
std::string str(pValue);
str = str + NewFile;
_mkdir(str.c_str());
str = str + "\\Sample.bat"; //
std::ofstream outf(str);
if (!outf)
{
printf("error ");
}
outf << "this is line1" << endl;
outf << "line 2" << endl;
return 0;
}
Please! Don't Forgot to Vote If its Helps
Creating/running an executable in a user writable location is something to be careful with (exploit people into running your process elevated, then running an attack payload), otherwise just a couple of things to tie together.
On Windows, most of those environment variables exist for legacy / compatibility reasons, SHGetKnownFolderPath is the modern way to find the folders. It allocates enough space for the path, be careful with manual memory from C-API, get it a unique_ptr or wstring as soon as possible. It works from Vista, there are older API's if really needed.
wchar_t *str = nullptr;
SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_DEFAULT, NULL, &str); // CHECK RETURN
...use str...
CoTaskMemFree(str);
Also be aware of Unicode and spaces in file paths.
Processes have two options, there is the system(command_line) in the cstdlib header, or for advanced use check out the Windows CreateProcessW. Something like:
STARTTUPINFO startup;
startup.cb = sizeof(startup);
PROCESS_INFORMATION pi;
CreateProcessW(NULL, L"cmd.exe /C C:\\ThePath\\myfile.bat", NULL, NULL, FALSE, 0, NULL, NULL, &startup, &pi);
Obviously specific to Windows. Linux, Mac, etc. have their own filesystem layouts and security.
C++ fstream won't create directories for you automatically. You could set up such directories as part of an installer, but to do it at runtime C++17 has std::filesystem::create_directories, which takes a path. If you can't use C++17, use CreateDirectory or _mkdir. Again on Windows be aware of Unicode.

How to run a c++ program multiple times with different input files?

I'm new to C++ and writing my master thesis and would really appreciate any help I can get!
I have a program that reads a txt file, then does a bunch of calculations, and returns a new txt file. The thing is that I want to run this program for 100+ different input files. Now I have to change the name of the input file in the code, but I would like to have it run for all the input files in my folder by itself.
I am using Visual Studio, but with little C++ experience.
Thanks :)
See this snippet. Since you are using MSCV, you need to enable MFC in configuration for this console application. Also add #include "afx.h" in #include "stdafx.h" where CFileFind is defined. PopulateFromFolder() should auto load the files into the vector files.
#include "stdafx.h"
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
void PopulateFromFolder(string path, vector<string>& files)
{
CFileFind finder;
CString fileName;
fileName.Format(L"%s*.*", CString(path.c_str()));
BOOL bOk = finder.FindFile(fileName);
while (bOk)
{
bOk = finder.FindNextFile();
if (finder.IsDots())
{
continue;
}
if (!finder.IsDirectory())
{
CString strFileName = finder.GetFileName();
files.push_back(CStringA(strFileName).GetString());
}
}
finder.Close();
}
int main()
{
vector<string> files;
string path = "D:\\MyFolder\\";
PopulateFromFolder(path, files);
auto a = path + files[0];
int i = 0;
while (i< files.size()-1)
{
cout << "processing " << files[i + 1] << endl;
ifstream fs(path+files[i++]);
if (fs.is_open())
{
//do something
}
fs.close();
}
return 0;
}
Output:
Using bash you can run them using:
$ for file in /Data/*.txt; do /path/your_program $file; done
You can define format for your input files names and put then into some directory. For example,
Input1.txt
Input2.txt
...
Input111.txt
Then use some kind of for loop:
for(int i = 1; i <= 111; ++i)
{
ifstream file("Input" + std::to_string(i) + ".txt");
if (file.is_open())
Operate(file);
}
If you don't know the exact number of files, you can check whether the file was openen by is_open() method. This way files with some numbers can be absent. You just loop for some max possible input file id.
This was a solution which doesn't require any dependencies. But if you don't mind it, you actually may consider Boost.Filesystem. Here is an example.
You can try to use std::experimental::filesystem (http://en.cppreference.com/w/cpp/experimental/fs). I guess that directory_iterator from this library can be useful for you - it allows you to iterate over all files in a given directory. Have a look at the example provided in the documentation: http://en.cppreference.com/w/cpp/experimental/fs/directory_iterator.
However, you have to make sure that you are compiling your code with a new standard (C++ 17).
Another way is to make for example a separate file containing a list of the names of all files that you want to work on. Then, you can read this list and for every file do what you need.

Error reading txt file c++

I have this code that suppose to read a txt file.
But for some reason i am always getting *File not found that means that fileIn.fail() failed...
#include <iostream>
#include <string.h>
#include <fstream>
#include <sstream>
#include <stdio.h>
using namespace std;
int main ()
{
string fileName;
ifstream fileIn;
bool x;
cout << "enter file name \n";
cin >> fileName;
fileIn.open(fileName);
if(fileIn.fail())
{
cerr << "* File not found";
return true;
}
the file located in the same folder as my main.cpp file and named input.txt. I have tried to set the fileName hard coded but this also didn't work.
What is wrong with my code?
here is the project:
Here is a checklist:
Do you have permissions to read/access the file?
Are you the owner of the file?(Linux)
Are you giving the correct path, relative or absolute from the executable?
If the answer to any of these is a no, then that is where the problem lies, not just "file not found" error.
--EDIT--
#VladIoffe the executable I see there, is qustion2 and the relative path you have to give is ../input.txt and not input.txt
You should use absolute path to the fileName.
Absoulut path will always works. But I hate full path I prefer relative path for a simple reason: code is more portable.
If you run your program with input.txt in the same path of executable it will work. But when you use an IDE you must set the current directory in the IDE settings.

boost filesystem copy_file "successful" but no files copied

im having trouble figuring out why my files wont copy. Here's a brief portion of the code:
(dir_itr is directory_iterator & root is a path)
if (!(is_directory(dir_itr->path())))
{
cout << "copying: " << dir_itr->path().filename() << endl;
try
{
copy(dir_itr->path(), root);
remove(dir_itr->path());
} catch (filesystem_error& ex) {
//more code
The results are as follows in the command window:
boost::filesystem::copy_file: The operation completed successfully:
"C:\Documents and Settings\R\Desktop\New Folder\New Folder (2)\New Bitmap Image 3.bmp",
"C:\Documents and Settings\R\Desktop\New Folder"
However no files are copied over.
I am basically just trying to move said file from folder c:\x\y\file.file to c:\x
I'm assuming why i cant move it is because i need a full file name and not just a directory or something? If this is the case, how do i convert path root to string so i can add a file name to it? (im gettin a thousand errors if i even try, they're so long i cant scroll all the way back up the window to see where it starts)
Perhaps boost::filesystem::system_complete can help:
(Sorry, I'm on my Mac and not windows but it shows a way to get the absolute path from a relative path). Good luck.
#include <iostream>
#include <boost/filesystem.hpp>
using namespace std;
int main(int argc, char *argv[]) {
boost::filesystem::path cwd(".");
boost::filesystem::path resolved = boost::filesystem::system_complete(cwd);
std::cout << cwd << std::endl;
std::cout << resolved << std::endl;
}
Outputs:
"."
"/private/var/folders/qw/x23nm9f11fxc45rgddb04n_w0000gn/T/CodeRunner/."
Got back to working on this and I added/changed the following:
try
{
string temp = root.string() + "\\" + dir_itr->path().filename().string();
path p(temp);
copy(dir_itr->path(), p);
remove(dir_itr->path());
//more code
And it seemed to work. I guess my assumption of needing to include the file name when copying was correct.

Problems using .open with ifsteam objects

The best way to explain my problem is probably just to show you my code, because it's as simple as it gets.
#include <iostream>
#include <fstream>
int main (int argc, const char * argv[])
{
std::ifstream in;
std::string line;
in.open("test.txt");
if (in.fail()) std::cout << "failed. \n";
getline(in, line);
std::cout << line;
return 0;
}
So when I run this, console is returning "failed." instead of opening up the file called test.txt — which is in the same folder as my .xcodeproj file and is also displayed in my Xcode navigator.
I'm not sure what I'm misunderstanding about this process, but I suspect it will be something simple.
Thanks! :)
The file is in the same directory as your .xcodeproj file? Well, there's your problem right here.
By default, the working directory of a process launched from Xcode will be the output directory (that is, the directory where the program is). Depending on your Xcode version, it's probably going to be in <Project Directory>/build/Debug.
Try moving the file there.