ここまでの4回で、I/O要求がどう流れ(第1〜3回)、キャッシュがどう受け止めるか(第4回)を見てきました。要求は最後にファイルシステムへ届きます。今回はその代表、NTFSの番です。
視点が変わります。これまでは「要求の流れ」という動的な話でした。今回はディスクの上にデータがどう置かれているかという静的な構造の話です。ダウンロードしたファイルに付く見えない「Zone.Identifier」の正体。小さいファイル1万個のコピーが、同じ合計サイズの1ファイルよりずっと遅い理由。「NTFSはジャーナリングだから安心」がどこまで本当か──全部この構造から説明できます。
連載「Windows I/Oの深層」の第5回です。
1. まず結論
- NTFSの中心はMFT(マスターファイルテーブル)です。全ファイルがMFT内のレコードとして台帳管理され、ファイルに関するすべての情報は「MFTエントリの中」か「エントリが指すMFT外の領域」にあります(2章)。1
- ファイルの実体は「属性の集合」です。小さいファイルはデータ本体ごとMFTレコード内に収まり(常駐)、大きいファイルはクラスター列への参照だけを持ちます(非常駐)。小ファイル大量処理の遅さはここから説明できます(2章)。1
- データは複数持てます(複数データストリーム)。普段のデータは「名前のないストリーム」で、
file.txt:名前で追加のストリームを持てます。Zone.Identifier(Mark of the Web)の正体です(3章)。2 - 名前も属性です。同じレコードに複数の名前を付けたものがハードリンク。8.3短縮名も「もう一つの名前」として同居しています(4章)。34
- リパースポイントは「開いたら別の場所」の公式な仕掛けです。シンボリックリンク・ジャンクション・OneDrive のファイルオンデマンドは、みなこのタグ付きデータの応用です(5章)。56
- ジャーナルは2つあります。
$LogFileはメタデータ整合性の回復用(壊れないための先行ログ)、USNジャーナルは変更履歴の記録用(何が変わったかの台帳)。役割がまったく違います(6章)。78 - 「サイズ」と「ディスク上のサイズ」は別物です。スパースファイルと圧縮が乖離を生みます。第2回で見た「圧縮ファイルは非同期にならない」の背景もここにあります(7章)。910
2. すべてはMFTのレコードである
2.1. ボリュームの台帳
NTFSボリュームをフォーマットすると、MFT(master file table)と、$ で始まる一連のメタデータファイルが作られます。MFTには、ボリューム上のすべてのファイルについて少なくとも1つのエントリがあり、MFT自身のエントリも含まれます。1
flowchart TB
subgraph VOL["NTFSボリューム"]
MFT["$MFT ── マスターファイルテーブル<br/>全ファイルのレコードの台帳(自分自身も載っている)"]
LOG["$LogFile ── メタデータ操作の<br/>トランザクションログ(6章)"]
BITMAP["$Bitmap ── クラスターの使用状況"]
OTH["$Boot / $Secure / $UpCase など<br/>その他のメタデータファイル"]
DATA["ユーザーデータ領域<br/>(非常駐データの置き場所)"]
end
MFT -->|"レコードが位置を指す"| DATA
図1: NTFSボリュームの構造。「ファイルシステム自身の管理情報もファイルとして持つ」のがNTFSの設計
ファイルに関する情報──サイズ、タイムスタンプ、アクセス許可、そしてデータの内容まで──は、MFTエントリの中に格納されるか、MFTエントリが位置を記述するMFT外の領域に格納されます。1 ファイルを削除するとエントリは「空き」としてマークされ再利用されますが、MFT自体は縮みません。また、MFTを連続的に保つためにMFTゾーンという領域が予約されており、ボリュームが埋まってくるとMFTの断片化が始まる──という寿命の話まで、公式ドキュメントに書かれています。1
2.2. ファイル=属性の集合、常駐と非常駐
ファイルレコードの中身は属性のリストです。標準情報(タイムスタンプ等)、ファイル名、セキュリティ、そしてデータ。ここで大事な分岐があります。
flowchart TB
subgraph REC["MFTファイルレコード(1ファイルぶんの台帳)"]
STD["標準情報属性<br/>タイムスタンプ・属性フラグ"]
FN["ファイル名属性<br/>(複数持てる ── 4章)"]
DATA["データ属性"]
end
Q{"データは小さいか"}
RES["常駐(resident)<br/>データ本体がレコード内に収まる<br/>読み出しはMFTアクセスだけで完結"]
NONRES["非常駐(non-resident)<br/>レコードには「クラスター列への参照」だけ<br/>実データはユーザーデータ領域に"]
DATA --> Q
Q -->|"数百バイト程度まで"| RES
Q -->|"それ以上"| NONRES
図2: ファイルレコードは属性の集合。データが小さければレコード内に「常駐」する
この構造から、現場で出会う現象がいくつも説明できます。
- 小ファイル1万個のコピーが遅い理由。1ファイルごとにMFTレコードの作成・名前の登録・セキュリティ設定というメタデータ操作が発生します。データ転送そのものより台帳仕事が支配的になるのです(そしてその1つ1つが、第6回で見るフィルターの検査対象にもなります)。
- 断片化の正体。非常駐データは「クラスターの連続区間(ラン)の列」として記録されます。連続領域が取れないとランの数が増え、読み出しに必要なシークが増える──これが断片化です。ランの実際の並びは
fsutil file layoutで覗けます。 - 「フォルダー」も特別ではない。ディレクトリは「ファイル名からMFTレコード番号への索引(インデックス)を持つファイル」です。台帳の上では、すべてが同じ仕組みの上に乗っています。
3. データは「ストリーム」の1つにすぎない
3.1. 1つのファイル、複数のバイト列
NTFSでは、1つのファイルが複数のデータストリームを持てます。普段 ReadFile/WriteFile で読み書きしているのは名前のない既定ストリームで、ファイル名:ストリーム名 という構文で代替データストリーム(ADS)を作れます。2
flowchart LR
subgraph F["report.docx というファイル(1つのMFTレコード)"]
D0["既定ストリーム(無名)<br/>= 普段見ている中身"]
D1[":Zone.Identifier<br/>出所情報(Mark of the Web)"]
D2[":任意の名前<br/>アプリ独自の付加情報"]
end
図3: 複数データストリーム。エクスプローラーのサイズ表示に出るのは既定ストリームだけ
いちばん身近なADSが Zone.Identifier です。ブラウザーでダウンロードしたファイルには、このストリームに出所(インターネット由来である等)が記録され、SmartScreenの「WindowsによってPCが保護されました」やOfficeの保護ビューの判定材料になります。この仕組みの表側は「Windowsで「Windows によって PC が保護されました」が出る理由」で扱いました──裏側の正体は、ただのNTFSストリームだったわけです。
3.2. 開発者が踏む落とし穴
- 見えない。エクスプローラーのサイズにも
dirの一覧にも出ません。dir /rかSysinternalsのstreamsで確認できます。11 - 運べない。ADSはNTFSの機能なので、FATのUSBメモリやクラウドストレージ経由のコピーでは失われがちです。「ダウンロード警告がコピーしたら消えた」はこれです。
- 自分のアプリでも開ける。
CreateFile("data.txt:meta", ...)のようにパスにコロンを含めるだけで読み書きできます。2 便利ですが、前項の「運べない」性質ごと引き受けることになるため、業務データの本体を入れる場所ではありません。
4. 名前もまた属性である ── ハードリンクと8.3名
4.1. ハードリンク ── 同じレコードへの複数の名前
図2で「ファイル名属性は複数持てる」と書きました。同一ボリューム内で、複数のパスが単一のファイルを参照する──これがハードリンクです(CreateHardLink / mklink /H)。3
flowchart TB
subgraph DIR1["C:\app\ のインデックス"]
E1["config.json → レコード#1234"]
end
subgraph DIR2["C:\backup\ のインデックス"]
E2["config-link.json → レコード#1234"]
end
REC["MFTレコード#1234<br/>データ本体(またはランへの参照)<br/>リンク数: 2"]
E1 --> REC
E2 --> REC
図4: ハードリンク。ディレクトリの索引が同じMFTレコードを指しているだけで、どちらも「本物」
どの名前から変更しても同じファイルなので内容は即座に一致します。3 そして「削除」の意味が変わります──DeleteFile は「名前を1つ外す」であり、最後の名前が外れ、開いているハンドルが閉じ、さらにメモリマップのセクションなどカーネル内の参照もすべて消えたときに初めて実体が消えます。第1回で見たcleanup(最後のハンドル)とclose(最後の参照)の2段階が、削除の寿命にもそのまま効いているわけです。なお属性の表示には癖があり、あるリンク経由で属性を変えても他のリンクの見かけ上の表示が古いまま、といった挙動が公式に注記されています。3
4.2. 8.3名 ── もう一つの隠れた名前
歴史的互換性のため、NTFSは長いファイル名に対して REPORT~1.DOC のような8.3形式の短縮名を自動生成できます。これも「もう一つの名前」としてレコードに同居します。大量のファイルがあるフォルダーでは短縮名の生成・衝突回避がコストになるため、fsutil 8dot3name で生成の無効化や既存短縮名の除去ができます(レジストリパスを短縮名で記録している古いアプリがあると壊れるので、strip前の検査機能があるのも実務的なポイントです)。4
パスと名前をめぐる落とし穴(MAX_PATH、予約名、末尾ドット)は「MAX_PATHとWindowsのパス・ファイル名の落とし穴」で詳しく扱っています。第1回の名前解決(オブジェクトマネージャー)とこの章(ファイルシステム内の名前)を合わせると、Windowsの「名前」の全体像になります。
5. リパースポイント ── 「開いたら別の場所」の仕掛け
ファイルやディレクトリにはリパースポイントを付けられます。実体は「タグ+ユーザー定義データ」という属性です。ファイルシステムがリパースポイント付きのファイルを開くと、タグに応じて処理が乗っ取られます──タグを理解するフィルタードライバーが処理を引き受けるか、名前の付け替え系のタグならリンク先のパスで解決がやり直されます。5
sequenceDiagram
participant App as アプリ
participant IOM as I/Oマネージャー
participant FS as NTFS
App->>IOM: CreateFile("C:\data\link.txt")
IOM->>FS: IRP_MJ_CREATE(第1回の世界)
Note over FS: 対象にリパースポイント発見<br/>タグとデータを返す
alt シンボリックリンク/ジャンクション(名前の付け替え)
FS-->>IOM: 「本当の場所はこちら」
IOM->>FS: リンク先のパスで解決をやり直す
else フィルター管理のタグ(クラウドファイル等)
Note over FS: タグを理解するフィルターが<br/>処理を引き受ける(第6回)
end
図5: リパースポイントの解決。「開く」という操作に割り込む公式のフックになっている
この1つの仕掛けの上に、見慣れた機能が並んでいます。
- シンボリックリンク(
mklink)──リンク先パスを保持する標識。別ボリュームやUNCパスも指せます。6 - ジャンクション/マウントポイント──ディレクトリを別のローカルボリュームの位置へつなぐ古参の仕組み。3
- OneDriveのファイルオンデマンド──実データが手元にないファイルをリパースポイントで表現し、開かれた瞬間にフィルターがダウンロードして中身を差し出します。「エクスプローラーには見えるのに、開くと通信が走る」の正体です(フィルターの仕組み自体は第6回で)。
実務の注意はひとつ。「パスの先が本当にローカルのその場所とは限らない」ことです。再帰的にツリーを辿るツールがジャンクションでループする、サイズ集計が二重になる、バックアップがクラウドの実体化を大量に引き起こす──リパースポイントの存在を知らないコードは、これらを踏みます。FindFirstFile 系の属性 FILE_ATTRIBUTE_REPARSE_POINT の確認が対策の入口です。5
6. 2つのジャーナル ── $LogFileとUSN
「NTFSはジャーナリングファイルシステム」とよく言われますが、NTFSには役割の違う2つのジャーナルがあります。混同すると保証を読み違えます。
flowchart TB
subgraph J1["$LogFile ── 先行ログ(壊れないため)"]
A1["メタデータ操作(レコード更新・名前変更等)を<br/>実行前にログへ記録"]
A2["システム障害後の次回起動時に<br/>ログを再生して構造の整合性を回復"]
A1 --> A2
end
subgraph J2["USNジャーナル ── 変更履歴(何が変わったかを知るため)"]
B1["ファイル/ディレクトリへの変更のたびに<br/>変更内容と名前を記録"]
B2["バックアップ・検索インデックス・同期ツールが<br/>「前回から何が変わったか」を全走査なしで把握"]
B1 --> B2
end
図6: 2つのジャーナル。$LogFileは「壊さない」ため、USNは「変更を知る」ため
$LogFile(トランザクションログ)は、メタデータ操作の先行ログです。システム障害が起きても、NTFSは次回起動時にこのログとチェックポイント情報からファイルシステムの整合性を自動回復します。7 ここで守られるのは構造です。第4回で見たとおり、キャッシュ上のダーティなデータ内容は電源断で失われうる──「ボリュームは壊れない。しかし最後の書き込みは消えうる」が正しい読み方です。- USNジャーナル(変更ジャーナル)は、ボリューム内のファイルやディレクトリに変更が起きるたびに、変更の内容と対象の名前を記録していく台帳です。8 バックアップやインデクサーが「前回から変わったものだけ」を全走査なしで拾うための仕組みで、障害後のインデックス再構築の回避にも使われます。8 実務では、
FileSystemWatcherの取りこぼし(「FileSystemWatcher実務ガイド」)を補う突き合わせ台帳としてfsutil usn readjournalを調査に使えることを覚えておくと役立ちます。
7. スパースと圧縮 ── 「サイズ」が二つある話
NTFSでは、ファイルの論理的な長さと実際に割り当てられた領域が別々に管理されます。プロパティ画面の「サイズ」と「ディスク上のサイズ」です。乖離を生む代表が2つあります。
スパースファイルは、ゼロが続く範囲に実領域を割り当てず「穴」として管理します。9 論理サイズ42GBの仮想ディスクファイルが、ディスク上では500MBしか使っていない──が普通に起こります。穴を読めばゼロが返り、書けばそのぶんだけ割り当てられます。
flowchart LR
subgraph L["論理的なファイル(サイズ: 1GB)"]
R1["データ 10MB"]
H1["穴(ゼロ) 500MB"]
R2["データ 5MB"]
H2["穴(ゼロ) 残り"]
end
subgraph P["ディスク上の割り当て(15MB+管理情報)"]
A1["ラン: R1の実体"]
A2["ラン: R2の実体"]
end
R1 --> A1
R2 --> A2
図7: スパースファイル。「穴」には割り当てが無く、論理サイズとディスク上のサイズが乖離する
NTFS圧縮は、データを圧縮ユニット単位で圧縮して格納します。10 透過的で便利ですが、コストも透過的ではありません──読み書きのたびに展開・再圧縮が走り、断片化も進みやすくなります。そして第2回5章で見たとおり、圧縮ファイルへのアクセスは非同期になりません(ファイルシステムが同期に変換します)。「非同期I/Oにしたのに速くならないファイルがある」ときに疑う場所の一つです。
割り当てベースの実サイズは GetCompressedFileSize で取得できます。「ファイルサイズの合計」と「ディスク使用量」が合わない調査では、スパース・圧縮・ADS(3章)・クラスター切り上げの4つを順に疑うのが定石です。
8. 自分の目で確かめる
今回も、手元のWindowsですべて観察できます(一部は管理者権限が必要です)。
:: 代替データストリームを見る
dir /r C:\Users\%USERNAME%\Downloads
:: ファイルのMFT上の配置(ラン)や属性を見る
fsutil file layout C:\path\to\file.dat
:: 8.3短縮名の生成設定と、既存の短縮名
fsutil 8dot3name query C:
dir /x
:: USNジャーナルの状態
fsutil usn queryjournal C:
:: リパースポイントの確認(リンク先とタグ)
dir /aL C:\Users\%USERNAME%
fsutil reparsepoint query "C:\Users\%USERNAME%\OneDrive"
Procmonでファイル操作を追うと、今回の登場人物が実名で流れていきます($LogFile への書き込み、ストリーム名付きのパス、リパース処理)。使い方は「Process Monitor(ProcMon)実践ガイド」を参照してください。
9. まとめ
- NTFSの中心はMFT。全ファイルが台帳のレコードで、情報は「レコード内」か「レコードが指す外部領域」にあります。小さいデータは常駐、大きいデータはラン参照で、小ファイル大量処理の遅さや断片化はこの構造の帰結です。1
- データストリームは複数持てます。Zone.Identifier(Mark of the Web)はただのADSで、
dir /rで見え、NTFSの外へは運ばれません。211 - 名前は属性で、複数持てます。ハードリンクは同じレコードへの同格の名前、8.3名は互換用のもう一つの名前。「削除=名前を外す」であり、実体の消滅は最後の名前・ハンドル・カーネル内参照(マップ済みセクション等)がすべて無くなったときです。34
- リパースポイントは「開く」への公式フックで、シンボリックリンクもジャンクションもファイルオンデマンドもこの応用です。ツリーを辿るコードは
FILE_ATTRIBUTE_REPARSE_POINTを意識する必要があります。56 - ジャーナルは2つ。
$LogFileは構造の整合性回復(壊れない)、USNは変更履歴(何が変わったか)。「ジャーナリングだからデータも安全」ではありません──データの耐久性は第4回の道具で作ります。78 - 論理サイズと割り当ては別物。スパース・圧縮・ADS・クラスター切り上げが「サイズが合わない」の四大要因です。圧縮ファイルが非同期I/Oにならない件も含め、性能調査の引き出しになります。910
続きは最終回、第6回「フィルタードライバーとミニフィルター ── ProcmonとウイルススキャンがI/Oに割り込める理由」です。第1回から折に触れて登場してきた「間に挟まる者たち」──ウイルス対策、Procmon、OneDrive、暗号化──がどうI/Oに割り込んでいるのか。連載の総仕上げとして、デバイススタックの隙間に立つ住人たちの正体を明かします。
関連記事
- Windows I/Oの深層(第1回) ── すべての読み書きはIRPになる:I/Oシステムの全体像
- Windows I/Oの深層(第2回) ── 同期I/Oと非同期I/O:OVERLAPPEDの本当の意味
- Windows I/Oの深層(第4回) ── キャッシュマネージャー:あなたのWriteFileはいつディスクに届くのか
- Windowsで「Windows によって PC が保護されました」が出る理由
- MAX_PATHとWindowsのパス・ファイル名の落とし穴 ── 260文字制限、予約名、末尾ドット、大文字小文字
- FileSystemWatcher実務ガイド - 取りこぼしと重複対策
- ネットワークドライブとUNCパスの落とし穴 ── 業務アプリでファイルサーバー(共有フォルダ)を扱う実務
- Process Monitor(ProcMon)実践ガイド ── 「設定が読まれない」「ACCESS DENIED」を10分で特定する
関連する相談領域
合同会社小村ソフトでは、ファイルサイズやコピー性能の不可解な挙動、リンク・ストリーム絡みの不具合など、NTFSの仕組みに根ざしたWindows業務アプリの設計・調査を扱っています。
参考リンク
-
Microsoft Learn, Master File Table. NTFSボリューム上のすべてのファイルについてMFTに少なくとも1つのエントリがあり、MFT自身のエントリも含まれること、ファイルのサイズ・タイムスタンプ・アクセス許可・データ内容を含むすべての情報がMFTエントリ内かMFTエントリが位置を記述するMFT外の領域に格納されること、ファイル削除時にエントリが空きとしてマークされ再利用されるがMFTのサイズは縮まないこと、MFTを連続に保つためのMFTゾーンが予約されること、割り当ての進行によりMFTの断片化が起こることについて。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, File Streams. NTFSのファイルデータが1つ以上のストリームとして格納されること、既定の(名前のない)データストリームと名前付きの代替データストリームがあること、「ファイル名:ストリーム名」の形式でストリームを指定してCreateFileで開けることについて。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Hard links and junctions. ハードリンクが同一ボリューム内で複数のパスが単一のファイルを参照するファイルシステム上の表現であること、CreateHardLinkで作成すること、どのリンク経由の変更も他のリンクから即座に見えること、属性の変更がすべてのハードリンクに伝播する一方で、ディレクトリエントリ上の表示は変更を行ったリンクでのみ更新されるという表示上の癖があること、およびジャンクション(ディレクトリを別のローカルボリュームへつなぐ仕組み)について。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, fsutil 8dot3name. NTFSが長いファイル名に対して8.3形式の短縮名を生成できること、fsutil 8dot3nameで短縮名生成の有効/無効の照会と設定、既存の短縮名の除去(strip)、除去した場合に影響を受けるレジストリ参照の走査ができることについて。 ↩ ↩2 ↩3
-
Microsoft Learn, Reparse points. リパースポイントがユーザー定義データとそのデータ形式を一意に識別するリパースタグの集まりであること、リパースポイント付きファイルのオープン時にファイルシステムがタグに対応する処理(タグを解釈するファイルシステムフィルターによる処理)を試みること、NTFSのファイルシステムリンクやリモートストレージ(階層記憶)の実装に使われていること、FILE_ATTRIBUTE_REPARSE_POINT属性で存在を確認できることについて。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Symbolic links. シンボリックリンクが別のファイルやディレクトリを指すファイルシステムオブジェクトであり、リンク先への透過的なリダイレクトとして機能すること、絶対・相対のリンクがあり、ボリュームをまたぐ参照やリモートパスへの参照が可能なことについて。 ↩ ↩2 ↩3
-
Microsoft Learn, NTFS overview. NTFSがログファイルとチェックポイント情報を使い、システム障害が起きた場合に次回起動時にトランザクションログを再生してファイルシステムの整合性を自動的に回復すること、不良セクターの動的な再マップや、バックグラウンドで軽微な破損を修復するself-healing NTFSを備えることについて。 ↩ ↩2 ↩3
-
Microsoft Learn, Change Journals. ボリューム内のファイルやディレクトリに変更が加えられるたびに、そのボリュームのUSN変更ジャーナルに変更の内容と対象ファイル/ディレクトリの名前が記録されること、ボリュームごとにジャーナルが維持されること、障害後のファイルシステムインデックスの回復に使え、ボリューム全体の再インデックスを回避できることについて。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Sparse Files. スパースファイルにおいて、ゼロで構成される大きな範囲に物理的なディスク領域を割り当てず、データを含む部分にのみ領域を割り当てること、割り当てのない範囲を読むとゼロが返ることについて。 ↩ ↩2 ↩3
-
Microsoft Learn, File Compression and Decompression. NTFSのファイル圧縮が透過的に行われ、圧縮単位ごとにデータが圧縮・格納されること、GetCompressedFileSizeで圧縮(実割り当て)後のサイズを取得できること、圧縮ファイルの読み書きに展開・再圧縮のコストが伴うことについて。 ↩ ↩2 ↩3
-
Microsoft Learn, Streams - Sysinternals. Sysinternalsのstreamsユーティリティが、NTFSファイルの代替データストリームを列挙・削除できることについて。 ↩ ↩2
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
Windows I/Oの深層(第4回) ── キャッシュマネージャー:あなたのWriteFileはいつディスクに届くのか
Windowsのキャッシュマネージャーを図解で解説する連載の第4回です。ファイルマッピングとして実装されたキャッシュ、先読みと遅延書き込み、FlushFileBuffersやFILE_FLAG_NO_BUFFERINGの使い分け、電源断でデータが消える条件までを整理します。
Windows I/Oの深層(第1回) ── すべての読み書きはIRPになる:I/Oシステムの全体像
WindowsのI/Oシステムを底から解説する連載の第1回です。オブジェクトマネージャーの名前空間、ドライバー・デバイス・ファイルの3つのオブジェクト、IRPのライフサイクル、CloseHandleの裏側までを図解で整理します。
Windows I/Oの深層(第6回・最終回) ── フィルタードライバーとミニフィルター:ProcmonとウイルススキャンがI/Oに割り込める理由
Windowsのフィルタードライバーとミニフィルターを図解で解説する連載の最終回です。フィルターマネージャーとアルティチュード、pre/postコールバック、Procmonやウイルス対策が全I/Oを検査できる仕組み、「あの環境だけ遅い」の調査手順まで整理します。
Windows I/Oの深層(第2回) ── 同期I/Oと非同期I/O:OVERLAPPEDの本当の意味
Windowsの同期I/Oと非同期I/O(オーバーラップI/O)を図解で解説する連載の第2回です。FILE_FLAG_OVERLAPPEDの意味、完了通知の4方式、非同期のはずが同期完了する条件、キャンセルの作法、.NETとの対応までを整理します。
Windows I/Oの深層(第3回) ── I/O完了ポート(IOCP)と.NETスレッドプール:async/awaitの地下室
I/O完了ポート(IOCP)を図解で解説する連載の第3回です。完了キューとスレッド数制御を一体化した設計、コンカレンシー値とLIFO解放、.NETスレッドプールとasync/await継続の実行スレッドまでを整理します。
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
不具合調査 / 長期稼働テーマ
再現しにくい不具合、通信停止、長期稼働障害、失敗パス検証を整理するトピックです。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
Windowsアプリ開発
業務アプリ、装置連携、通信ツールなどの Windows ソフト開発を支援します。
不具合調査・原因解析
再現しにくい障害、長期稼働後の不具合、通信停止などの調査を支援します。
よくある質問
この記事のテーマについて、相談時によくある質問をまとめています。
- MFT(マスターファイルテーブル)とは何ですか?
- NTFSボリュームの心臓部にあたるデータ構造で、ボリューム上のすべてのファイルについて少なくとも1つのエントリ(ファイルレコード)を持つ台帳です。MFT自身のエントリも含まれます。ファイルのサイズ、タイムスタンプ、アクセス許可、そしてデータ本体に至るまで、ファイルに関するすべての情報は、MFTエントリの中か、MFTエントリが指し示すMFT外の領域に格納されます。小さなファイルならデータ本体ごとMFTエントリ内に収まり(常駐)、大きなファイルはデータの置き場所(クラスターの並び)への参照だけがエントリに記録されます(非常駐)。ファイルを削除するとエントリは空きとしてマークされ再利用されますが、MFT自体のサイズは縮みません。
- ファイルに付いている「Zone.Identifier」という見えないデータは何ですか?
- NTFSの複数データストリーム(代替データストリーム)の一つです。NTFSでは1つのファイルが複数のバイト列(ストリーム)を持て、普段読み書きしているのは名前のない既定ストリームです。「file.txt:Zone.Identifier」のようにコロン区切りで指定する追加ストリームに、Windowsはファイルの出所(インターネットからダウンロードした等)を記録します。これがいわゆる「Mark of the Web」で、SmartScreenの警告やOfficeの保護ビューの判定材料になります。代替ストリームはエクスプローラーのサイズ表示に現れず、dir /rコマンドやSysinternalsのstreamsツールで確認できます。NTFS以外のファイルシステム(FATなど)へコピーすると保持されない点にも注意が必要です。
- ハードリンクとシンボリックリンクは何が違いますか?
- ハードリンクは「同じファイル実体(同じMFTレコード)を指す、同格の名前がもう一つ増える」ことです。同一ボリューム内でしか作れず、どの名前からアクセスしても同じファイルで、1つの名前を削除しても他の名前が残っていればファイルは消えません。シンボリックリンクは「別のパスへ案内する標識」で、リパースポイントとして実装されます。リンク先のパス文字列を保持しているだけなので、別ボリュームやリモートも指せますが、リンク先が消えれば行き止まりになります。実務では、ハードリンクは実体の共有(削除の意味が変わる)、シンボリックリンクはパスの付け替え(移設やリダイレクト)と使い分けるのが基本です。
- NTFSはジャーナリングファイルシステムだから、電源断でもデータは消えないのですか?
- 守られる範囲を正確に理解する必要があります。NTFSのトランザクションログ($LogFile)が守るのは、ファイルシステムの構造(メタデータ)の整合性です。システム障害が起きても、次回起動時にログを使って整合性を自動回復し、「ボリュームが壊れて読めない」事態を防ぎます。しかし、書き込み途中だったファイルのデータ内容そのものが復元されるわけではありません。連載第4回で見たとおり、キャッシュ上のダーティなデータは電源断で失われます。つまり「ボリュームは壊れないが、最後の書き込み内容は消えうる」が正しい理解で、データ自体の耐久性が必要ならFlushFileBuffersやWRITE_THROUGH、あるいはアプリ側の書き込み設計(一時ファイル+リネーム等)で作り込む必要があります。
- ファイルの「サイズ」と「ディスク上のサイズ」が違うのはなぜですか?
- NTFSでは、ファイルの論理的な長さと、実際に割り当てられたディスク領域が別々に管理されているからです。通常のファイルでもクラスター単位(既定4KB)で切り上げて割り当てるため差が出ますが、大きく乖離するのはスパースファイルと圧縮ファイルです。スパースファイルでは、ゼロが続く範囲に実領域を割り当てず「穴」として管理するため、論理サイズ数GBでもディスク上は数MBということが起こります。圧縮ファイルでは圧縮後のサイズだけが割り当てられます。逆に「ディスク上のサイズ」の方が大きく見える場合は、クラスター切り上げや代替データストリームが原因のことがあります。
著者プロフィール
記事の著者プロフィールページです。
小村 豪
合同会社小村ソフト 代表
Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。
公開リンク