Adding to the name of a file - c++

I'm working on an application that processes text files, and I want to create a new file with a similar name to that file, but slightly modified.
So for instance, I have a function that takes a string fileName as a parameter and creates a new file with the word "PROCESSED" added before ".txt."
so if fileName = "testFile.txt"
the new file should be named "testFilePROCESSED.txt"
string newFile = filename + "PROCESSED"; obviously doesn't work since the filename would be "testFile.txtPROCESSED" in this case.

You just need more practice with strings:
int ii = filename.rfind('.');
filename.insert(ii, "PROCESSED");

Let's keep it simple, I assume fileName is a string.
`#include <sstream>`
using namespace std;
stringstream ss;
fileName.erase(name.end()-4, name.end()); //Extension removal.
ss << name << "PROCESSED.txt";
string newFileName = ss.str();

Related

I want to create a text file in cpp using ofstream

I want to create a file qbc.txt. I know how to create it, but I want to create a program that, if a file already exists with the same name, it would rename it to qbc(1).txt.
In C++17, boost's filesystem library was standardized as std::filesystem
It comes with a convenient std::filesystem::exists function.
It accepts a std::filesystem::path object, but fortunately those can be constructed with a std::string, making our program trivially easy:
std::string prefix = "qbc";
std::string extension = ".txt";
std::filesystem::path filename{prefix + extension};
int i = 0;
while (std::filesystem::exists(filename)){
filename = prefix + "(" + std::to_string(++i) + ")" + extension;
}
// now filename is "qbc(1)" or "qbc(2)" etc.
Unfortunately no compiler has full support for it at the time of this writing!
Here is a simple solution. The file_exists() function came from #Raviprakash in his response. I've added how to change the filename and try again until success. I've done an approach similar to this before in Python.
If you know that your program is the only one that will create or remove these files, then you can cache the last created one and simply create the next one instead of looping over all of the created ones every time. But this kind of optimization would only make sense if you plan to make hundreds of thousands of files this way.
#include <fstream>
#include <string>
bool file_exists(const std::string &filename) {
std::ifstream in(filename);
return in.good();
}
std::ofstream& open_new(std::ofstream &out, std::string prefix,
std::string suffix)
{
std::string filename = prefix + suffix;
unsigned int index = 0;
while (file_exists(filename)) {
index++;
filename = prefix + "(" + std::to_string(index) + ")" + suffix;
}
out.rdbuf()->open(filename, std::ios_base::out);
return out;
}
int main() {
std::string prefix = "qbc";
std::string suffix = ".txt";
std::ofstream out;
open_new(out, prefix, suffix);
out << "hello world!\n";
return 0;
}
I know the program needs some improvements but the general idea is here:
#include <fstream>
#include <string>
using namespace std;
inline bool file_exists(const std::string& name)
{
ifstream f(name.c_str());
return f.good();
}
int main()
{
string filename, name;
name = "qbc";
filename = name;
int counter = 1;
while (file_exists(filename+".txt")) {
string str = to_string(counter);
filename = name+ "(" + str + ")";
counter++;
}
filename += ".txt";
ofstream out(filename.c_str());
return 0;
}
I don't think this can be entirely solved using just the standard libraries. You can certainly keep picking a new file name until you find one that's unused and then create the new file (as the other answers have shown).
But there's an inherent race condition in that approach. What if another process creates a file between the time your program decides the name is available and the time it actually creates the file? Imagine two copies of your program both trying to write out files.
What you need is an atomic way to check for the file's existence and also to create the file. The normal way to do that is to first just try to create the file and then see if you succeeded or not. Unfortunately, I don't think the standard C++ or C libraries give you enough tools to do that. (I'd be happy to be proven wrong about that.)
Operating systems often provide APIs for doing just that. For example, Windows has GetTempFileName, which just keeps trying to create a new file until it succeeds. The key is that, once it succeeds, it keeps the file open so that it knows no other process can steal the name that's been selected.
If you tell us which OS you're using, we might be able to provide a more detailed answer.

Fstream not reading a complete struct from binary data (C++)

I've been trying to make my program write a string into a binary file using Ofstream::write(), but I could not find out how to (through the interwebs), so I tried writing a struct with a string into the file. That worked perfectly; I could open the file and read the string (with my human eyes), but when I tried to use Ifstream::read() to read the struct, I just got an empty string and the string that I wrote (in this case, "dir" was the empty one, and "fileName" was correctly read).
Any and all help is appreciated :)
PS: Both strings are saved in the file...
This is my writing code:
StringStruct texPath;
texPath.dir = "src/Assets/";
texPath.fileName = "bricks_top.png";
file.write((char*)&texPath, sizeof(texPath));
This is my reading code:
StringStruct texFile;
file.read((char*)&texFile, sizeof(texFile));
std::string filepath = "";
filepath += texFile.dir;
filepath += texFile.fileName;
std::cout << filepath;
And this is the "StringStruct" code:
struct StringStruct {
std::string dir = "src/Assets/";
std::string fileName = "Example.png";
};
Ok, I recieved some comments (thanks manni66) saying that I have to write as c-strings. So I changed my struct to this:
struct StringStruct {
char* dir = "src/Assets/";
char* fileName = "Example.png";
};
So that I was writing each string as a c-string instead.

Extract the file name from filename with path which comes from argument

My program get the filename with or without path(direct or indirect).
I'd like to use the filename from argv as a part of output filename.
The problem is that sometimes the filename from argv includes path and sometimes doesn't.
What I want to do is
1. if filename includes path, extract filename only and return filename.
2. if filename doesn't includes path, return filename.
Current my code is
std::string input_trace_filename = argv[1];
std::string read_filename = input_trace_filename + ".read.";
std::string write_filename = input_trace_filename + ".write.";
Thanks in advance.
You can use this:
std::string filename = string(argv[1]);
int index = filename.find_last_of("/\\");
std::string input_trace_filename = filename.substr(index+1);

c++ ofstream write_to_log.open (" relative path + array");

I want the line below to write a new file using the content given in the array
but into a new folder named logs:
char log_file_name[100]; /* this array contains the name of a new file */
ofstream write_to_log;
write_to_log.open (relative path, log_file_name , fstream::app);
How do I get it working ?
You can use CreateDirectory for creating folders with VC++ in Windows.
#include <windows.h>
#include <string>
#include <fstream>
using namespace std;
int main() {
string path = "C:\\users\\folder";
CreateDirectory(path.c_str(), NULL);
char log_file_name[100] = "log.txt";
path += '\\';
path += log_file_name;
ofstream write_to_log(path.c_str(), fstream::app);
return 0;
}
The NULL refers to a security attributes structure that you may have to create. More details at MSDN here and in this answer.
You can save your self a lot of potential trouble and replace char log_file_name[100]; with std::string log_file_name; The benefits of string are many, the most important here are they resize and they make appending really easy. The string does everything a char array does and a whole lot of extras. In virtually all cases, you should chose a string over a char array.
string path;
string log_file_name;
With the path and the file name as strings
path += "\\" + log_file_name
ofstream write_to_log(path, fstream::app);
if (write_to_log)
{ // file is open and looks writable (have to start writing to be sure)
// do stuff. Or not. It's a free country.
}
else
{ // file didn't open
// Handle error
}
All done and the file, if it exists and is writable, is open and ready to go. Always check the state of a stream when you use it. SO is littered with questions from people who didn't and got confused by the result.
On older compilers you may have to change the create and open line slightly:
ofstream write_to_log(path.c_str(), fstream::app);

Name *.bin file after string

I'm trying to get a string from the user through stdin and save it to the variable InputString, then create a binary file with the same name as the value of InputString. This is the code I've written so far:
std::string InputString;
getline(std::cin, InputString);
std::cout << InputString << std::endl;
// The code above works.
// Errors start below. :(
void Printi(std::string filename)
{
std::ofstream Printi(filename".bin");
Printi((char*)&Hans, sizeof(Person)); // Hans is an instance of my class Person.
Printi.close();
}
Printi(InputString);
I get the following errors (translated into English from my localized compiler):
"Printi": Local function definition is not allowed
Missing ")" (in line std::ofstream Printi..)
How can I solve this problem using only standard C++ libraries?
std::ofstream Printi(filename".bin") needs to be std::ofstream Printi(filename + ".bin"). The + operator is used to concatenate the strings and append the .bin to the end of what was supplied in the file name.