25

I'm using tempfile() within a function in a package, so users will be creating new files. I do not want to leave a mess behind.

Does R automatically delete files created in the directory accessed with tempfile(), or must these be deleted manually?

If files are automatically removed, on what basis does this occur (e.g. end of R session, after closing RStudio, after some time interval, or something else?)

Obviously it's not hard to delete them with some extra code (related post: https://stackoverflow.com/a/56715074/680068), but I will avoid that if they are automatically taken care of with some existing process.

zx8754
  • 52,746
  • 12
  • 114
  • 209
stevec
  • 41,291
  • 27
  • 223
  • 311
  • 9
    I can’t believe that this isn‘t clearly stated in the documentation. But I can’t find it there. – Konrad Rudolph Sep 25 '19 at 09:25
  • 1
    @jay.sf That question doesn’t answer this one. – Konrad Rudolph Sep 25 '19 at 09:28
  • maybe its in a `.Last.sys` function: from `?quit`: `There is a system analogue, .Last.sys(), which is run after .Last() if runLast is true.` – chinsoon12 Sep 25 '19 at 10:06
  • an unanswered rstudio server qn: https://community.rstudio.com/t/rstudio-server-doesnt-delete-rtmp-folders/37648 – chinsoon12 Sep 25 '19 at 10:10
  • 1
    I do know that all files placed in the (default) `tempdir()` will be cleaned up, along with the directory when the R session is closed normally. A crash will not clean this directory up. So if your R sessions are prone to crashing, you might want to clean the files up with unlink, otherwise R should clean up the files. Of course if the files are large you might want to do the cleaning yourself anyway as soon as they are not needed anymore. – phiver Sep 25 '19 at 10:21
  • @phiver Sure — but where is this documented? – Konrad Rudolph Sep 25 '19 at 10:30
  • 3
    @KonradRudolph, it is not in the official documentation. I only know this due to the use in the quantmod package and debugging some functions that download data into the tempdir, but the closest I can find to any explanation is [this blogpost](http://rstat.consulting/blog/temporary-dir-and-files-in-r/). – phiver Sep 25 '19 at 12:13
  • this is a shot in the dark, but because it is in a function can you wrap your code in `local()` to evaluate locally ? I am not sure if this would work when creating files - but it does work when creating variables in R. – Mike Feb 24 '20 at 22:02

2 Answers2

19

(All this assumes you are using the default argument for tmpdir and the TEMP environment variable is set normally for your operating system.)

tl;dr Temporary files are deleted whenever R_CleanTempDir runs (as when the R session terminates)

The temporary files are deleted by deleting the temporary directory tempdir(). This occurs via the internal function R_CleanTempDir (link points to a unix implementation). This can be invoked through a variety of instances, but the most usual case is via quit (see below for the full chain). To answer your question, the temporary files will be deleted under a "normal" quit of the R session. (The "normal" is there to avoid things like a power failure at an inopportune time, plus "suicides".)

Indeed this is mentioned in the helpfile for ?quit:

Exactly what happens at termination of an R session depends on the platform and GUI interface in use. A typical sequence is to run .Last() and .Last.sys() (unless runLast is false), to save the workspace if requested (and in most cases also to save the session history: see savehistory), then run any finalizers (see reg.finalizer) that have been set to be run on exit, close all open graphics devices, remove the session temporary directory and print any remaining warnings (e.g., from .Last() and device closure).

As suggested in that helpfile, you may want to see if reg.finalizer would be helpful for your issue.

In some circumstances tempdir() may be deleted during long-running R session, but to guarantee deletion of temporary files you must explicitly remove them in the session or quit the session.


do_quit

SEXP attribute_hidden do_quit(SEXP call, SEXP op, SEXP args, SEXP rho)
{
    const char *tmp;
    SA_TYPE ask=SA_DEFAULT;
    int status, runLast;

    checkArity(op, args);
    /* if there are any browser contexts active don't quit */
    if(countContexts(CTXT_BROWSER, 1)) {
    warning(_("cannot quit from browser"));
    return R_NilValue;
    }
    if( !isString(CAR(args)) )
    error(_("one of \"yes\", \"no\", \"ask\" or \"default\" expected."));
    tmp = CHAR(STRING_ELT(CAR(args), 0)); /* ASCII */
    if( !strcmp(tmp, "ask") ) {
    ask = SA_SAVEASK;
    if(!R_Interactive)
        warning(_("save=\"ask\" in non-interactive use: command-line default will be used"));
    } else if( !strcmp(tmp, "no") )
    ask = SA_NOSAVE;
    else if( !strcmp(tmp, "yes") )
    ask = SA_SAVE;
    else if( !strcmp(tmp, "default") )
    ask = SA_DEFAULT;
    else
    error(_("unrecognized value of 'save'"));
    status = asInteger(CADR(args));
    if (status == NA_INTEGER) {
    warning(_("invalid 'status', 0 assumed"));
    status = 0;
    }
    runLast = asLogical(CADDR(args));
    if (runLast == NA_LOGICAL) {
    warning(_("invalid 'runLast', FALSE assumed"));
    runLast = 0;
    }
    /* run the .Last function. If it gives an error, will drop back to main
       loop. */
    R_CleanUp(ask, status, runLast);
    exit(0);
    /*NOTREACHED*/
}

invokes R_CleanUp which invokes R_CleanTempDir:

void R_CleanUp(SA_TYPE saveact, int status, int runLast)
{
    if(saveact == SA_DEFAULT) /* The normal case apart from R_Suicide */
    saveact = SaveAction;

    if(saveact == SA_SAVEASK) {
    if(R_Interactive) {
        switch (R_YesNoCancel(G_("Save workspace image?"))) {
        case YES:
        saveact = SA_SAVE;
        break;
        case NO:
        saveact = SA_NOSAVE;
        break;
        case CANCEL:
        // There might be residual events with destroyed handles
        R_ProcessEvents();
        jump_to_toplevel();
        break;

        }
    } else saveact = SaveAction;
    }

    switch (saveact) {
    case SA_SAVE:
    if(runLast) R_dot_Last();
    if(R_DirtyImage) R_SaveGlobalEnv();
    if (CharacterMode == RGui) {
        R_setupHistory(); /* re-read the history size and filename */
        wgl_savehistory(R_HistoryFile, R_HistorySize);
    } else if(R_Interactive && CharacterMode == RTerm) {
        R_setupHistory(); /* re-read the history size and filename */
        gl_savehistory(R_HistoryFile, R_HistorySize);
    }
    break;
    case SA_NOSAVE:
    if(runLast) R_dot_Last();
    break;
    case SA_SUICIDE:
    default:
    break;
    }
    R_RunExitFinalizers();
    editorcleanall();
    CleanEd();
    KillAllDevices(); /* Unix does not do this under SA_SUICIDE */
    AllDevicesKilled = TRUE; /* used in devWindows.c to inhibit callbacks */
    R_CleanTempDir(); /* changes directory */
    if (R_Interactive && CharacterMode == RTerm)
    SetConsoleTitle(oldtitle);
    if (R_CollectWarnings && saveact != SA_SUICIDE
    && CharacterMode == RTerm)   /* no point in doing this for Rgui
                    as the console is about to close */
    PrintWarnings();        /* from device close and (if run) .Last */
    app_cleanup();
    RConsole = NULL;
    // Add some protection against calling this more than once:
    // caused by signals on Unix, so maybe cannot happen here.
    if(ifp) { 
    fclose(ifp);    /* input file from -f or --file= */
    ifp = NULL; 
    }
    if(ifile[0]) {
    unlink(ifile); /* input file from -e */
    ifile[0] = '\0';
    }
    exit(status);
}
Hugh
  • 15,521
  • 12
  • 57
  • 100
-1

By default, the function uses the temp directory returned by tempdir() which returns a path to the system temp directory. So it is controlled by the OS. If you use a different directory, I guess you will have to clean it yourself.

Pavel Obraztcov
  • 338
  • 1
  • 6