Computer368106 views
高校倫理1440106 views
高校物理160203 views
数学講師2886227 views
小学算数1200427 views
教育149510 views
高校日本史190571 views
いろは3010814 views
中学英語811710 views
高校化学2924392 views
Help
Tools
NewsSpreadsheetCalendarSlidesTier ListPen ToolIllustrationCrayonPixel ArtASCII ArtPerspectiveEndless StairsGraphMind MapER DiagramFamily TreeMemeCurved TextImage EditorMosaicRetro FilterPencil SketchOCR/HighlighterMakeup EditorFaviconVideo TrimmerScrolling VideoVideo TitleColor PickerColor ExtractorBonfireFireworksWater RippleWater SplashBreaking GlassWood GrainMarble TextureCSS ButtonIcon MakerBar ChartGrouped Bar ChartStacked Bar ChartPie ChartLine ChartArea ChartStacked Area ChartScatter Plot3D Bar Chart3D Pie ChartBar Chart RaceBubble ChartPopulation PyramidPictogramEarningsCandlestick ChartInvestment RiskMortgage SimulatorCalculatorMatrix CalculatorFunction GraphPolynomial ExpansionVenn DiagramField VisualizerRubik's Cube Group TheoryTraveling SalesmanVoronoi and DelaunayFractalColumn ArithmeticDraw Math FiguresArithmetic AnimationArithmetic Word ProblemsCounting with Tree DiagramsCube NetsCross SectionsMotion PathMechanicsWavesLight and LensesThermodynamicsHow Semiconductors WorkMolecular StructuresAtomic OrbitalsElectrochemical CellsChemical EquilibriumCrystal LatticesBuffer pHComplex IonsDNA Double HelixCell DivisionMembrane ChannelsNerve ImpulseRock ClassificationWeatherConstellationsSolar and Lunar Eclipses3D ModelingFloor PlanSeismic StructuresIntersection TurnMaglevCooking AnimationOrigamiLive Viewer CountGeoJSON MapRailway MapPopulation MapCrime MapLand Price MapSchool MapShrine and Castle MapHouse of Representatives MapWord MapSolitaireReversiHakoiri MusumeChessHamburgerRippleSlide Puzzle MakerNeon PinballNovel MakerJapanese Typing PracticePiano Score EditorMusic Theory

English

ファイルのアトミックな書き込み(中途半端な状態を残さない方法)

ファイルへの書き込み中にプログラムがクラッシュすると、ファイルが中途半端な状態で残ることがある。アトミック(不可分)な書き込みを行えば、書き込みが完全に成功するか、まったく行われないかのどちらかを保証できる。

問題のあるコード

# ❌ クラッシュすると壊れたファイルが残る
with open('config.json', 'w') as f:
    f.write('{"key": ')
    # ここでクラッシュすると不完全な JSON が残る
    f.write('"value"}')

この方法では、書き込み途中の不完全なファイルが残るリスクがある。

一時ファイルを使ったアトミック書き込み

基本的なパターンは、一時ファイルに書き込んでから、元のファイルにリネームすることだ。

import os
import tempfile

def atomic_write(filepath, content):
    # 同じディレクトリに一時ファイルを作成
    dir_name = os.path.dirname(filepath) or '.'
    
    with tempfile.NamedTemporaryFile(
        mode='w',
        dir=dir_name,
        delete=False
    ) as tmp:
        tmp.write(content)
        tmp_path = tmp.name
    
    # リネーム(アトミックな操作)
    os.replace(tmp_path, filepath)

# 使用例
atomic_write('config.json', '{"key": "value"}')

os.replace() は POSIX システムではアトミックな操作であり、書き込みが完全に成功するか、元のファイルがそのまま残るかのどちらかになる。

なぜリネームがアトミックなのか

ファイルシステムのリネーム操作は、メタデータ(ディレクトリエントリ)の更新だけで済むため、アトミックに実行できる。一方、ファイルの内容を直接書き換える場合は、複数のディスクブロックを更新する必要があり、途中で中断されるリスクがある。

同じファイルシステムに書く

os.replace() がアトミックに動作するには、一時ファイルと最終ファイルが同じファイルシステム上にある必要がある。異なるファイルシステム間では、コピー+削除になり、アトミック性が失われる。

# ✅ 同じディレクトリに一時ファイルを作成
with tempfile.NamedTemporaryFile(dir='/same/directory', delete=False) as tmp:
    pass

# ❌ /tmp は別のファイルシステムかもしれない
with tempfile.NamedTemporaryFile(delete=False) as tmp:  # /tmp に作成される
    pass
os.replace(tmp.name, '/home/user/data.txt')  # 別ファイルシステムだと非アトミック

fsync でディスクに確実に書き込む

OS のバッファに書き込んだだけでは、電源断でデータが失われる可能性がある。fsync() を呼ぶと、データが物理ディスクに書き込まれる。

import os
import tempfile

def atomic_write_safe(filepath, content):
    dir_name = os.path.dirname(filepath) or '.'
    
    with tempfile.NamedTemporaryFile(
        mode='w',
        dir=dir_name,
        delete=False
    ) as tmp:
        tmp.write(content)
        tmp.flush()
        os.fsync(tmp.fileno())  # ディスクに確実に書き込む
        tmp_path = tmp.name
    
    os.replace(tmp_path, filepath)
    
    # ディレクトリのメタデータも同期(より安全)
    dir_fd = os.open(dir_name, os.O_RDONLY)
    try:
        os.fsync(dir_fd)
    finally:
        os.close(dir_fd)

atomicwrites ライブラリを使う

atomicwrites ライブラリを使えば、これらの処理を簡潔に書ける。

pip install atomicwrites
from atomicwrites import atomic_write

with atomic_write('config.json', overwrite=True) as f:
    f.write('{"key": "value"}')
# 書き込みが成功した場合のみ、元のファイルが置き換わる

バックアップを残す

より安全にするため、上書き前にバックアップを残す方法もある。

import os
import shutil

def atomic_write_with_backup(filepath, content):
    backup_path = filepath + '.bak'
    
    # 既存ファイルがあればバックアップ
    if os.path.exists(filepath):
        shutil.copy2(filepath, backup_path)
    
    # アトミック書き込み
    atomic_write(filepath, content)