Every language
14 languages, copy-ready. One at a time with syntax highlighting, or all inline.
JSJavaScript
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
// A private temp DIRECTORY, not a bare file: an exclusive collision-proof
// name plus room for whatever else the task needs next to it.
const dir = await mkdtemp(join(tmpdir(), 'app-'));
const file = join(dir, 'work.txt');
try {
await writeFile(file, 'scratch data\n', 'utf8');
console.log(file);
// ...hand `file` to a child process, a test, a parser...
} finally {
// force: no throw if creation half-failed; recursive: takes the dir too
await rm(dir, { recursive: true, force: true });
}mkdtemp appends six random characters to the prefix and creates the directory with mode 0700 — never build temp names from Date.now() or process.pid. rm with force:true makes cleanup idempotent; without it a failed writeFile lets the finally block throw ENOENT and mask the real error. Sync twin: fs.mkdtempSync.
TSTypeScript
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
/** Run `fn` with a fresh temp file path; always remove it afterwards. */
async function withTempFile(
fn: (path: string) => Promise<void>,
): Promise<void> {
const dir = await mkdtemp(join(tmpdir(), 'app-'));
const path = join(dir, 'work.txt');
try {
await writeFile(path, 'scratch data\n', 'utf8');
await fn(path);
} finally {
await rm(dir, { recursive: true, force: true });
}
}
await withTempFile(async (path) => console.log(path));The finally block is the whole point — it runs when fn rejects too, so the temp directory never survives a task that died mid-flight. TS 5.2+ on Node 20 offers `await using` (Symbol.asyncDispose) as the structural alternative to the callback wrapper.
GoGo
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.CreateTemp("", "app-*.txt") // "" = os.TempDir(), exclusive create
if err != nil {
panic(err)
}
path := f.Name()
// LIFO: Close runs first, Remove second — required on Windows,
// where an open file cannot be unlinked.
defer os.Remove(path)
defer f.Close()
if _, err := f.WriteString("scratch data\n"); err != nil {
panic(err)
}
fmt.Println(path)
}os.CreateTemp replaced ioutil.TempFile; the * in the pattern marks where the random suffix lands (no * means append at the end). The ignored Remove error is deliberate best-effort — but treat the OS sweeping /tmp as a backstop, not the mechanism. os.MkdirTemp is the directory twin.
RsRust
use std::io::Write;
fn main() -> std::io::Result<()> {
let mut file = tempfile::NamedTempFile::new()?;
writeln!(file, "scratch data")?;
println!("temp file: {}", file.path().display());
// ...pass file.path() around — it is a real, visible path...
Ok(())
} // `file` drops here: closed AND unlinked, even on panic-unwindtempfile = "3" in Cargo.toml. Deletion is tied to Drop, so a ? early-return or a panicking thread still cleans up — exactly the property the manual languages rebuild with defer/finally. Call file.persist("final.txt") when the file must survive.
PHPPHP
<?php
// tmpfile(): exclusive name in the system temp dir + deletion
// registered for fclose() and script shutdown.
$fh = tmpfile();
if ($fh === false) {
throw new RuntimeException('tmpfile() failed');
}
// It returns a stream, not a path — recover the path like this:
$path = stream_get_meta_data($fh)['uri'];
fwrite($fh, "scratch data\n");
fflush($fh);
// ...rewind($fh) to read back, or pass $path to an external command...
fclose($fh); // removes the fileThe handle owns the file: fclose() (or script termination) deletes it, so there is no unlink to forget — and no way to keep the file except copying it. Need a path you control? tempnam(sys_get_temp_dir(), 'app-') creates an exclusive empty file you must unlink yourself.
PyPython
import tempfile
with tempfile.NamedTemporaryFile(
mode="w+", encoding="utf-8", delete=True
) as f:
f.write("scratch data\n")
f.flush() # contents now visible at f.name to other processes
print(f.name)
# leaving the with-block closes AND unlinks the filedelete=True is the default: close() unlinks. Pass delete=False when the file must outlive the handle — cleanup then becomes your job. On Windows the name cannot be reopened by other code while the handle is open (Linux: it can). tempfile.TemporaryFile is the anonymous variant with no portable name.
CC
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void) {
char path[] = "/tmp/app-XXXXXX"; /* template rewritten in place */
int fd = mkstemp(path); /* atomically: random name + O_EXCL open */
if (fd == -1) {
perror("mkstemp");
return 1;
}
dprintf(fd, "scratch data\n");
if (close(fd) == -1) { /* flush before anyone reads it */
perror("close");
}
unlink(path); /* must run on EVERY exit path */
return 0;
}mkstemp is the only race-free POSIX spelling — never tmpnam(), which hands back a name another process can create first. Real programs centralize close+unlink (or fdopen + fclose) in one helper so no error branch can skip the unlink. Windows CRT: _mktemp_s + _open(..., _O_CREAT | _O_EXCL).
C++C++
#include <filesystem>
#include <iostream>
#include <stdexcept>
#include <string>
#include <string_view>
#include <unistd.h>
namespace fs = std::filesystem;
// RAII over mkstemp: destructor closes + unlinks on every exit path,
// including exceptions. C++ has no std temp-file facility — POSIX creates.
class TempFile {
public:
explicit TempFile(const fs::path& pattern)
: path_(pattern.string()) {
fd_ = ::mkstemp(path_.data()); // rewrites the trailing XXXXXX
if (fd_ == -1) throw std::runtime_error("mkstemp failed");
}
~TempFile() {
if (fd_ != -1) ::close(fd_);
std::error_code ec;
fs::remove(path_, ec); // best-effort, never throws
}
TempFile(const TempFile&) = delete;
TempFile& operator=(const TempFile&) = delete;
void write(std::string_view bytes) {
if (::write(fd_, bytes.data(), bytes.size()) == -1)
throw std::runtime_error("write failed");
}
const std::string& path() const { return path_; }
private:
std::string path_;
int fd_ = -1;
};
int main() {
TempFile t(fs::temp_directory_path() / "app-XXXXXX");
t.write("scratch data\n");
std::cout << t.path() << '\n';
// ...pass t.path() to other code...
} // closed + unlinked hereC++17+ (non-const std::string::data(), <filesystem>). POSIX only — MSVC needs _mktemp_s/_open or a UUID-named file. The deleted copy constructor is load-bearing: a copied handle would close and unlink twice.
C#C#
using System;
using System.IO;
// GetTempFileName(): creates a ZERO-BYTE file and returns its path —
// the platform guarantees the name is fresh.
string path = Path.GetTempFileName();
try
{
File.WriteAllText(path, "scratch data");
Console.WriteLine(path);
// ...hand the path to another process or a test...
}
finally
{
File.Delete(path); // throws if the file is already gone — wrap if that can happen
}GetTempFileName cycles .tmp names and throws IOException once ~65k files sit in %TEMP% — long-running services prefer Path.Combine(Path.GetTempPath(), $"app-{Guid.NewGuid():N}.tmp") opened with FileShare.None. File.Delete on a missing path throws FileNotFoundException; catch it when failure paths may have removed the file already.
JvJava
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class CreateTempFile {
public static void main(String[] args) throws IOException {
Path tmp = Files.createTempFile("app-", ".txt"); // exclusive, in java.io.tmpdir
try {
Files.writeString(tmp, "scratch data\n");
System.out.println(tmp);
// ...pass tmp to other code...
} finally {
Files.deleteIfExists(tmp); // no throw if someone already removed it
}
}
}Files.createTempFile(prefix, suffix, dir) — omit the dir and it honors java.io.tmpdir. File.deleteOnExit() is the leaky alternative: it only fires at JVM exit, so app servers that run for months accumulate files. The attributes overload sets POSIX perms when the content is sensitive.
SwSwift
import Foundation
let fm = FileManager.default
// No mkstemp equivalent in Foundation: assemble a unique name yourself.
let url = fm.temporaryDirectory
.appendingPathComponent("app-\(UUID().uuidString).txt")
do {
try "scratch data".write(to: url, atomically: true, encoding: .utf8)
print(url.path)
// ...work with the file...
} catch {
fatalError("temp write failed: \(error)")
}
try? fm.removeItem(at: url) // idempotent; misses only a hard exitUUID names make collisions vanish, but creation is still not exclusive — for hostile temp directories open the file with O_EXCL via Darwin/Glibc's open(2) instead. atomically: true writes a sibling file then renames: exactly the durable pattern. In real code, factor this into a function so defer { try? fm.removeItem(at: url) } also covers thrown errors.
KtKotlin
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.writeText
// Scoped resource: creation, your block, teardown — in that order.
// finally guarantees the unlink even when the block throws.
fun <R> withTempFile(
prefix: String = "app-",
suffix: String = ".txt",
block: (Path) -> R,
): R {
val tmp = Files.createTempFile(prefix, suffix)
try {
return block(tmp)
} finally {
Files.deleteIfExists(tmp)
}
}
fun main() {
withTempFile { tmp ->
tmp.writeText("scratch data\n")
println(tmp)
}
}Same JVM semantics as the Java impl: createTempFile is exclusive and honors java.io.tmpdir. kotlin.io.path supplies the writeText/deleteIfExists extension sugar (kotlin-stdlib jdk7 variant, the default on the JVM).
RbRuby
require 'tempfile'
# Block form: closed AND unlinked when the block ends — however it exits.
Tempfile.create('app-') do |f|
f.write("scratch data\n")
f.flush # contents visible at f.path from here on
puts f.path # a real path — child processes can read it
end
# Tempfile.new is the manual spelling: close! unlinks at once, plain close
# leaves the file for a finalizer to remove later — too passive for servers.Tempfile.create yields a Tempfile whose path is a real file in Dir.tmpdir; on Windows it stays locked until the block ends. Inside the block is the only safe window to use f.path — after it returns the file is gone.
ZigZig
const std = @import("std");
pub fn main() !void {
// No mkstemp in std: build a unique name from OS randomness.
const name = try std.fmt.allocPrint(
std.heap.page_allocator,
"/tmp/app-{d}.txt",
.{std.crypto.random.int(u64)},
);
defer std.heap.page_allocator.free(name);
{
// .exclusive fails with error.PathAlreadyExists instead of
// clobbering — with 2^64 names, retrying is academic.
const f = try std.fs.createFileAbsolute(name, .{
.exclusive = true,
.truncate = false,
});
defer f.close();
try f.writeAll("scratch data\n");
std.debug.print("temp file: {s}\n", .{name});
}
std.fs.deleteFileAbsolute(name) catch |err| {
std.debug.print("cleanup failed: {s}\n", .{@errorName(err)});
};
}std.crypto.random pulls from the OS CSPRNG. /tmp is a POSIX assumption — read std.posix.getenv("TMPDIR") in production. Cleanup here is manual and does NOT run when a try above fails mid-way; a real helper takes a block (like the Kotlin impl) so defer ordering covers every path. Zig 0.12+ API spelling.