I am trying to save a file somewhere else than the folder of the exe. I have pieced together this unelegant way:
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <unistd.h>
using namespace std;
int main() {
//getting current path of the executable
char executable_path[256];
getcwd(executable_path, 255);
//unelegant back and forth conversion to add a different location
string file_loction_as_string;
file_loction_as_string = executable_path;
file_loction_as_string += "/output_files/hello_world.txt"; //folder has to exist
char *file_loction_as_char = const_cast<char*>(file_loction_as_string.c_str());
// creating, writing, closing file
ofstream output_file(file_loction_as_char);
output_file << "hello world!";
output_file.close();
}
Is there a more elegant way to do this? So that the char-string-char* is not necessary.
Also is it possible to create the output folder in the process apart from mkdir?
Thank you
You can get rid of 3 lines of code if you use the following.
int main()
{
//getting current path of the executable
char executable_path[256];
getcwd(executable_path, 255);
//unelegant back and forth conversion to add a different location
string file_loction_as_string = string(executable_path) + "/output_files/hello_world.txt";
// creating, writing, closing file
ofstream output_file(file_loction_as_string.c_str());
output_file << "hello world!";
output_file.close();
}
Related
Hey guys I'm new to this,
I managed to make c++ open a random .jpg file from a folder using srand, the files are named sequentially 1-25.
Now I want to print out which file has been chosen by the randomizer every time I run the programm and log it into a .txt file.
The log in the .txt file should look like this:
4
8
5
..and so on, so that it adds the result of the randomizer to a new line each time it gets executed.
This is the code I have so far:
#include <sstream>
#include <string>
#include <cstdlib>
#include <ctime>
#include <fstream>
using namespace std;
int main()
{
srand((unsigned)time(0));
ostringstream oss;
oss << "\"C:\\Users\\etc..";
oss << rand() % 25 + 1;
oss << ".jpg\"";
system(oss.str().c_str());
system("pause");
return 0;
}
See below a complete example how you can achieve what you described.
The function LogToFile uses std::ofstream to open a file in append mode, and write to it.
You can change it if you'd like a different format (e.g. separate by commas instead of newline).
In order to call it with the number I added a variable n to hold the number (rather than streaming it directly into the std::ostringstream).
A side note: better to avoid using namespace std - see here Why is "using namespace std;" considered bad practice?.
The code:
#include <string>
#include <ctime>
#include <fstream>
#include <sstream>
#include <assert.h>
bool LogToFile(std::string const & filename, int n)
{
std::ofstream file;
file.open(filename, std::ios_base::app); // open in append mode
if (!file.is_open())
{
return false;
}
file << n << std::endl;
file.close();
return true;
}
int main()
{
// change according to your needs:
const std::string LOG_FILENAME = "log.txt";
const std::string IMAGE_FOLDER = "C:\\tmp";
srand((unsigned)time(0));
int n = rand() % 25 + 1;
// Add the number to the log file:
bool bRes = LogToFile(LOG_FILENAME, n);
assert(bRes);
std::ostringstream oss;
oss << "\"" << IMAGE_FOLDER << "\\" << n << ".jpg" << "\"";
system(oss.str().c_str());
system("pause");
return 0;
}
I have some trouble with producing files in C++. I consulted this answer here but when I try using it, it doesn't produce a file. What I wrote:
//~/Documents/Test_CPP/ex2/main_2.cpp
#include <fstream>
int main()
{
std::ofstream file("Hello.txt");
// Hello.txt has been created here
}
I compile it with the command g++ main_2.cpp and run it with ./a.out. I don't really know what could go wrong here, except theorizing that the file might be produced not in the current directory but somewhere else. So I tried changing Hello.txt to ~/Documents/Test_CPP/ex2/Hello.txt, which doesn't change anything. What exactly am I doing wrong here?
I have encountered this problem on macOS with Xcode if you use some IDEs you should point to build-dir.
My suggestion: use std::filesystem::current_path(). It will give full path to you elf\exe dir.
#include <string>
#include <iostream>
#include <filesystem>
#include <fstream>
int main() {
std::string file_name{"Hello.txt"};
auto path{std::filesystem::current_path()};
path = path / file_name;
if (std::filesystem::exists(path)) {
std::filesystem::remove(path);
}
std::ofstream out_stream(path, std::ios::out);
if (!out_stream.is_open()) {
std::cerr << "Error open file" << std::endl;
return -1;
}
out_stream << "test" << std::endl;
out_stream.close();
return 0;
}
This can sometimes happen if you do not properly terminate the connection to the file
EG.
file.close();
This must be done before the program terminates.
I have this short program:
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
int main (int argc, char * argv[]) {
std::string homedir = std::getenv("HOME");
std::string filename = argc > 1 ? argv[1] : (homedir + "/" + "file");
std::cout << homedir << std::endl;
std::cout << filename << std::endl;
std::fstream file;
file.open(filename, std::ios::out);
file << "Yo yo waddup" << std::endl;
file.close();
return 0;
}
When I supply no arguments, it opens a file in the users home directory. That of course makes sense. But when I run it from a different directory like this:
$ ./folder/hometest examplefile
The program creates "examplefile" in my current directory instead of the directory where the program is.
Why exactly is this happening?
Why exactly is this happening?
The program is behaving just as expected.
The file is opened relative to the current work directory, not where the executable is located.
If it didn't work that way,
All your programs will have to work with absolute paths, or
The location of the program will be flooded with files. First, that might not be possible because of permissions issue. Second, in a multi-user system, users will end up trying to create the same file names/directories.
Neither of the above is desirable.
Is there a way to create files on a computer using C++ and the location of the C++ program? I want to be able to use this program on multiple computers yet each computer has its own different directory. For example if I want to create test.txt file located on the user directory is there a way to put the path of the file corresponding to the program file's location because "user" differs on the name of the user.
as long as you are on windows you can use the API GetUserName then use SetCurrentDirectory API to change working directory then create your file there using CreateFile or fstream:
#include <iostream>
#include <windows.h>
#include <fstream>
#include <string>
using namespace std;
int main()
{
ULONG len = 50;
LPSTR lpBuffer = (LPSTR)GlobalAlloc(GPTR, len);
GetUserName(lpBuffer, &len);
cout << lpBuffer << endl;
// don't forget to clean when you're done:
string str = "C:\\Users\\";
str += lpBuffer;
str += "\\test.txt";
cout << str << endl;
ofstream out(str.c_str());
if(out.fail())
perror("Opening failed");
out << "Hello " << lpBuffer;
out.close();
GlobalFree(lpBuffer);
GlobalFree(lpBuffer);
return 0;
}
this program gets the current username and creates file inside its folder and writes in it "Hello" 'yourusername'
Basically I need to open and read a list of files I get from another command.
For each line of output of popen
open a file usen ifstream.open
it compiles and if I put the file name directly it works fine, but it doesn't do anything when using popen output. I've seen questions like this but none of this particular way of giving filenames.
here's the code:
#include <iostream>
#include <sqlite3.h>
#include <stdio.h>
#include <fstream>
using namespace std;
int main () {
ifstream singlefile;
FILE *filelist;
char filename[512];
string progline;
if(!(filelist = popen("find `pwd` -name \"*.js\"", "r"))){
return 1;
}
while( fgets(filename, sizeof(filename), filelist)!=NULL)
{
cout << filename;
singlefile.open(filename, ifstream::in);
while ( singlefile.good() )
{
getline (singlefile,progline);
cout << progline << endl;
}
singlefile.close();
}
pclose(filelist);
return 0;
}
next step would be not open each file inside the loop but to store the file list and then open each file.
Thanks
fgets keeps the trailing newline, resulting in a filename of a non-existing file. Also the stream state is only updated after reading. If I replace the while body with the following code, it works for me:
cout << filename;
size_t len = strlen(filename);
// chop off trailing newline
if (len > 1 && filename[len - 1] == '\n') filename[len - 1] = 0;
singlefile.open(filename, ifstream::in);
while ( getline(singlefile, progline) )
{
cout << progline << endl;
}
singlefile.close();
If you actually want to iterate through a list of files, I'd use Boost.Filesystem, which has a nice C++ interface, works for all filenames (even for those with newlines), and is platform-independent.
If this actually is only an example and your actual command is not find, there is still some room for simplification. Here is a suggestion that uses Boost.Iostreams to get rid of most of the C function calls (it would be great to have a device source reading from a process's standard output, but Boost.Iostreams lacks that):
#include <cstdio>
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <string>
#include <stdio.h>
#include <boost/noncopyable.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
using namespace std;
namespace io = boost::iostreams;
class Popen: private boost::noncopyable {
public:
explicit Popen(const char* command):
m_stream(popen(command, "r")) {
if (!m_stream) throw runtime_error("popen failed");
}
~Popen() {
pclose(m_stream);
}
FILE* stream() const {
return m_stream;
}
private:
FILE* m_stream;
};
int main() {
Popen pipe_wrapper("find `pwd` -name \"*.cpp\"");
io::file_descriptor_source pipe_device(fileno(pipe_wrapper.stream()), io::never_close_handle);
io::stream<io::file_descriptor_source> pipe_stream(pipe_device, 0x1000, 0x1000);
string filename;
while (getline(pipe_stream, filename)) {
cout << filename << endl;
ifstream file_stream(filename.c_str(), ifstream::in);
string progline;
while (getline(file_stream, progline)) {
cout << progline << endl;
}
}
}