cfreopen

Write to subdirectory using freopen


I am trying to write out to files inside subdirectories using freopen:

freopen("output/output-1.txt", "w", stdout);

I have tried changing it to output to the current directory and it works. It terminates without errors when the target output file is in a subdirectory; however no files are created. Creating the required directory does not fix the issue.

void write_to(int subtask, int tc){
    string output = string("testcases/subtask-") + to_string(subtask) + "-tc-" + to_string(tc);
    freopen(output.c_str(), "w", stdout);
}

int main(){
    for(int i = 1; i <= 25; i++){
        write_to(1, i);
        // rest of code to generate and cout test cases
    }
}

Does anyone have a solution to this?


Solution

  • Read documentation of freopen(3). You should test and use its result:

    The freopen() function opens the file whose name is the string pointed to by path and associates the stream pointed to by stream with it. The original stream (if it exists) is closed.

    about its return value:

    Upon successful completion fopen(), fdopen() and freopen() return a FILE pointer. Otherwise, NULL is returned and errno is set to indicate the error.

    So you need to code at least (if on Linux or some POSIX system)

    void write_to(int subtask, int tc){
       string output = 
         string("testcases/subtask-") + to_string(subtask) 
          + "-tc-" + to_string(tc);
       FILE*outf = freopen(output.c_str(), "w", stdout);
       if (!outf) {
         perror(output.c_str());
         char pwdbuf[128];
         memset (pwdbuf, 0, sizeof(pwdbuf));
         getcwd(pwdbuf, sizeof(pwdbuf)-1);
         fprintf(stderr, "failure in %s\n", pwdbuf);
         exit(EXIT_FAILURE);
       }
    }
    

    (the code above won't solve your issue, but will output a meaningful error message on error; perhaps you are not running your code in the appropriate current directory)

    I also recommend ending your for loop in main with fflush(stdout) or fflush(NULL).

    If on Linux or POSIX, you might instead work at the file descriptor level (so code a redirection), and use open(2) & dup(2) (using STDOUT_FILENO as the second argument to dup2).

    If testcases is a directory in your $HOME (that is, ~/testcases/ as expanded by your shell) you would want

    string output =
      string (getenv("HOME")) + "/" 
      + string("testcases/subtask-") + to_string(subtask) 
      + "-tc-" + to_string(tc);