Files

為什麼目錄的大小報告與其他文件不同?

  • February 21, 2018

我想知道為什麼一個空目錄佔用了 4096 字節的空間,我已經看到了這個問題。據說空間是按塊分配的,因此新目錄的大小是 4096 字節。

但是,我很確定“正常”文件的分配也是分塊完成的。至少在Windows 文件系統中是這樣的,我猜它在 ext* 中必須至少相似。

現在據我了解,其他類型文件(如文件、符號連結等)的大小列表是根據實際大小完成的。因為當我創建一個空文件時,我看到一個 0 作為大小。當鍵入幾個字元時,我將 <字元數> 字節視為大小等。

所以我的問題是,雖然其他文件的分配也是分塊完成的,為什麼報告目錄和文件大小的策略不同?

澄清

我認為這個問題很清楚,但顯然不是。我將嘗試在這裡澄清這個問題。

1)我認為目錄是:

我將嘗試通過以下範例解釋我認為目錄是什麼。閱讀後,如有錯誤,請通知我。

假設我們有一個名為mydir. 假設它包含 3 個文件,分別是f0f1f2. 假設每個文件都是 1 字節長。

現在,什麼是mydir?它是一個指向包含以下內容的 inode 的指針:字元串“f0”和f0指向的 inode 編號。f1字元串“f1”和指向的inode 號。f2以及字元串“f2”和指向的inode號。(至少這是我認為的目錄。如果我錯了,請糾正我。)

現在可能有兩種計算目錄大小的方法:

1)計算mydir指向的inode的大小。

mydir2) 將內容指向的 inode 的大小相加。

雖然 1 更反直覺,但讓我們假設它是正在使用的方法。(對於這個問題,實際使用的方法是哪種方法無關緊要。)然後,大小mydir計算如下:

2 + 2 + 2 + 3 * &lt;space_required_to_store_an_inode_number&gt;

2 是因為每個文件名都是 2 個字節長。

2)問題:

現在的問題是:假設我認為一個目錄是正確的,報告的大小mydir應該遠小於 4096,無論是使用方法 1 還是方法 2 來計算其大小。

現在,您會說它報告 4096 字節的原因是因為分配是按塊完成的。因此,報告的大小那麼大。

但是我會說:對於正常文件,分配也是分塊完成的。(請參閱thrig 的答案以供參考)但是,它們的尺寸以實際尺寸報告。(如果它們包含 1 個字元則為 1 個字節,如果它們包含 2 個字元則為 2 個字節等)

所以我的問題是,為什麼報告目錄大小的政策與報告正常文件大小的政策如此不同?

更多說明:

我們知道為非空文件和空目錄分配的初始塊數都是 8 個塊。(請參閱thrig 的答案)因此,即使正常文件和目錄的分配數量相同,為什麼報告的目錄大小要大得多?

我認為您感到困惑的原因是因為您不知道目錄什麼。為此,讓我們退後一步,檢查一下 Unix 文件系統是如何工作的。

Unix 文件系統有幾個獨立的概念來定址磁碟上的數據:

  • 數據塊是磁碟上具有文件內容的一組塊。

  • inode是文件系統上的特殊塊,在該文件系統中具有唯一的數字地址,其中包含有關文件的元數據,例如:

    • 權限
    • 訪問/修改時間
    • 尺寸
    • 指向數據塊的指針(可以是塊列表、範圍等)
  • 文件名是映射到 inode 的文件系統根目錄上的分層位置。

換句話說,一個“文件”實際上由三個不同的東西組成:

  1. 文件系統中的 PATH
  2. 帶有元數據的 inode
  3. inode 指向的數據塊

大多數時候,使用者認為文件是“與文件名關聯的實體”的同義詞——只有在處理低級實體或文件/套接字 API 時,才會想到 inode 或數據塊。目錄是那些低級實體之一。

您可能認為目錄是一個包含一堆其他文件的文件。這只是對了一半。目錄是將文件名映射到 inode 編號的文件。它不“包含”文件,而是指向文件名的指針。把它想像成一個包含如下條目的文本文件:

  • . - 索引節點 1234
  • .. - 索引節點 200
  • 文件 - 索引節點 2008
  • README.txt - 索引節點 2009

上面的條目稱為目錄條目。它們基本上是從文件名到 inode 號的映射。目錄是包含目錄條目的特殊文件。

這當然是一種簡化,但它解釋了基本思想和其他目錄怪異。

  • 為什麼目錄不知道自己的大小?

    • 因為它們只包含指向其他東西的指針,所以您必須遍歷它們的內容才能找到大小
  • 為什麼目錄永遠不是空的?

    • 因為它們至少包含 . 和 .. 條目。因此,一個正確的目錄將至少與可以包含這些條目的最小文件大小一樣小。在大多數文件系統中,4096 字節是最小的。
  • 為什麼重命名文件時需要對父目錄有寫權限?

    • 因為您不僅要更改文件,還要更改指向該文件的目錄條目。
  • 為什麼 ls 顯示一個奇怪數量的“連結”到一個目錄?

    • 一個目錄可以被它自己、它的父目錄、它的子目錄引用(連結到)。
  • 硬連結有什麼作用,它與符號連結有何不同?

    • 硬連結會添加一個指向相同 inode 編號的*目錄條目。*因為它指向一個inode編號,所以它只能指向同一個文件系統中的文件(inode是文件系統的本地)
    • 符號連結添加了一個指向單獨文件名的新 inode。因為它引用文件名,所以它可以指向樹中的任意文件。

可是等等!奇怪的事情正在發生!

ls -ld somedirectory始終顯示文件大小為 4096,而ls -l somefile顯示文件的實際大小。為什麼?

混淆點1:當我們說“大小”時,我們可以指兩件事:

  • filesize,這是一個儲存在 inode 中的數字;和
  • 分配的大小,即與 inode 關聯的塊數乘以每個塊的大小。

一般來說,這些不是同一個數字。嘗試stat正常文件上執行,您會看到這種差異。

當文件系統創建一個非空文件時,它通常會急切地分組分配數據塊。這是因為文件有任意快速增長和收縮的趨勢。如果文件系統僅根據需要分配盡可能多的數據塊來表示文件,則增長/收縮會更慢,並且碎片將是一個嚴重的問題。所以在實踐中,文件系統不必為小的變化重新分配空間。這意味著磁碟上可能有很多空間被文件“聲明”但完全未使用。

文件系統如何處理所有這些未使用的空間?沒有。直到感覺需要為止。如果您的文件系統優化器工具 - 可能是在後台執行的線上優化器,可能是 fsck 的一部分,可能是文件系統本身的內置工具 - 感覺像這樣,它可能會重新分配文件的數據塊 - 移動使用的塊,釋放未使用的塊塊等

所以現在我們來看看正常文件和目錄之間的區別:因為目錄構成了文件系統的“主幹”,所以您希望它們可能需要經常訪問或修改,因此應該進行優化。因此,您根本不希望它們支離破碎。當創建目錄時,它們總是最大化所有數據塊的大小,即使它們只有這麼多的目錄條目。這對於目錄來說是可以的,因為與文件不同,目錄通常在大小和增長率方面受到限制。

4096 報告的目錄大小是儲存在目錄 inode 中的“filesize”數字,而不是目錄中的條目數。它不是一個固定的數字——它是適合為目錄分配的塊數的最大字節數。通常,這是為具有任何內容的文件分配的 512 字節/塊乘以 8 個塊 - 順便說一下,對於目錄,文件大小和分配的大小是相同的。因為它是作為一個單獨的組分配的,所以文件系統優化器不會移動它的塊。

隨著目錄的增長,更多的數據塊被分配給它,並且它也會通過相應地調整文件大小來最大化這些塊。

因此lsstat將顯示目錄 inode 的 filesize 欄位,該欄位設置為分配給它的數據塊的大小。

引用自:https://unix.stackexchange.com/questions/234065