2
\$\begingroup\$

I had answered this question from stackoverlow and the code below is code that I wrote to explain to the OP a possible way to achieve what I believe they were looking for.

The general idea that I got from them was that they were trying to open a file with a specified file name and if that file does exist that they in turn wanted to create a new file with the same filename but with extra characters appended to the filename.

This is the small program that I wrote to mimic that behavior.

#include <string>
#include <fstream>
#include <iostream>

int main() {
    std::string originalFilename("out.txt");
    std::string extension(".txt");                  
    std::string nextFilename;
    bool originalFileFound = false;

    // First test to see if original file exist by opening 
    // if so then generate the next usable name
    std::fstream fileIn( originalFilename, std::ios::in );
    unsigned int counter = 0;

    if (fileIn.is_open()) {
        counter++;
        nextFilename = originalFilename.substr( 0, originalFilename.size() - extension.size() ) 
                       + "_" + std::to_string(counter) + extension;
        originalFileFound = true;
    }
    fileIn.close();

    // Generate a few files with the appended number system to 
    // the end of the original filename if the original file was found.
    if ( originalFileFound ) {
        for ( int i = 1; i < 6; i++ ) {
            std::fstream nextFile;
            nextFile.open( nextFilename, std::ios::out );
            if (nextFile.is_open()) {
                nextFile << nextFilename; // Write this before updating...
                counter++;
                nextFilename = nextFilename.substr(0, nextFilename.find_first_of('_') + 1) 
                               + std::to_string(counter) + extension;
            }
            nextFile.close();
        }
    }
    return 0;
}

I would like to know if there is a more elegant, more efficient and cleaner way to achieve this using modern C++. Writing this simple program in essence was basically self practice to improve my skills with string manipulation and the string's set of library functions and algorithms.

\$\endgroup\$
0
\$\begingroup\$
  • Prefer RAII-style opening the file in the constructor. You already done that with

        std::fstream fileIn( originalFilename, std::ios::in );
    

    so why not follow the suit with

        std::fstream nextFile(nextFilename, std::ios::out);
    
  • There is no need to explicitly nextFile.close();. The destructor will take care of it at the end of each iteration.

  • There is nothing wrong with the early return. Instead of setting originalFileFound = true;, and testing it later on, quit immediately if opening fails. That would spare a boolean flag and a level of indentation.

  • Consolidate handling of nextFilename in one place. Consider

        if (!fileIn.is_open()) {
            print_error_message();
            return 1;
        }
    
        std::string prefix = originalFilename.substr(0, originalFilename.size() - extension.size());
    
        for (int i = 0, counter = 0; counter < 5; i++) {
            nextFilename = prefix + "_" + std::to_string(i) + extension;
            ....
        }
    
  • I would be very cautious to use this program, because it may overwrite existing files.

\$\endgroup\$
  • \$\begingroup\$ I truly appreciate the feed back. Using a temp string for prefix does make the code look a little more cleaner and concise. And yes I know that this could potentially overwrite existing files, but as I stated it was just a demonstration program to an already existing question over at stackoverflow. I could turn this into a function that would take file manipulation flags as arguments, such as appending, overwriting etc. \$\endgroup\$ – Francis Cugler Feb 18 at 20:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.