空のディレクトリが4096バイトのスペースを占めるのはなぜだろうと思っていたところ、 this の質問が表示されました。スペースはブロック単位で割り当てられるため、新しいディレクトリのサイズは4096バイトです。
ただし、「通常の」ファイルの割り当てもブロック単位で行われることは確かです。少なくともそれは Windows filesystems のようなものであり、少なくともext *でも同様である必要があると思います。
私が理解している限りでは、ファイル、シンボリックリンクなどの他のタイプのファイルのサイズリストは、実際のサイズで行われます。空のファイルを作成すると、サイズとして0が表示されるためです。数文字タイプすると、サイズとして<文字数>バイトが見えます。
だから私の質問は、他のファイルの割り当てもブロックで行われますが、ディレクトリとファイルのサイズを報告するためのポリシーが異なるのはなぜですか?
質問は十分に明確であると思いましたが、明らかにそうではありませんでした。ここで質問を明確にします。
1)ディレクトリとは:
以下の例で、ディレクトリとは何かを説明しようと思います。読んだ後、誤りがあればお知らせください。
mydir
という名前のディレクトリがあるとします。そして、そこにf0
、f1
、f2
の3つのファイルが含まれているとしましょう。各ファイルの長さが1バイトであると仮定しましょう。
さて、mydir
とは何ですか?これは、以下を含むiノードへのポインターです。ストリング「f0」とf0
が指すiノード番号。文字列「f1」とf1
が指すiノード番号。そして、文字列「f2」とf2
が指すiノード番号。 (少なくとも、これは私が考えるディレクトリです。間違っている場合は修正してください。)
現在、ディレクトリのサイズを計算する方法は2つあります。
1)mydir
が指すiノードのサイズを計算します。
2)mydir
の内容が指すiノードのサイズを合計します。
1の方が直感的ではありませんが、これが使用されている方法であると仮定しましょう。 (この質問では、どの方法が実際に使用されているかは問題ではありません。)次に、mydir
のサイズは次のように計算されます。
2 + 2 + 2 + 3 * <space_required_to_store_an_inode_number>
2は、各ファイル名の長さが2バイトであるためです。
2)質問:
ここで質問:ディレクトリが正しいと思うと仮定すると、メソッド1またはメソッド2を使用してそのサイズを計算しても、mydir
のレポートサイズは4096をはるかに下回るはずです。
ここで、4096バイトが報告される理由は、割り当てがブロック単位で行われるためであると言います。したがって、報告されたサイズはそれほど大きくありません。
しかしそれから私は言うでしょう:割り当ては通常のファイルのブロックでも行われます。 (参考として thrig's answer を参照してください)ただし、それらのサイズは実際のサイズで報告されます。 (1文字の場合は1バイト、2文字の場合は2バイトなど)
だから私の質問は、ディレクトリのサイズを報告するためのポリシーが通常のファイルのサイズを報告することとはなぜ違うのですか?
さらに明確化:
空ではないファイルと空のディレクトリに割り当てられたブロックの初期数はどちらも8ブロックであることはわかっています。 ( thrig's answer を参照)通常のファイルとディレクトリの両方で同じ数のブロックで割り当てが行われているにもかかわらず、報告されたディレクトリのサイズがはるかに大きいのはなぜですか?
あなたが混乱している理由は、ディレクトリが何であるかわからないためだと思います。これを行うには、少し前に戻り、Unixファイルシステムがどのように機能するかを調べます。
Unixファイルシステムには、ディスク上のデータをアドレス指定するためのいくつかの個別の概念があります。
言い換えると、「ファイル」は実際には3つの異なるもので構成されています。
ほとんどの場合、ユーザーはファイルが「ファイル名に関連付けられたエンティティ」と同義であると想像します。これは、低レベルのエンティティまたはファイル/ソケットAPIを処理する場合にのみ、iノードまたはデータブロックと考えます。ディレクトリはそれらの低レベルのエンティティの1つです。
ディレクトリは、他のファイルの束を含むファイルであると考えるかもしれません。それは半分だけ正しいです。ディレクトリは、ファイル名をiノード番号にマップするファイルです。ファイルは含まれていませんが、ファイル名へのポインタです。次のようなエントリを含むテキストファイルのように考えてください。
上記のエントリはディレクトリエントリと呼ばれます。それらは基本的にファイル名からiノード番号へのマッピングです。ディレクトリは、ディレクトリエントリを含む特別なファイルです。
これはもちろん単純化ですが、基本的な考え方やその他のディレクトリの奇妙さを説明しています。
ちょっと待って!奇妙なことが起こっています!
ls -ld somedirectory
は常にファイルサイズが4096であることを示しますが、ls -l somefile
は、ファイルの実際のサイズを示します。どうして?
混乱のポイント1:「サイズ」と言うとき、2つのことを指すことがあります。
一般に、これらは同じ数ではありません。 regularファイルでstat
を実行してみてください。この違いがわかります。
ファイルシステムが空ではないファイルを作成するとき、それは通常グループでデータブロックを熱心に割り当てます。これは、ファイルが任意に速く拡大および縮小する傾向があるためです。ファイルシステムがファイルを表すのに必要な数のデータブロックのみを割り当てた場合、拡大/縮小は遅くなり、断片化は深刻な問題になります。したがって、実際には、ファイルシステムは小さな変更のためにスペースを再割り当てし続ける必要はありません。これは、ファイルによって「要求」されたが、完全に未使用のディスクに多くのスペースがある可能性があることを意味します。
ファイルシステムは、このすべての未使用領域をどのように処理しますか?何もない。それが必要であると感じるまで。ファイルシステムオプティマイザーツール(おそらくバックグラウンドで実行されているオンラインオプティマイザー、おそらくfsckの一部、ファイルシステム自体に組み込まれている)のように思える場合、ファイルのデータブロックを再割り当てする可能性があります-使用済みブロックを移動し、未使用を解放しますブロックなど.
ここで、通常のファイルとディレクトリの違いについて説明します。ディレクトリはファイルシステムの「バックボーン」を形成しているため、頻繁にアクセスまたは変更する必要があり、最適化する必要があることが予想されます。そして、あなたはそれらをまったく断片化したくありません。ディレクトリが作成されると、ディレクトリエントリが非常に多い場合でも、すべてのデータブロックのサイズが常にmax outになります。ディレクトリはファイルとは異なり、通常、ディレクトリのサイズと成長率が制限されているため、これは問題ありません。
4096と報告されたディレクトリーのサイズは、ディレクトリー内のエントリーの数ではなく、ディレクトリーiノードに保管されている「ファイルサイズ」の数です。これは固定数ではなく、ディレクトリに割り当てられたブロック数に収まる最大バイト数です。通常、これは512バイト/ブロック×任意の内容のファイルに割り当てられた8ブロックです-ちなみに、ディレクトリの場合、ファイルサイズと割り当てられたサイズは同じです。単一のグループとして割り当てられるため、ファイルシステムオプティマイザーはブロックを移動しません。
ディレクトリが大きくなると、より多くのデータブロックがそのディレクトリに割り当てられ、それに応じてファイルサイズを調整することで、それらのブロックもmax outします。
したがって、ls
およびstat
は、ディレクトリのiノードのファイルサイズフィールドを表示します。これは、割り当てられたデータブロックのサイズに設定されています。
最初の空のディレクトリサイズはファイルシステムに依存すると思います。アクセス可能なext3およびext4ファイルシステムでは、4096バイトの空のディレクトリも取得します。 NFSマウントされたNAS=ある種の場合、80バイトの空のディレクトリを取得します。ReiserFSファイルシステムにアクセスできません。新しく作成された空のディレクトリサイズがあります。面白い。
従来、ディレクトリは、そのiノード(ファイルを記述するディスク上の構造)にビットが設定されたファイルであり、ディレクトリであることを示していました。そのファイルは可変長レコードで埋められました。 _/usr/include/linux/dirent.h
_の内容は次のとおりです。
_struct dirent64 {
__u64 d_ino;
__s64 d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[256];
};
_
_d_off
_値を使用すると、ディレクトリファイルエントリをスキップできます。エントリが削除された場合(unlink()
システムコール、rm
コマンドで使用)、前のエントリの_d_off
_値が不足しているレコードを考慮して増加しました。レコードの「圧縮」は行われませんでした。おそらく、ファイルに割り当てられたディスクブロックのバイト数の観点から割り当てを表示するのが最も簡単でした。ディレクトリファイル内のすべてのエントリのバイト数や、最後のエントリー。
最近では、ディレクトリの内部形式はBツリーや ハッシュツリー のようになっています。ブロック単位でディレクトリを実行することでパフォーマンスが大幅に向上するか、古い学校のディレクトリと同様にその中に「空白」があるため、特にディレクトリの「実際のサイズ」が何であるかを判断するのは難しいと思いますしばらく使用されていて、ファイルが削除されたり、追加されたりしたもの。ブロック数にブロックごとのバイト数を掛けた値を表示するだけの方が簡単です。
ファイルにはブロックが割り当てられていない場合があります。 ls
の_-s
_フラグはこの違いを示しますが、ディレクトリにはいくつかの最小ブロックが割り当てられているため、デフォルトのサイズになります。 (あなたがこれらの概念をウィンドウの外に投げ出すいくつかの派手な最新のファイルシステムを使用しているのでない限り。)例えば:
_% mkdir testfoo
% cd testfoo/
% mkdir foodir
% touch foofile
% ln -s foofile foosln
% ls -ld foo*
drwxrwxr-x 2 jmates jmates 512 Oct 5 19:48 foodir
-rw-rw-r-- 1 jmates jmates 0 Oct 5 19:48 foofile
lrwxrwxr-x 1 jmates jmates 7 Oct 5 19:48 foosln -> foofile
% ls -lds foo*
8 drwxrwxr-x 2 jmates jmates 512 Oct 5 19:48 foodir
0 -rw-rw-r-- 1 jmates jmates 0 Oct 5 19:48 foofile
0 lrwxrwxr-x 1 jmates jmates 7 Oct 5 19:48 foosln -> foofile
%
_
readlink(2)
に必要な詳細に7バイトを割り当てているにもかかわらず、ここではシンボリックリンクはブロックを取りません。とにかく、1バイトか2バイトでfoofile
を埋めましょう:
_% echo >> foofile a
% ls -lds foo*
8 drwxrwxr-x 2 jmates jmates 512 Oct 5 19:48 foodir
8 -rw-rw-r-- 1 jmates jmates 2 Oct 5 19:49 foofile
0 lrwxrwxr-x 1 jmates jmates 7 Oct 5 19:48 foosln -> foofile
%
_
そして、2バイトしかない(foofile
と改行a
が追加されている)にもかかわらず、echo
に割り当てられたブロックが_8
_にジャンプしたことがわかります。
ファイルはスパースである場合もあります。これは、ファイルと対話するツールがスパース性を処理する方法に応じて、報告されたファイルサイズと実際のコンテンツが異なる場合があることを示します。
また、ディレクトリのサイズを増やし、非常に長い名前で多くのファイルを作成し、_ls -lds .
_を使用して新しい長いファイル名を作成した後、ディレクトリ(および割り当てられたブロック)のサイズがどうなるかを確認できます。