Tại sao báo cáo kích thước cho các thư mục là khác nhau so với các tập tin khác?


8

Tôi đã tự hỏi tại sao một thư mục trống chiếm 4096 byte không gian và tôi đã thấy câu hỏi này . Nó được tuyên bố rằng không gian được phân bổ trong các khối và do đó, kích thước của một thư mục mới là 4096 byte.

Tuy nhiên tôi khá chắc chắn rằng việc phân bổ cho các tệp "bình thường" cũng được thực hiện theo các khối. Ít nhất là như vậy trong các hệ thống tập tin Windows và tôi đoán rằng nó ít nhất phải giống nhau trong ext *.

Theo như tôi hiểu, việc liệt kê kích thước cho các loại tệp khác, chẳng hạn như tệp, liên kết tượng trưng, ​​v.v ... được thực hiện theo kích thước thực. Bởi vì khi tôi tạo một tệp trống, tôi thấy 0 là kích thước. Khi gõ một vài ký tự, tôi thấy các byte <số ký tự> là kích thước, v.v.

Vì vậy, câu hỏi của tôi là, mặc dù việc phân bổ cho các tệp khác cũng được thực hiện theo khối, tại sao chính sách báo cáo kích thước của thư mục và tệp khác nhau?

Làm rõ

Tôi nghĩ rằng câu hỏi đã đủ rõ ràng nhưng rõ ràng là không. Tôi sẽ cố gắng làm rõ câu hỏi ở đây.

1) Những gì tôi nghĩ rằng một thư mục là:

Tôi sẽ cố gắng giải thích những gì tôi nghĩ rằng một thư mục là ví dụ sau đây. Sau khi đọc, nếu nó sai, xin vui lòng thông báo cho tôi.

Hãy nói rằng chúng tôi có một thư mục có tên mydir. Và chúng ta hãy nói rằng nó chứa 3 tác phẩm, đó là: f0, f1f2. Giả sử rằng mỗi tệp dài 1 byte.

Bây giờ, là mydirgì? Nó là một con trỏ tới một nút có chứa các phần sau: Chuỗi "f0" và số inode f0trỏ đến. Chuỗi "f1" và số inode f1trỏ đến. Và chuỗi "f2" và số inode f2trỏ đến. (Ít nhất đây là những gì tôi nghĩ là một thư mục. Vui lòng sửa cho tôi nếu tôi sai.)

Bây giờ có thể có hai phương pháp để tính kích thước của một thư mục:

1) Tính kích thước của nút in mydirtới.

2) Tổng hợp kích thước của các nút mà nội dung của các mydirđiểm đến.

Mặc dù 1 là trực quan hơn, hãy giả sử rằng đó là phương pháp đang được sử dụng. (Đối với câu hỏi này, phương thức nào là phương thức thực sự đang được sử dụng không quan trọng.) Sau đó, kích thước của mydirđược tính như sau:

2 + 2 + 2 + 3 * <space_required_to_store_an_inode_number>

2 là vì mỗi tên tệp dài 2 byte.

2) Câu hỏi:

Bây giờ câu hỏi: Giả sử những gì tôi nghĩ rằng một thư mục là chính xác, kích thước được báo cáo mydirphải nhỏ hơn 4096, bất kể phương pháp 1 hoặc phương pháp 2 đang được sử dụng để tính kích thước của nó.

Bây giờ, bạn sẽ nói rằng lý do nó được báo cáo 4096 byte là do việc phân bổ được thực hiện theo khối. Do đó, kích thước báo cáo lớn.

Nhưng sau đó tôi sẽ nói: Phân bổ cũng được thực hiện trong các khối cho các tệp thông thường. (Xem câu trả lời của thrig để tham khảo) Tuy nhiên, kích thước của chúng được báo cáo theo kích thước thật. (1 byte nếu chúng chứa 1 ký tự, 2 byte nếu chúng chứa 2 ký tự, v.v.)

Vì vậy, câu hỏi của tôi là, tại sao chính sách báo cáo kích thước của các thư mục lại khác với kích thước báo cáo của các tệp thông thường?

Làm rõ hơn:

Chúng tôi biết rằng số khối ban đầu được phân bổ cho một tệp không trống và cho một thư mục trống là cả 8 khối. (Xem câu trả lời của thrig ) Vì vậy, mặc dù việc phân bổ được thực hiện trong cùng một số khối cho cả tệp và thư mục thông thường, tại sao kích thước được báo cáo cho một thư mục lại lớn hơn nhiều?

Câu trả lời:


11

Tôi nghĩ lý do bạn bối rối là vì bạn không biết thư mục là gì . Để làm điều này, hãy lùi lại một bước và kiểm tra hệ thống tập tin Unix hoạt động như thế nào.

Hệ thống tập tin Unix có một số khái niệm riêng biệt để xử lý dữ liệu trên đĩa:

  • khối dữ liệu là một nhóm các khối trên đĩa có nội dung của tệp.
  • inodes là các khối đặc biệt trên một hệ thống tệp, với một địa chỉ số duy nhất trong hệ thống tệp đó, chứa siêu dữ liệu về một tệp như:
    • quyền
    • thời gian truy cập / sửa đổi
    • kích thước
    • con trỏ tới các khối dữ liệu (có thể là danh sách các khối, phạm vi, v.v.)
  • tên tệp là các vị trí phân cấp trên thư mục gốc của hệ thống tệp được ánh xạ tới các nút.

Nói cách khác, một "tập tin" thực sự bao gồm ba thứ khác nhau:

  1. một PATH trong hệ thống tập tin
  2. một nút với siêu dữ liệu
  3. khối dữ liệu được trỏ đến bởi nút

Hầu hết thời gian, người dùng tưởng tượng một tệp đồng nghĩa với "thực thể được liên kết với tên tệp" - chỉ khi bạn xử lý các thực thể cấp thấp hoặc API tệp / ổ cắm mà bạn nghĩ về inodes hoặc khối dữ liệu. Thư mục là một trong những thực thể cấp thấp.

Bạn có thể nghĩ rằng một thư mục là một tệp chứa một loạt các tệp khác. Điều đó chỉ đúng một nửa. Một thư mục là một tập tin ánh xạ tên tệp thành số inode. Nó không "chứa" các tệp, nhưng con trỏ tới tên tệp. Hãy nghĩ về nó giống như một tệp văn bản có chứa các mục như thế này:

  • . - inode 1234
  • .. - inode 200
  • Tài liệu - inode 2008
  • README.txt - inode 2009

Các mục trên được gọi là mục thư mục . Về cơ bản, chúng là ánh xạ từ tên tệp đến số inode. Một thư mục là một tập tin đặc biệt có chứa các mục thư mục.

Tất nhiên đó là sự đơn giản hóa, nhưng nó giải thích ý tưởng cơ bản và sự kỳ lạ của thư mục khác.

  • Tại sao thư mục không biết kích thước của chính họ?
    • Vì chúng chỉ chứa con trỏ tới các thứ khác, nên bạn phải lặp lại nội dung của chúng để tìm kích thước
  • Tại sao thư mục không bao giờ trống?
    • Bởi vì chúng chứa ít nhất là. và .. mục. Do đó, một thư mục thích hợp sẽ có kích thước nhỏ nhất bằng kích thước tệp nhỏ nhất có thể chứa các mục đó. Trong hầu hết các hệ thống tập tin, 4096 byte là nhỏ nhất.
  • Tại sao bạn cần có quyền ghi trên thư mục mẹ khi đổi tên tệp?
    • Bởi vì bạn không chỉ thay đổi tệp, bạn đang thay đổi mục nhập thư mục trỏ đến tệp.
  • Tại sao ls hiển thị một số lượng lớn các "liên kết" đến một thư mục?
    • một thư mục có thể được tham chiếu (liên kết đến) bởi chính nó, cha mẹ của nó, các con của nó.
  • Một liên kết cứng làm gì và nó khác với một liên kết tượng trưng như thế nào?
    • một liên kết cứng thêm một mục nhập thư mục trỏ đến cùng một số inode. Bởi vì nó trỏ đến một số inode, nó chỉ có thể trỏ đến các tệp trong cùng một hệ thống tệp (các nút là cục bộ của một hệ thống tệp)
    • một symlink thêm một inode mới trỏ đến một tên tệp riêng. Bởi vì nó đề cập đến một tên tệp, nó có thể trỏ đến các tệp tùy ý trong cây.

Nhưng chờ đã! Những điều kỳ lạ đang xảy ra!

ls -ld somedirectoryluôn hiển thị kích thước tệp là 4096, trong khi ls -l somefilehiển thị kích thước thực của tệp. Tại sao?

Điểm nhầm lẫn 1: khi chúng ta nói "kích thước" chúng ta có thể đề cập đến hai điều:

  • filesize, là một số được lưu trong inode; và
  • kích thước được phân bổ, là số khối được liên kết với inode nhân với kích thước của mỗi khối.

Nói chung , đây không phải là cùng một số. Hãy thử chạy stattrên một tệp thông thường và bạn sẽ thấy sự khác biệt này.

Khi một hệ thống tệp tạo ra một tệp không trống, nó thường háo hức phân bổ các khối dữ liệu theo nhóm. Điều này là do các tệp có xu hướng phát triển và co lại nhanh chóng tùy ý. Nếu hệ thống tệp chỉ được phân bổ bao nhiêu khối dữ liệu cần thiết để thể hiện tệp, việc tăng / thu hẹp sẽ chậm hơn và phân mảnh sẽ là một vấn đề nghiêm trọng. Vì vậy, trong thực tế, các hệ thống tập tin không phải giữ lại không gian phân bổ cho các thay đổi nhỏ. Điều này có nghĩa là có thể có rất nhiều dung lượng trên đĩa bị "khiếu nại" bởi các tệp nhưng hoàn toàn không được sử dụng.

Hệ thống tập tin làm gì với tất cả không gian chưa sử dụng này? Không có gì. Cho đến khi nó cảm thấy như nó cần. Nếu công cụ tối ưu hóa hệ thống tệp của bạn - có thể là trình tối ưu hóa trực tuyến đang chạy trong nền, có thể là một phần của fsck của bạn, có thể được tích hợp vào chính hệ thống tệp của bạn - cảm thấy như vậy, nó có thể gán lại các khối dữ liệu của các tệp của bạn - di chuyển các khối đã sử dụng, giải phóng không sử dụng khối, v.v.

Vì vậy, bây giờ chúng ta đi đến sự khác biệt giữa các tệp và thư mục thông thường: bởi vì các thư mục tạo thành "xương sống" của hệ thống tệp của bạn, bạn hy vọng rằng chúng có thể cần được truy cập hoặc sửa đổi thường xuyên và do đó nên được tối ưu hóa. Và vì vậy bạn không muốn chúng bị phân mảnh. Khi các thư mục được tạo, chúng luôn tối đa tất cả các khối dữ liệu của chúng về kích thước, ngay cả khi chúng chỉ có rất nhiều mục nhập thư mục. Điều này là ổn đối với các thư mục, bởi vì, không giống như các tệp, các thư mục thường bị giới hạn về kích thước và tốc độ tăng trưởng.

Kích thước 4096 được báo cáo của các thư mục là số "filesize" được lưu trong inode thư mục, không phải số lượng mục trong thư mục. Đó không phải là một số cố định - đó là các byte tối đa sẽ phù hợp với số khối được phân bổ cho thư mục. Thông thường, đây là 512 byte / khối lần 8 khối được phân bổ cho một tệp có bất kỳ nội dung nào - tình cờ, đối với các thư mục, kích thước tệp và kích thước được phân bổ là như nhau. Vì được phân bổ thành một nhóm duy nhất, trình tối ưu hóa hệ thống tập tin sẽ không di chuyển các khối của nó xung quanh.

Khi thư mục phát triển, nhiều khối dữ liệu được gán cho nó và nó cũng sẽ tối đa hóa các khối đó bằng cách điều chỉnh kích thước tệp cho phù hợp.

Và như vậy lsstatsẽ hiển thị trường kích thước tệp của inode của thư mục, được đặt thành kích thước của các khối dữ liệu được gán cho nó.


[1] Đây là một câu trả lời tuyệt vời, cảm ơn nhưng tôi đã biết những điều này và nó không trả lời câu hỏi của tôi. Hãy để tôi làm rõ: Hãy nói rằng có một thư mục được gọi mydir. Và giả sử nó chứa một số tệp như : f0, f1f2. Bây giờ, là mydirgì? Nó là một con trỏ tới một nút có chứa dòng sau: Chuỗi "f0" và số inode mà nó trỏ tới. Chuỗi "f1" và số inode mà nó trỏ tới. Chuỗi "f2" và số inode mà nó trỏ đến. (Ít nhất đây là hình ảnh trong tâm trí của tôi. Nó có thể sai) Cho đến nay rất tốt.
Utku

[2] Bây giờ, chúng ta phải quyết định ý nghĩa của kích thước của một thư mục. Một trong hai tùy chọn là xác định nó chỉ là kích thước của các mydirđiểm inode . Không thêm kích thước của các nút mà nội dung của thư mục trỏ đến. Một cách khác có thể được định nghĩa là tổng kích thước của các nút được chỉ ra bởi nội dung của thư mục. Để đơn giản, nếu chúng tôi giả sử rằng nó được tính theo định nghĩa trước đây, kích thước của mydirnên là: 2 + 2 + 2 + 3 * <kích thước cần thiết để lưu trữ số inode>. 2 là vì mỗi tên tệp mydirdài hai ký tự.
Utku

[3] Suy nghĩ theo cách này, kích thước được báo cáo của một thư mục trống phải nhỏ hơn 4096 byte. Bây giờ bạn sẽ nói rằng phân bổ được thực hiện trong các khối. Do đó, kích thước báo cáo là rất lớn. Nhưng sau đó tôi sẽ nói: Phân bổ cho các tệp thông thường cũng được thực hiện theo khối. Nhưng kích thước của chúng được báo cáo là kích thước thật của chúng. Câu hỏi của tôi là này. Lý do cho các chính sách khác nhau như vậy trong báo cáo kích thước của tệp so với thư mục là gì.
Utku

Tôi sẽ làm cho một sự khác biệt giữa kích thước tập tin và kích thước phân bổ. Theo ý của họ, các hệ thống tệp có thể sử dụng các kỹ thuật khác nhau để phân bổ các khối - nói chung, inode chứa "danh sách khối" trỏ đến các khối dữ liệu, một số hệ thống tệp có thể lưu trữ dữ liệu tệp trong chính khối của inode, một số hệ thống tệp có thể có inode nêu một khối bắt đầu / kết thúc, một số có thể phân chia / phân bổ các khối giữa các tệp, v.v. Nói cách khác, không có gì đảm bảo trong trường hợp chung rằng tệp "sở hữu" toàn bộ khối. Kích thước duy nhất "được sở hữu" bởi tệp là nội dung thực tế (không phải là nút).
madumlao

Tuy nhiên, các thư mục là các tệp đặc biệt và có thể được hệ thống tệp xử lý khác nhau liên quan đến phân bổ tệp / khối. Không gian được phân bổ trên đĩa cho một thư mục có lẽ cũng thuộc sở hữu riêng của thư mục cho mục đích tối ưu hóa (để cho phép nội dung của thư mục được đọc / ghi nhanh hơn). Vì vậy, tôi sẽ nghĩ về sự khác biệt KHÔNG phải là sự khác biệt báo cáo, mà là sự khác biệt phân bổ. Thư mục "sở hữu" toàn bộ khối khi được tạo, một tệp thông thường, không nhất thiết phải như vậy. Điều này sẽ giải thích tại sao kích thước thư mục khác nhau tùy thuộc vào hệ thống tập tin.
madumlao

3

Tôi nghĩ rằng kích thước thư mục ban đầu, trống, phụ thuộc vào hệ thống tập tin. Trên các hệ thống tập tin ext3 và ext4 mà tôi có quyền truy cập, tôi cũng nhận được các thư mục trống 4096 byte. Trên một loại NAS gắn NFS nào đó, tôi nhận được một thư mục trống 80 byte. Tôi không có quyền truy cập vào hệ thống tập tin ReiserFS, kích thước thư mục trống mới được tạo, sẽ rất thú vị.

Theo truyền thống, một thư mục là một tệp có một bit được đặt trong inode của nó (cấu trúc trên đĩa mô tả tệp) cho biết đó là một thư mục. Tập tin đó chứa đầy các bản ghi có độ dài thay đổi. Đây là những gì /usr/include/linux/dirent.hnói:

struct dirent64 {
    __u64       d_ino;
    __s64       d_off;
    unsigned short  d_reclen;
    unsigned char   d_type;
    char        d_name[256];
};

Bạn có thể bỏ qua các mục nhập tệp thư mục bằng cách sử dụng các d_offgiá trị. Nếu một mục nhập đã bị xóa ( unlink()cuộc gọi hệ thống, được sử dụng bởi rmlệnh), d_offgiá trị của mục nhập trước đó đã tăng lên để tính đến bản ghi bị thiếu. Không có gì làm "nén" hồ sơ. Có lẽ chỉ đơn giản nhất là hiển thị phân bổ theo số lượng byte trong các khối đĩa được phân bổ cho tệp, thay vì cố gắng tìm ra có bao nhiêu byte trong tài khoản tệp thư mục cho tất cả các mục hoặc chỉ tối đa mục cuối cùng.

Ngày nay, các thư mục có các định dạng nội bộ như B-cây hoặc Cây Hash . Tôi đoán rằng đó là một cải tiến hiệu suất lớn để thực hiện các thư mục theo khối hoặc có "khoảng trống" bên trong chúng tương tự như các thư mục trường học cũ, vì vậy thật khó để quyết định "kích thước thực" trong byte của thư mục là gì, đặc biệt một cái đã được sử dụng trong một thời gian và đã xóa các tập tin và thêm vào nó rất nhiều. Dễ dàng hơn chỉ để hiển thị số khối được nhân với số byte trên mỗi khối.


Nhưng tại sao nó dễ dàng báo cáo kích thước thực của một tệp "bình thường" mà không phải là một thư mục?
Utku

1
@Utku - bởi vì các chương trình có thể sử dụng kích thước thật của một tệp bình thường. Bạn có thể malloc một bộ đệm có kích thước của tệp và đọc tệp vào bộ đệm. Bạn có thể đọc các byte có giá trị kích thước tệp từ tệp và gửi chúng qua ổ cắm. Việc sử dụng là vô hạn. Nếu bạn chỉ có số khối, bạn bị mắc kẹt trong việc đọc số lượng khối và sau đó kiểm tra tất cả các byte để tìm ra vị trí cuối của các byte trong các khối. CP / M đã không làm điều đó và đệm các byte của tệp với các ký tự Control-Z thành bội số 512 byte?
Bruce Ediger

1
Sau đó là câu trả lời như sau: Các tệp được báo cáo với kích thước thật vì kích thước thực này có thể được sử dụng nhưng vì kịch bản đó không thể thực hiện được cho các thư mục, nên hệ thống tệp (hoặc bất cứ điều gì khác, tôi không chắc là gì) đi vào những rắc rối của việc xác định và báo cáo kích thước thực của một thư mục?
Utku

@Utku - Tôi nghĩ rằng âm thanh đó chính xác, và rất súc tích.
Bruce Ediger

Tôi cũng nghĩ vậy, nhưng tôi nghĩ rằng có lẽ có một lý do khác quan trọng hơn. Rốt cuộc, việc báo cáo kích thước thật của một thư mục khó đến mức nào, ngay cả khi nó không được sử dụng cho chúng ta? Tôi nghĩ rằng nó không nên thêm nhiều hơn một vài phần nghìn giây.
Utku

2

Một tập tin có thể không có khối được phân bổ cho nó; các -slá cờ để lssẽ hiển thị sự khác biệt này, trong khi một thư mục sẽ có một số số khối tối thiểu được giao, do đó kích thước mặc định. (Trừ khi bạn đang sử dụng một số hệ thống tệp hiện đại ưa thích để ném các khái niệm này ra khỏi cửa sổ.) Ví dụ:

% 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
% 

Lưu ý rằng liên kết tượng trưng ở đây không có khối, mặc dù dành bảy byte cho các chi tiết cần thiết readlink(2), thật tò mò! Dù sao, bây giờ hãy đệm foofilevới một hoặc hai byte:

% 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
%

Và người ta có thể thấy rằng các khối được phân bổ cho foofileđã nhảy lên 8mặc dù chỉ có hai byte ( avà dòng mới được xử lý echo).

Các tệp cũng có thể thưa thớt, đó là một cách khác mà kích thước tệp được báo cáo so với nội dung thực tế có thể khác nhau, tùy thuộc vào cách công cụ tương tác với tệp xử lý độ thưa thớt đó.

Ngoài ra, kích thước của thư mục có thể được tăng lên, tạo nhiều tệp có tên rất dài và kiểm tra xem điều gì xảy ra với kích thước của thư mục (và cho các khối được phân bổ) sau mỗi tên tệp dài mới được tạo bằng ls -lds .


[1] Để xem tôi có hiểu không: Số khối được phân bổ foofileban đầu là 0 vì nó trống. Do đó, foofileđã không chỉ vào một nút. Nhưng sau khi thực hiện một thay đổi nhỏ nhất foofile, một inode phải được gán cho nó và hệ thống tập tin được phân bổ số lượng khối phân bổ nhỏ nhất cho nó. Có đúng không?
Utku

[2] Mặc dù vậy, vẫn còn 3 câu hỏi: 1) Tại sao fooslnkhông chiếm bất kỳ khối nào? Nó không trống kể từ thời điểm nó được tạo ra. Do đó, nó cảm thấy như nó nên chiếm một số khối khi tạo. 2) Tại sao số khối phân bổ nhỏ nhất là 8? (hoặc là nó?) Không phải là 1? 3) Và cũng vậy, mặc dù bây giờ tôi biết rằng các tệp cũng được phân bổ theo khối, nhưng tôi vẫn không biết tại sao kích thước của thư mục được báo cáo là tổng kích thước của các khối mà nó chiếm so với kích thước của tệp được báo cáo là kích thước thật của nó?
Utku

"Inode" là một thực thể tách biệt với các khối dữ liệu. Inode có thể được coi là siêu dữ liệu với một con trỏ tới các khối (thường là một danh sách). Trong trường hợp của một liên kết tượng trưng, ​​KHÔNG có khối nào - chính nút inode chứa tên tệp được trỏ đến.
madumlao

@madumlao Sau đó, con số được báo cáo là số khối thực sự; "số lượng khối mà nút của tệp này trỏ tới"?
Út

1
Đúng. Theo truyền thống, các nút có danh sách chặn và ls -s hiển thị kích thước của danh sách đó. Các liên kết tượng trưng có các khối bằng 0 và do đó sẽ luôn báo cáo các số không bạn sử dụng các công cụ cấp thấp để chỉnh sửa các khối dữ liệu của chúng. Tôi không nghĩ các hệ thống tập tin nhất thiết bị ràng buộc bởi phép ẩn dụ của danh sách chặn. Các hệ thống tệp dựa trên RAM hoặc hệ thống tệp cơ sở dữ liệu hoặc các công cụ FUSE khác có thể "gian lận" bằng cách nào đó. Và tôi khá chắc chắn rằng reiserfs có "hỗ trợ tệp nhỏ" có thể lưu trữ dữ liệu của một tệp nhỏ bên trong khối inode nếu nó phù hợp. Không biết làm thế nào reiser báo cáo ls -s cho các tệp nhỏ mặc dù. số không? 1?
madumlao
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.