Every language
14 implementations, copy-ready. One at a time with syntax highlighting, or all inline.
JSJavaScript
import { copyFile, rename, constants } from 'node:fs/promises';
// Copy — the source stays put; the destination is overwritten.
await copyFile('report.pdf', 'report-backup.pdf');
// Move — one atomic rename when both paths share a filesystem.
await rename('inbox/report.pdf', 'archive/report.pdf');copyFile clobbers an existing destination by default — pass constants.COPYFILE_EXCL as the third argument to make it refuse instead. rename is rename(2): across filesystems (a tmpfs /tmp, another volume) it rejects with EXDEV, so fall back to copyFile + unlink.
TSTypeScript
import { copyFile, rename } from 'node:fs/promises';
const src = 'report.pdf';
const backup = 'report-backup.pdf';
await copyFile(src, backup);
await rename(src, `archive/${src}`);Identical runtime to the JavaScript version — the bindings just pin the paths. Both promises reject on failure (ENOENT for a missing source), so wrap the pair in try/catch: without it, a failed copy can still see the source renamed away.
GoGo
package main
import (
"io"
"os"
)
func copyFile(src, dst string) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, in)
return err
}
func main() {
if err := copyFile("report.pdf", "report-backup.pdf"); err != nil {
panic(err)
}
if err := os.Rename("inbox/report.pdf", "archive/report.pdf"); err != nil {
panic(err)
}
}os.Rename is atomic and replaces the destination on Unix; across filesystems it returns a *LinkError wrapping EXDEV — then copy and os.Remove. os.Create truncates an existing destination, and io.Copy uses copy_file_range/sendfile on Linux when it can.
RsRust
use std::fs;
fn main() -> std::io::Result<()> {
// Copy — returns the byte count; keeps the mode but not the mtime.
fs::copy("report.pdf", "report-backup.pdf")?;
// Move — one rename on the same filesystem.
fs::rename("inbox/report.pdf", "archive/report.pdf")?;
Ok(())
}fs::rename overwrites an existing destination on Unix but fails across filesystems — io::ErrorKind::CrossesDevices since Rust 1.85 — where the fallback is fs::copy followed by fs::remove_file. fs::copy transfers permission bits only; timestamps and xattrs are lost.
PHPPHP
<?php
// Copy — overwrites an existing destination.
if (!copy('report.pdf', 'report-backup.pdf')) {
fwrite(STDERR, "copy failed\n");
}
// Move — rename() doubles as the move; overwrites files, not directories.
if (!rename('inbox/report.pdf', 'archive/report.pdf')) {
fwrite(STDERR, "rename failed\n");
}Both return false with a warning instead of throwing — check the return, or set_error_handler to convert them to exceptions. rename() needs write access to both directories; on failure the source is left untouched. copy() truncates an existing destination.
PyPython
import shutil
# Copy — copy2 keeps permissions, mtime, and extended attributes.
shutil.copy2("report.pdf", "report-backup.pdf")
# Move — rename when possible, copy+delete across filesystems.
shutil.move("inbox/report.pdf", "archive/report.pdf")shutil.move never leaves you holding EXDEV — when os.rename fails across devices it falls back to copy2 plus os.unlink. os.rename is the raw atomic primitive (same-filesystem only); copy2 overwrites an existing destination file, and shutil.copytree is the directory counterpart.
CC
#define _POSIX_C_SOURCE 200809L
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int copy_file(const char *src, const char *dst) {
int in = open(src, O_RDONLY);
if (in < 0) return -1;
int out = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (out < 0) {
close(in);
return -1;
}
char buf[65536];
ssize_t n;
while ((n = read(in, buf, sizeof buf)) > 0) {
char *p = buf;
while (n > 0) {
ssize_t w = write(out, p, (size_t)n);
if (w < 0) {
close(in);
close(out);
return -1;
}
p += w;
n -= w;
}
}
if (n < 0) {
close(in);
close(out);
return -1;
}
close(in);
return close(out) == 0 ? 0 : -1;
}
int main(void) {
if (copy_file("report.pdf", "report-backup.pdf") != 0) {
perror("copy_file");
return 1;
}
if (rename("inbox/report.pdf", "archive/report.pdf") != 0) {
perror("rename");
return 1;
}
return 0;
}ISO C defines no file copy, so the portable answer is this POSIX read/write loop through a 64 KiB buffer — Linux sendfile(2) is the faster shortcut. rename(2) is atomic and overwrites an existing destination file, but fails with EXDEV across filesystems, where the fallback is copy plus unlink().
C++C++
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
std::error_code ec;
fs::copy_file("report.pdf", "report-backup.pdf",
fs::copy_options::overwrite_existing, ec);
if (ec) std::cerr << "copy: " << ec.message() << '\n';
fs::rename("inbox/report.pdf", "archive/report.pdf", ec);
if (ec) std::cerr << "move: " << ec.message() << '\n';
}C++17 std::filesystem. The error_code overload reports failures instead of throwing fs::filesystem_error; copy_options::skip_existing and update_existing are the alternatives to overwrite_existing. rename() maps to rename(2) on POSIX — atomic, replaces an existing regular file, but fails across volumes.
C#C#
using System.IO;
// Copy — overwrite: true replaces an existing destination; false throws.
File.Copy("report.pdf", "report-backup.pdf", overwrite: true);
// Move — an atomic rename on the same volume.
File.Move("inbox/report.pdf", "archive/report.pdf");File.Move without the overwrite overload throws IOException when the destination exists; File.Move(src, dest, overwrite: true) landed in .NET Core 3.0. On Windows the source must not be open — a held FileStream locks it. File.Replace(src, dest, backup) is the atomic swap when you want the old file kept.
JvJava
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
public class CopyMoveFile {
public static void main(String[] args) throws IOException {
Path src = Path.of("report.pdf");
Files.copy(src, Path.of("report-backup.pdf"),
StandardCopyOption.REPLACE_EXISTING);
Files.move(src, Path.of("archive/report.pdf"),
StandardCopyOption.REPLACE_EXISTING);
}
}Without REPLACE_EXISTING both throw FileAlreadyExistsException. ATOMIC_MOVE demands rename semantics — with it, all other options are ignored, and a store that cannot comply throws AtomicMoveNotSupportedException. The legacy File.renameTo reports failure as a silent false; don't use it.
SwSwift
import Foundation
let fm = FileManager.default
// Copy — throws if the destination already exists.
try fm.copyItem(atPath: "report.pdf", toPath: "report-backup.pdf")
// Move — Foundation has no overwrite flag, so clear the way first.
try? fm.removeItem(atPath: "archive/report.pdf")
try fm.moveItem(atPath: "inbox/report.pdf", toPath: "archive/report.pdf")copyItem and moveItem refuse to clobber — there is no overwrite option, hence the try? removeItem, which tolerates a not-found file. moveItem crosses volumes fine (it copies then deletes the source), unlike raw rename(2).
KtKotlin
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption
fun main() {
val src = File("report.pdf")
src.copyTo(File("report-backup.pdf"), overwrite = true)
Files.move(src.toPath(), Path.of("archive/report.pdf"), StandardCopyOption.REPLACE_EXISTING)
}copyTo is kotlin.io's File extension over java.nio's Files.copy — without overwrite = true it throws FileAlreadyExistsException. The move goes through Files.move because File.renameTo() reports failure as a bare false with no reason attached.
RbRuby
require 'fileutils'
FileUtils.cp('report.pdf', 'report-backup.pdf') # overwrites quietly
FileUtils.mv('inbox/report.pdf', 'archive/report.pdf') # rename, or copy+unlinkFileUtils.mv is a rename within one filesystem and degrades to copy then unlink across them; cp clobbers an existing destination without complaint. Pass preserve: true to carry over permissions and timestamps; cp_r is the recursive version.
ZigZig
const std = @import("std");
pub fn main() !void {
const cwd = std.fs.cwd();
// Copy — refuses to clobber an existing destination.
try cwd.copyFile("report.pdf", cwd, "report-backup.pdf", .{});
// Move — a rename, cheap when both paths share a filesystem.
try cwd.rename("inbox/report.pdf", "archive/report.pdf");
}Stdlib only. copyFile defaults to overwrite_existing = false — pass .{ .overwrite_existing = true } to replace an existing destination. rename wraps rename(2): it overwrites on POSIX but fails with error.PathAlreadyExists on Windows, and crossing filesystems returns error.RenameAcrossMountPoints.