2010-02-22 103 views
15

C routines opendir(), readdir() và closir() cung cấp một cách để tôi duyệt qua một cấu trúc thư mục. Tuy nhiên, mỗi cấu trúc dirent được trả về bởi readdir() dường như không cung cấp một cách hữu ích cho tôi để có được tập hợp các con trỏ tới DIR mà tôi sẽ cần phải recurse vào thư mục con thư mục.Duyệt cây thư mục hiệu quả với opendir(), readdir() và closir()

Tất nhiên, họ cho tôi tên tệp, vì vậy tôi có thể nối tên đó vào đường dẫn thư mục và chỉ mục() và opendir() hoặc tôi có thể thay đổi thư mục làm việc hiện tại của quá trình qua chdir() và cuộn nó trở lại thông qua chdir ("..").

Vấn đề với cách tiếp cận đầu tiên là nếu chiều dài của đường dẫn thư mục đủ lớn, thì chi phí để chuyển một chuỗi chứa nó tới opendir() sẽ vượt quá chi phí mở thư mục. Nếu bạn có một chút lý thuyết hơn, bạn có thể nói sự phức tạp của bạn có thể tăng vượt quá thời gian tuyến tính (trong tổng số ký tự của các tên tập tin (tương đối) trong cây thư mục).

Ngoài ra, cách tiếp cận thứ hai có vấn đề. Vì mỗi tiến trình có một thư mục làm việc hiện tại, tất cả chỉ một luồng sẽ phải chặn trong một ứng dụng đa luồng. Ngoài ra, tôi không biết nếu thư mục làm việc hiện tại chỉ là một sự thuận tiện đơn thuần (tức là, đường dẫn tương đối sẽ được nối vào nó trước một truy vấn hệ thống tập tin). Nếu có, cách tiếp cận này cũng sẽ không hiệu quả.

Tôi chấp nhận lựa chọn thay thế cho các chức năng này. Vì vậy, làm thế nào nó có thể đi qua một cây thư mục UNIX hiệu quả (thời gian tuyến tính trong tổng số ký tự của các tập tin theo nó)?

+0

Độ dài tối đa của một tên tập tin hoặc thư mục được thiết lập bởi MAXCOMPLEN, đó là truyền thống 255 và hầu như không bao giờ hơn 512. Vì vậy, nếu bạn thực hiện chức năng đệ quy của bạn, bạn sẽ không phải chuỗi rất lớn, chắc chắn hư không gần điểm phân bổ và quản lý các chuỗi giữ đường dẫn thư mục ảnh hưởng đến độ phức tạp tổng thể của quá trình truyền tải. –

Trả lời

4

Cách sử dụng opendir/readdir/closedir là làm cho hàm đệ quy! Hãy xem đoạn mã tại đây theo số Dreamincode.net.

Hy vọng điều này sẽ hữu ích.

EDIT Cảm ơn R.Sahu, các linky đã hết hạn, tuy nhiên, tìm thấy nó qua wayback archive và mất sự tự do để thêm nó vào gist. Hãy nhớ, để kiểm tra giấy phép cho phù hợp và thuộc tính tác giả ban đầu cho nguồn! :)

+0

Liên kết cho mã không còn hợp lệ nữa. Chỉ là FYI. –

+0

@RSahu đã cập nhật cho phù hợp;) – t0mm13b

5

Bạn dường như thiếu một điểm cơ bản: truyền tải thư mục liên quan đến việc đọc dữ liệu từ đĩa. Ngay cả khi/nếu dữ liệu đó nằm trong bộ nhớ cache, bạn sẽ phải trải qua một số lượng mã hợp lý để lấy nó từ bộ nhớ cache vào trong tiến trình của bạn. Đường dẫn cũng thường khá ngắn - bất kỳ hơn một vài trăm byte là khá bất thường. Cùng nhau này có nghĩa là bạn có thể khá hợp lý xây dựng dây cho tất cả các đường dẫn bạn cần mà không có bất kỳ vấn đề thực sự. Thời gian xây dựng dây vẫn còn khá nhỏ so với thời gian đọc dữ liệu từ đĩa. Điều đó có nghĩa là bạn thường có thể bỏ qua thời gian dành cho thao tác chuỗi và chỉ làm việc tối ưu hóa việc sử dụng đĩa.

Trải nghiệm của riêng tôi là cho hầu hết các thư mục lướt qua tìm kiếm rộng rãi thường thích hợp hơn - khi bạn duyệt qua thư mục hiện tại, hãy đặt đường dẫn đầy đủ đến tất cả các thư mục con trong một hàng đợi ưu tiên. Khi bạn hoàn thành việc duyệt qua thư mục hiện tại, hãy kéo mục đầu tiên từ hàng đợi và duyệt qua nó, tiếp tục cho đến khi hàng đợi rỗng. Điều này thường cải thiện vị trí bộ nhớ cache, do đó, nó làm giảm lượng thời gian đọc đĩa. Tùy thuộc vào hệ thống (tốc độ đĩa so với tốc độ CPU, tổng bộ nhớ có sẵn, v.v.) nó gần như luôn luôn nhanh nhất là tốc độ truyền tải đầu tiên, và có thể dễ dàng lên tới gấp đôi (hoặc lâu hơn).

+0

Tại sao lại sử dụng hàng đợi ưu tiên và không phải thứ gì đơn giản hơn như hàng đợi FIFO? Bạn sử dụng gì làm thuộc tính ưu tiên? –

+0

@Andrew: Câu hỏi hay. Một FIFO sẽ hoạt động hoàn hảo. Một PQ chỉ đơn giản là làm cho nó dễ dàng để tạo ra kết quả theo thứ tự sắp xếp theo tên, mà người dùng thường thích (chắc chắn, tôi thích nó khi tôi đang sử dụng nó ...) –

+0

cảm ơn, có ý nghĩa, tôi đã không xem xét đầu ra định dạng. –

15

Bạn đã thử ftw() hay còn gọi là Tệp Tree Walk Walk?

SNIPPIT từ man 3 ftw:

int ftw(const char *dir, int (*fn)(const char *file, const struct stat *sb, int flag), int nopenfd);

ftw() đi qua cây thư mục bắt đầu từ dir thư mục được chỉ định. Đối với mỗi mục nhập tìm thấy trong cây, nó gọi fn() với tên đường dẫn đầy đủ của mục nhập, con trỏ tới cấu trúc chỉ số (2) cho mục nhập và cờ int

+2

Và 'nftw()' đôi khi - có một sự khác biệt tinh tế giữa hai, nhưng tôi phải đi bashing thủ công để tìm nó ... http: //www.opengroup.org/onlinepubs/9699919799/functions/nftw. html ("Hàm nftw() sẽ đệ quy đệ quy hệ thống phân cấp thư mục bắt nguồn từ đường dẫn. Hàm nftw() có tác dụng tương tự với ftw() ngoại trừ việc cần thêm một cờ đối số ..."). –

+0

Cảm ơn bạn đã nhắc tôi về 'nftw()'. Tôi nhớ sử dụng nó trên 'ftw()' bởi vì trước đây cho phép bạn chuyển một lá cờ để bảo nó không tái sử dụng các liên kết tượng trưng (trong số những thứ khác). – SiegeX

+0

Chúng ta có thể sử dụng ftw() để thực hiện truyền tải thông qua một thư mục không? (để chúng tôi có thể xóa các tập tin/thư mục từ dưới cùng của cấu trúc cây thư mục) – Dinushan

2

Có thể quá mức cần thiết cho ứng dụng của bạn, nhưng đây là thư viện được thiết kế để duyệt qua một cây thư mục với hàng trăm triệu tệp.

https://github.com/hpc/libcircle

Các vấn đề liên quan