惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Help Net Security
J
Java Code Geeks
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
H
Hackread – Cybersecurity News, Data Breaches, AI and More
V
Visual Studio Blog
G
Google Developers Blog
V
V2EX
The Register - Security
The Register - Security
博客园 - 三生石上(FineUI控件)
云风的 BLOG
云风的 BLOG
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
博客园_首页
S
SegmentFault 最新的问题
博客园 - Franky
Martin Fowler
Martin Fowler
Stack Overflow Blog
Stack Overflow Blog
A
About on SuperTechFans
人人都是产品经理
人人都是产品经理
aimingoo的专栏
aimingoo的专栏
罗磊的独立博客
C
Check Point Blog
MyScale Blog
MyScale Blog
T
The Blog of Author Tim Ferriss
MongoDB | Blog
MongoDB | Blog
The GitHub Blog
The GitHub Blog
Last Week in AI
Last Week in AI
Microsoft Azure Blog
Microsoft Azure Blog
IT之家
IT之家
F
Fortinet All Blogs
Jina AI
Jina AI
P
Proofpoint News Feed
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
阮一峰的网络日志
阮一峰的网络日志
B
Blog
L
LangChain Blog
月光博客
月光博客
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
宝玉的分享
宝玉的分享
博客园 - 【当耐特】
T
Tailwind CSS Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Microsoft Security Blog
Microsoft Security Blog
WordPress大学
WordPress大学
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
B
Blog RSS Feed
博客园 - 聂微东
Hugging Face - Blog
Hugging Face - Blog
M
MIT News - Artificial intelligence
GbyAI
GbyAI

alexwlchan’s notes

Managing the caption of a photo with AppleScript (but not PhotoKit) Goodhart’s and Campbell’s Law are different Notes from The Cornishman No. 176 (Spring 2026) Notes from The Cornishman No. 176 (Spring 2026) GitUp can’t diff text files larger than 8MB Home Testing the width of a page on a mobile device using Playwright Disable AirPods charging notifications Start a Caddy server in a subprocess during a Python session Filter a list of JSON object based on a list of tags HOME_GET_ME_HOME is a Citymapper Shortcuts action The FileExistsError exception exposes a filename attribute The red-lined bubble snail Why can’t Python connect to example.com? Useful type hints for Python How to truncate the middle of long command output AirPlay Receiver can interfere with Flask apps What’s the main prefix in SQLite queries? The file(1) command can read SQLite databases My randline project is tested by Crater Drawing an image with Liquid Glass using SwiftUI Previews Road signs in the Soviet union don’t have circular heads Setting up golink in my personal tailnet Get a map of IP addresses for devices in my tailnet The SQLite command line shell will count your unclosed parentheses Use SQL triggers to prevent overwriting a value Testing date formatting with date-fns-tz and different timezones The “strangler” pattern is named after a tree, not an act of violence Place with the same name, but different etymology
Create a file atomically in Go
2026-02-22 · via alexwlchan’s notes

Use os.CreateTemp to create a temporary file in the target directory, then do an atomic rename once you’ve finished writing.

Here’s an interesting function from the Tailscale repos that Anton told me about in a code review last week: a function to write to a file atomically. This ensures you don’t get partially written data in the final file.

10import (

11 "fmt"

12 "os"

13 "path/filepath"

14 "runtime"

15)

16

17// WriteFile writes data to filename+some suffix, then renames it into filename.

18// The perm argument is ignored on Windows, but if the target filename already

19// exists then the target file's attributes and ACLs are preserved. If the target

20// filename already exists but is not a regular file, WriteFile returns an error.

21func WriteFile(filename string, data []byte, perm os.FileMode) (err error) {

22 fi, err := os.Stat(filename)

23 if err == nil && !fi.Mode().IsRegular() {

24 return fmt.Errorf("%s already exists and is not a regular file", filename)

25 }

26 f, err := os.CreateTemp(filepath.Dir(filename), filepath.Base(filename)+".tmp")

27 if err != nil {

28 return err

29 }

30 tmpName := f.Name()

31 defer func() {

32 if err != nil {

33 f.Close()

34 os.Remove(tmpName)

35 }

36 }()

37 if _, err := f.Write(data); err != nil {

38 return err

39 }

40 if runtime.GOOS != "windows" {

41 if err := f.Chmod(perm); err != nil {

42 return err

43 }

44 }

45 if err := f.Sync(); err != nil {

46 return err

47 }

48 if err := f.Close(); err != nil {

49 return err

50 }

51 return Rename(tmpName, filename)

52}

Lines 10–52 of atomicfile/atomicfile.go in the tailscale/tailscale repo. Copyright Tailscale Inc & contributors, used under the BSD-3-Clause license.

This is similar to code I’ve produced in other projects to do atomic file writes – write to a temporary file first, then do an atomic rename to the final destination.

The temporary file is created in the same directory as the target, to give the best chance of being able to do an atomic rename. You can’t do an atomic rename across filesystem boundaries; using the same directory ensures both files are on the same filesystem.

To handle concurrent writes, I normally insert a random UUID into the temporary filename, so different processes write to different tempfiles. This is handled automatically by Go’s os.CreateTemp function, which adds a random string to the end of the filename.

The Rename() function has different logic for Windows and non-Windows systems:

  • On non-Windows, it uses os.Rename(). The Go documentation notes that “even within the same directory, on non-Unix platforms Rename is not an atomic operation”.
  • On Windows, it makes a syscall to the ReplaceFileW function. A cursory Internet search is conflicted on whether this is a truly atomic rename, although concurs that it’s the best option on Windows.