Renaming a file to name of file that already exists - c++

i am renaming file for example file1.txt to "newFile.txt" but when the code runs for the next time. the file newFile.txt already exists so the newly file created whos name is "file1.txt" doesn't renamed to "newFile.txt"
what i want is if the "newFile.txt" already exists renaming "file1.txt" should overwrite the "file1.txt" is it possible ??
Here goes my code
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
char data[100];
fstream outfile;
outfile.open("afile.dat" , ios::out );
cout << "Writing to the file" << endl;
cout << "Enter your name: ";
cin.getline(data, 100);
outfile << data << endl;
cout << "Enter your age: ";
cin >> data;
cin.ignore();
// again write inputted data into the file.
outfile << data << endl;
cout << "Reading from the file" << endl;
outfile >> data;
cout << data << endl;
outfile >> data;
cout << data << endl;
outfile.close();
// this is how i am renaming
std::rename("afile.dat" , "file2.txt");
return 0;
}

Your code works and renames a file only once.
The second time you run your program, file banana.txt already exist in that directory and function std::rename("afile.dat" , "banana.txt"); returns an error code.
So you need to check if a file with the new filename is already exists or handle an error after function std::rename.

One possible solution is to use the <filesystem> library - you can check it with std::filesystem::exists() from the <filesystem> header and copy the contents of the old file to the new file with copy option update_existing. Then you can remove the old file, effectively doing what you're looking to do.
It'd look like so:
if(outFile.is_open()) {
outFile.close();
}
if( std::filesystem::exists( newFile ) ) {
// this can be on the same line, just making a var for readability
auto copyOption{std::filesystem::copy_options::update_existing};
std::filesystem::copy_file( oldFile, newFile, copyOption);
std::filesystem::remove( oldFile );
// OR if you don't care what was in the old file anyways,
// ignore the previous three lines above and just remove it
std::remove(oldFile);
} else {
std::filesystem::rename( oldFile, newFile );
}
outFile.open(newFile);
There ARE other ways to do this, but I find this to be a very easy approach in my subjective opinion (if performance of file close/open is acceptable for your case).

why not output contents of new file to another file, then delete the original file already there and ren the new file to original name
cat newfile > newfile1
del original file
ren newfile1 to original file name ... i do this all the time ... i must be missing something using all that code you are using to do it

Related

Opening a C++ .txt file using user-input

I'm trying to open a C++ .txt file as shown in my code below. This is part of a larger program that I'm working on where I write the contents of one file into another so that it contains the same information as the original but I am required to provide user-input. If the user-provides a .txt file that is not the one we are using, I have to produce an error message and prompt them to re-enter an input until they input the correct one (test.txt):
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
/* Refers to test.txt */
ofstream mainfile;
std::string filename;
std::cout << "Please enter the name of your data file: ";
std::cin >> filename;
mainfile.open(filename.c_str());
mainfile << "test.txt";
if(!mainfile) {
std::cout << "I'm sorry, I could not open '" << filename << "'." << std::endl;
std::cout << "Please enter another name: " <<
std::endl;
std::cin >> filename;
} else {
std::cout << "File '" << filename << "' opened successfully!" << std::endl;
}
return 0;
}
My current issue is that the program is terminating too early, even when I input incorrect inputs such as jaguar.txt or flowers.txt, anything that isn't "test.txt". In fact, when I input just about any .txt file name it will output saying that it opened successfully.
It seems that what you want to do is open up 2 different files, where one is used as the file to copy from (test.txt), and the other is the file to copy to (jaguar.txt). Instead of checking if test.txt exists with std::ofstream, you should instead use std::ifstream.
Using ifstream, if the file does not exist, your code will work properly. Instead, because you are currently using ofstream, the file will open correctly, because you're essentially telling it to make the file for you.
So basically, where you have used ofstream mainfile, instead it should be:
ifstream mainfile;
Later in the code, you can prompt the user for the file to copy to (i.e. jaguar.txt), and this will be the one where you output data using ofstream.
Use ifstream to read from a file, and ofstream to write to a file.
To check whether the source file exists, test the corresponding ifstream after trying to open it:
ifstream mainfile; // ifstream stands for "input file stream"
std::cout << "Please enter the name of your data file: ";
std::cin >> filename;
mainfile.open(filename);
while (!mainfile) { // asking endlessly, until the user inputs a good file
std::cout << "I'm sorry, I could not open '" << filename << "'." << std::endl;
std::cout << "Please enter another name: " <<
std::endl;
std::cin >> filename;
mainfile.open(filename);
}
std::cout << "File '" << filename << "' opened successfully!" << std::endl;
By the way, in the error message "open" is programmer's jargon. It's a general word which includes both reading and writing. If your application copies stuff from one file to the other, the user may get confused: is there a problem with input or output? You might want to say "read" instead of "open", even though technically you didn't read anything yet. That would make a clearer error message.
If you want to copy one file to another, use one of the methods described in a dedicated question.

find if the word exist in the text file

Please can anybody help me? I'm a beginner and I have a hard assignment.
I need to write a c++ program that does the following :
Ask the user to enter two text file , the the first one contains a list of words in one column Regardless of their number , second one contains the text file ,like this:
//output
Enter the keywords file: keywords_file.txt
Enter the text file: text_file.txt
2.Search for the keywords from the keywords file in the text file
3.if the keyword exist the output =1 "true", if the keyword doesn't exist output =0 "false" ,like this :
system : 1 //its exist
book : 0 //its doesn't exist
Then output in new text file (ofstream)
I put the words in file each one on its own line because some of them are phrases I don't want to sprit them ,search them as one word , also the test file I want it to stay as complete text not separate words from each other so possibly I cant use "map" & "vector". I already tried them...so possibly I can consider that each word in the words file just a line and read them all , then search for them in the text file
i found this code here in the site but its need modifications , could any body help me ?
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
bool CheckWord(char* filename, char* search)
{
int offset;
string line;
ifstream Myfile;
Myfile.open (filename);
if (Myfile.is_open())
{
while (!Myfile.eof())
{
getline(Myfile,line);
if ((offset = line.find(search, 0)) != string::npos)
{
cout << "found '" << search << "' in '" << line << "'" << endl;
Myfile.close();
return true;
}
else
{
cout << "Not found" << endl;
}
}
Myfile.close();
}
else
cout << "Unable to open this file." << endl;
return false;
}
int main ()
{
CheckWord("dictionary.txt", "need");
return 0;
}
The code that you found somewhere is really bad. You should not use it. Let me explain you why.
Most important, it does not fulfill any of your requirments. So, it is completely wrong for your purpose
There are design-, syntax- and semantic errors. It does not even compile on my machine
Examples: Do not use using namespace std; always use fully qualified names like std::string
Type of vearibe offset should be size_t. You compare it later to string::npos. So, type is wrong
The constructor of std::ifstream can open the file for you. So the call to open is not necessary
MyFile is not a class name. it should start with a lowercase character
Using is_open is not necessary. The bool operator for the iostreams is overloaded. So, you can simply write if (myFile)
while (!Myfile.eof()) is a semantic bug. It will not work as you think. Please find many many examples here on SO. Please write instead while (std::getline(myFile, line))
Explicit call to close is not necessary. The destructor of the stream will automatically close the file for you
Function should haveonly one exit point. There are 2 return statements.
cout << "Not found" << endl; can be replaced by std::cout << "Not found\n". But better would be to mention, what has been "not found"
Do not use char* for strings. Always use std::string instead.
Write many many comments and use meaningful variable names
You see. You should not use this code. It is really bad.
Then, next step, before you start any coding, you should anaylyse the requirements and then design a solution
So, obviously, you need to open 2 input files and one output files. If any of this open activities fail, then no need to open any other file. So, Let us do this sequentially. Open, check, if ok, then open next.
Then, because you want to compare words from a list to the contents of a complete text file, we should first and only once read the comlete text file. Then, we will read keyword by keyword and check, if it is in the text file data.
The we seacrh for the keyword and will show the result in the output file and, for debug purposes, also on std::cout.
Since you are new and have maybe restrictions regarding the usage of modern C++ and espcially the usage of the C++ STL, I will use simple C++ code.
Please see the following simple example.
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
int main() {
// Give instructions to the user to enter the file name for the keywords file
std::cout << "Please enter the file name for the keywords file:\t ";
// Read the filename for the keywords file
std::string keywordFileNname;
std::cin >> keywordFileNname;
// Open the keywords file for reading
std::ifstream keyWordFileStream(keywordFileNname);
// Check, if that worked and continue only if OK
if (keyWordFileStream) {
// Next, we ant to have the text file name. Instruct use to give the filename for the text file
std::cout << "Please enter the file name for the text file: \t ";
// Read the file name of the text file
std::string textFileName;
std::cin >> textFileName;
// Open the text file for reading
std::ifstream textFileStream(textFileName);
// Check, if the text file could be opened and continue only, of OK
if (textFileStream) {
// Now, give instructions to the user to open the output file name
std::cout << "Please enter the file name for the output file: \t ";
// Read the filename for the output file
std::string outputFileName;
std::cin >> outputFileName;
// Open the output file stream
std::ofstream outputFileStream(outputFileName);
// Check, if the output file could be opened, If OK, continue
if (outputFileStream) {
// So, all files are open, we can start to work
// We will read the complete text file in one string
// This solution is not very good, but avoids more complex features
std::string textFileData;
char oneCHaracter;
while (textFileStream.get(oneCHaracter)) {
textFileData += oneCHaracter;
}
// So, now all text file has been read to one string.
// Next we will read keyword by keyowrd and search it in the text file
std::string keyWord;
while (keyWordFileStream >> keyWord) {
int exists = 0;
// Check, if the keyword is in the text file data
if (textFileData.find(keyWord) != std::string::npos) {
// Keyword found
exists = 1;
}
// Write result to output file
outputFileStream << std::right << std::setw(50) << keyWord << std::left << " --> " << exists << '\n';
// And write some debug output. You may delete this line if not needed
std::cout << std::right << std::setw(50) << keyWord << std::left << " --> " << exists << '\n';
}
}
else {
// output file could not be opened. Show error message
std::cerr << "\nError: Could not open output file '" << outputFileName << "'\n\n";
}
}
else {
// text file could not be opened. Show error message
std::cerr << "\nError: Could not open text file '" << textFileName << "'\n\n";
}
}
else {
// Keyword file could not be opened. Show error message
std::cerr << "\nError: Could not open key word file '" << keywordFileNname << "'\n\n";
}
return 0;
}
You can see that I always check the result of IO operations. That is very important.
There is of course also a more advanced and more modern C++ solution. To concentrate more on the essential task, I put all the file handling stuff in a separate function.
This example code uses C++17. So you must enable C++17 for your compiler. Please see (one of many possible solutions)
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <vector>
#include <iterator>
#include <algorithm>
// In order to concentrate on the essential task, we put the file stream stuff in a separate function
bool getValidStream(std::ifstream& keyFileStream, std::ifstream& textFileStream, std::ofstream& outFileStream) {
// We are pessimistic and assume an error
bool result{ false };
// Give instructions to the user to enter the file name for the keywords file
if (std::cout << "Please enter the file name for the keywords file:\t ")
// Read keyword text filename
if (std::string keywordFileNname{}; std::cin >> keywordFileNname)
// Open key word file
if (keyFileStream.open(keywordFileNname); keyFileStream)
// Give instructions to the user to enter the file name for the text file
if (std::cout << "Please enter the file name for the text file: \t ")
// Read text filename
if (std::string textFileName{}; std::cin >> textFileName)
// Open text file
if (textFileStream.open(textFileName); textFileStream)
// Give instructions to the user to enter the file name for the output file
if (std::cout << "Please enter the file name for the output file: \t ")
// Read output filename
if (std::string outFileName{}; std::cin >> outFileName)
// Open output file
if (outFileStream.open(outFileName); outFileStream)
result = true;
if (not result)
std::cerr << "\nError: Problems with files\n\n";
return result;
}
int main() {
// Define streams to use in our software
std::ifstream keyWordFileStream{}, textFileStream{};
std::ofstream outputFileStream{};
// Get valid streams
if (getValidStream(keyWordFileStream, textFileStream, outputFileStream)) {
// Read all keywords into a vector
std::vector keywords(std::istream_iterator<std::string>(keyWordFileStream),{});
// Read complete textfile into a string variable
std::string textData(std::istreambuf_iterator<char>(textFileStream), {});
// Output result
std::transform(keywords.begin(), keywords.end(), std::ostream_iterator<std::string>(outputFileStream, "\n"),
[&](const std::string& key) {return (textData.find(key) != std::string::npos) ? key + ": 1" : key + ": 0"; });
}
return 0;
}
The code you have shown is almost workable. The core logic of finding the search string in the line read from the file using find is what you would want to do. If you find it, return true. That's certainly one way of going about the problem you describe.
Read on why !Myfile.eof() is bad, fix it.
Remove close() calls since the destructor of std::basic_ifstream release the underlying file resource
You're passing in character literals but your function signature is bool CheckWord(char* , char* ). Fix that source of warning.
Once, you've fixed all this, you should be fine. You have the core logic of finding words in a file. I still don't get why you asked the question when you've got a near working solution. If you're looking for complexity gains etc. you need to explore the data structure to be used, but then that's probably not your intention for this assignment.

edit: trouble checking if file is empty or not, what am I doing wrong?

Edit: changed my question to be more accurate of the situation
I'm trying to open up a text file (create it if it doesnt exist,open it if it doesnt). It is the same input file as output.
ofstream oFile("goalsFile.txt");
fstream iFile("goalsFile.txt");
string goalsText;
string tempBuffer;
//int fileLength = 0;
bool empty = false;
if (oFile.is_open())
{
if (iFile.is_open())
{
iFile >> tempBuffer;
iFile.seekg(0, iFile.end);
size_t fileLength = iFile.tellg();
iFile.seekg(0, iFile.beg);
if (fileLength == 0)
{
cout << "Set a new goal\n" << "Goal Name:"; //if I end debugging her the file ends up being empty
getline(cin, goalSet);
oFile << goalSet;
oFile << ";";
cout << endl;
cout << "Goal Cost:";
getline(cin, tempBuffer);
goalCost = stoi(tempBuffer);
oFile << goalCost;
cout << endl;
}
}
}
Couple of issues. For one, if the file exist and has text within it, it still goes into the if loop that would normally ask me to set a new goal. I can't seem to figure out what's happening here.
The problem is simply that you are using buffered IO streams. Despite the fact that they reference the same file underneath, they have completely separate buffers.
// open the file for writing and erase existing contents.
std::ostream out(filename);
// open the now empty file for reading.
std::istream in(filename);
// write to out's buffer
out << "hello";
At this point, "hello" may not have been written to disk, the only guarantee is that it's in the output buffer of out. To force it to be written to disk you could use
out << std::endl; // new line + flush
out << std::flush; // just a flush
that means that we've committed our output to disk, but the input buffer is still untouched at this point, and so the file still appears to be empty.
In order for your input file to see what you've written to the output file, you'd need to use sync.
#include <iostream>
#include <fstream>
#include <string>
static const char* filename = "testfile.txt";
int main()
{
std::string hello;
{
std::ofstream out(filename);
std::ifstream in(filename);
out << "hello\n";
in >> hello;
std::cout << "unsync'd read got '" << hello << "'\n";
}
{
std::ofstream out(filename);
std::ifstream in(filename);
out << "hello\n";
out << std::flush;
in.sync();
in >> hello;
std::cout << "sync'd read got '" << hello << "'\n";
}
}
The next problem you'll run into trying to do this with buffered streams is the need to clear() the eof bit on the input stream every time more data is written to the file...
Try Boost::FileSystem::is_empty which test if your file is empty. I read somewhere that using fstream's is not a good way to test empty files.

ifstream opens files named by cin but not when pulled from an array. Any difference between cin and a regular string definition?

TL;DR File names stored as strings in array (using new) - ifstream won't open them (perror returns "No such file or directory"). Swap out array variable with a call to the user to name the file (using cin) - ifstream opens the file. Why? How do I get the array to work?
Things to Know
All files exist in folders with naming scheme run20### where
All files are named S20###.ABC where ### is the same from the parent directory and ABC can go from 001-999. These are all text files (there are no .txt extensions though) that CAN be opened by ifstream and getline.
I'm writing a program that's going to pull information from up to 150 files. An early version I wrote had the user input the file name (using cin). ifstream took the stored name and opened the file successfully every time. Obviously, I don't want to type 150 file names in so the program stores all of the file names as strings in an array for the program to pull from. However, when it goes to open the file (in the correct path and with the correct file name and extension), the error I get from perror returns "No such file or directory." If I just do a quick swap of the variables though so that the file name comes from cin, the file opens. Why would cin work and the array version not? Is there any way to get the array to work?
I've also tried something similar where there is no array. Instead, in the for loop that would pull the files from the array, the file gets named each time.
Here's the code (sorry about the headers, couldn't get it to format right):
#include <iostream>
#include <array>
#include <string>
#include <ctime>
#include <cstring>
#include <fstream>
#include <sstream>
using namespace std;
int main() {
//--------------------------Initial setup----------------------------------
cout << "Please give the full name of the folder you would like to open in the /Users/lucas/HPS/TDCData directory" << endl << endl;
string sFolderName;
cin >> sFolderName;
// Create path. I have mine here but you'll have to change it to something you'll
// use if you want to run the code
string sPathName = "/Users/lucas/HPS/TDCData/" + sFolderName;
//----------------Create file name array------------------------------------
// Get naming base from the folder name given
string sFileBase = "S20";
for (int i = 5; i <= sFolderName.length(); i++){
sFileBase = sFileBase + sFolderName[i];
}
//Specify range since different directories have different numbers of files
cout << "Files must be named S20###.ABC" << endl;
cout << "Specify a range for ABC" << endl;
int iFloor;
int iCeiling;
cout << "Floor: " << endl;
cin >> iFloor;
cout << "Ceiling: " << endl;
cin >> iCeiling;
// Define an array to store names and then store them
string *aFiles;
int iFilesSize = iCeiling - iFloor + 1;
aFiles = new string [iFilesSize];
cout << "Array created" << endl;
for (int i = iFloor; i <= iCeiling; i++){
string name = sFileBase;
if (i < 10){
name = name + ".00" + to_string(i);
}
else if (i < 100) {
name = name + ".0" + to_string(i);
}
else {
name = name + '.' + to_string(i);
}
aFiles[i-1] = name;
}
//----------------Open each file in aFiles----------------------
for (int i = 0; i < iFilesSize; i++){
// There are two important lines of code here. The first gets sFileName from
// aFiles. The second gets sFileName from user input using cin (this is commented out).
// Obviously, none of the last section of code is needed for the second line to work.
// The first line does not work for me. The second does.
string sFileName;
//First
sFileName = aFiles[i];
//Second
//cin >> sFileName
string sFullPath = sPathName + "/" + sFileName;
cout << "Searching ... " << sFullPath << endl << endl;
//Open file
ifstream inputFile(sFullPath);
//Check that the file opened
if (! inputFile.is_open()) {
cout << "Error reading" << sFullPath << endl;
perror("Error is: ");
return 0;
}
else {
cout << "File opened successfully..." << aFiles[i] << endl << endl;
}
}
cout << "All files opened..." << endl << endl;
return 0;
}
Also here's a link to a zip of one of the directories for any tests someone might want to run. Thanks for any and all help!
It looks like you start filling aFiles from index iFloor, while you start reading aFiles from index 0.
How about changing aFiles[i-1] = name; to aFiles[i-iFloor] = name;
"TL;DR File names stored as strings in array (using new)"
Don't do this. Use a dynamic container like std::vector<std::string> instead.
"- ifstream won't open them (perror returns "No such file or directory")."
Use the debugger to check what's actually passed to the
ifstream inputFile(sFullPath);
with sFullPath.
"Swap out array variable with a call to the user to name the file (using cin) - ifstream opens the file. Why? How do I get the array to work?"
You cannot replace the behaviors of a stream getting values as you're trying with the array.
The best way to make the input stream source transparent, is to simply use a std::istream reference, and don't care if it's std::cin or e.g. a std::istringstream reference.
The std::string instance needed to initialize the mentioned std::istringstream can be build e.g. using a std::ostringstream and pass the str() property to the std::istringstream constructor.

C++: How can I switch between input and output from file?

I'm trying to write up a program that will display the contents of a text file to the screen for a user. Specifically, the text file will be a list of names that the program will read and display each name to the user individually. The user will then either like the name and keep it or dislike the name and remove it.
My dilemma is: if the user elects to keep the name, the program will need to go from reading the file to "writing" (deleting the name) the file and then back to reading the file again! I found the following relevant code on http://www.tutorialspoint.com/cplusplus/cpp_files_streams.htm. It shows that one must use .close() to switch from reading to writing, but this seems funky to a newbie like me. Is there a better way to do it or is the code below just fine?
#include <fstream>
#include <iostream>
using namespace std;
int main ()
{
char data[100];
// open a file in write mode.
ofstream outfile;
outfile.open("afile.dat");
cout << "Writing to the file" << endl;
cout << "Enter your name: ";
cin.getline(data, 100);
// write inputted data into the file.
outfile << data << endl;
cout << "Enter your age: ";
cin >> data;
cin.ignore();
// again write inputted data into the file.
outfile << data << endl;
// close the opened file.
outfile.close();
This is where the file goes from write mode to read mode.
// open a file in read mode.
ifstream infile;
infile.open("afile.dat");
cout << "Reading from the file" << endl;
infile >> data;
// write the data at the screen.
cout << data << endl;
// again read the data from the file and display it.
infile >> data;
cout << data << endl;
// close the opened file.
infile.close();
return 0;
}
Also, I'm having a hard time finding how to read and modify individual characters in the file. I need to do this too, as the file needs to follow a specific pattern, with five names per line and one space between each name (newline at end of fifth name, obviously). Help with this would be appreciated.
Changing things mid-file is complicated.
What I would do is either create a temporary file, write the kept names to that file and replace the original file with this temporary file, (or just store the kept names in a vector and rewrite the file)
try
std::fstream ff("io.txt", std::fstream::in | std::fstream::out);
and fstream::read, fstream::write, fstream::seekg
If the file is small then load it into memory.
Otherwise use fopen with "a+" or "r+" mode and fseek.