2015-09-30 13 views
6

Tôi có một vấn đề đơn giản: Tôi lặp cấu trúc thư mục lớn và sâu sắc lồng nhau sử dụng Files.walkFileTree như thế này:Efficently tìm tập tin trong thư mục cụ thể

final int CUTOFF = 5; 
final List<Path> foundList = new ArrayList<>(); 
Files.walkFileTree(codeRoot, new SimpleFileVisitor<Path>() { 
    @Override 
    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) 
      throws IOException { 
     String rPath = codeRoot.relativize(dir).toString(); 
     int level = rPath.length() - rPath.replace("/", "").length(); 
     if (dir.getFileName().toString().equals("target") || level < CUTOFF) { 
      return FileVisitResult.CONTINUE; 
     } 
     return FileVisitResult.SKIP_SUBTREE; 
    } 
    @Override 
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) 
      throws IOException { 
     if (file.getFileName().toString().endsWith(".txt")) { 
      foundList.add(file); 
     } 
     return FileVisitResult.CONTINUE; 
    } 
}); 

Mục tiêu của tôi là để thêm tất cả các file dưới một thư mục cụ thể target mà tôi biết tối đa là CUTOFF cấp dưới codeRoot.

Tôi đang tìm cách hiệu quả hơn để thực hiện việc này về các cuộc gọi stat() cần thiết hoặc ai đó nói "không thể thực hiện".

Cấp độ ngôn ngữ là Java8.

+0

Tại sao bạn nghĩ rằng nó có thể được thực hiện? walkFileTree sử dụng NIO có nghĩa là nó không thường xuyên như đi bộ bản địa về hiệu suất. Nếu bạn gọi điều này thường xuyên, bạn có thể sử dụng một số cache. Một ví dụ về bộ đệm: thời gian sửa đổi cuối cùng của thư mục (trong một số hệ thống tập tin) để lưu vào bộ nhớ cache các thư mục không thay đổi kể từ lần gọi cuối cùng. –

+0

@MladenAdamovic Tôi chủ yếu nghĩ rằng tôi có thể thiếu một số thuật toán ngắn-cắt, kể từ khi thực hiện của tôi là ngây thơ như nó được. Ngoài ra, tôi không có đầu mối nếu 'relativize()' có tác động đến hiệu suất fs mà tôi có thể tránh được. Ý tưởng của bạn về tối ưu hóa chạy lặp lại là một điều tốt, cảm ơn! – mabi

+0

Bạn đang sử dụng gì làm thước đo tốc độ? Bạn đã thực hiện một giải pháp tương tự trong C/C++ làm điểm tham chiếu chưa? Tại sao bạn nghĩ rằng nó không hiệu quả cho đến nay? – Fallso

Trả lời

1

Thuật toán được trình bày là truy vấn một lần. Trong trường hợp này, bạn đang mắc kẹt với một tìm kiếm thời gian tuyến tính thông qua tất cả các thư mục. Bạn không thể giảm thiểu sự cần thiết phải kiểm tra từng thư mục theo cách đó. Bạn có thể xem bộ nhớ đệm, tất nhiên, nhưng nếu bạn đang bận tâm với sự kết hợp bộ nhớ cache và cần hiệu suất cao, bạn cũng có thể xem xét việc xây dựng một chỉ mục. Trong cả hai trường hợp, tôi sẽ giải quyết câu hỏi bạn đã hỏi, đó là về truy vấn một lần.

Phiên bản Files.walkFileTree bạn đang sử dụng đi bộ toàn bộ cây, bao gồm tất cả các tệp và thư mục vượt quá mức tối đa. Bạn đang loại trừ một cách rõ ràng chúng bằng cách phân tích cú pháp tên đường dẫn, một kỹ thuật mà bạn nghĩ đúng có thể không hiệu quả. Giải pháp là luôn đọc tài liệu. Có phiên bản thứ hai của Files.walkFileTree với chiều sâu tối đa làm đối số rõ ràng. Từ một số: tutorial on walking the file tree:

Phương pháp walkFileTree thứ hai cho phép bạn chỉ định bổ sung giới hạn về số lượng truy cập và tập hợp các tập tin đính kèm.

Nếu bạn sử dụng phương pháp thứ hai, bạn sẽ chỉ truy cập các tệp ứng viên ở mức tối đa và bạn có thể tránh tất cả các mã tạo thành subtrees.

+0

Tốt bắt về phương pháp bổ sung. Điều đó đã nhắc tôi xem xét triển khai 'walkFileTree', sử dụng' stack' để theo dõi các thư mục cần truy cập. Sự trở lại của 'SKIP_SUBTREE' sẽ bật phần tử ngăn xếp, mà * nên * kết thúc truyền tải xa hơn điều này (bằng cách không tạo mục nhập ngăn xếp mới cho thư mục này), đúng không? Vì vậy, bạn đang nói hai là tương đương nhưng sử dụng 'maxDepth' biến thể, tôi có thể cắt tính toán chiều sâu bằng tay? – mabi

+0

@mabi Thao tác 'SKIP_SUBTREE' thường được gọi là" cắt tỉa ". Nó dừng truyền tải tại nút hiện tại, tránh truyền tải ở tất cả các nút con của nó, và đơn giản là tiếp tục _as if_ subtree được duyệt qua. Vì vậy, có, phân tích của bạn về hành vi này là chính xác. Đối với câu hỏi thứ hai, việc thực hiện sử dụng 'maxDepth' thực sự theo dõi độ sâu (trên thực tế, nó đã làm như vậy, vì nó là kích thước của ngăn xếp), giảm bớt sự cần thiết phải tính toán nó. Mẹo: không bao giờ viết mã mà người khác đã viết cho bạn. – eh9

+0

Điểm công bằng. Kể từ khi bạn đã đạt cả hai "bạn không thể làm nhiều hơn" và "có chỗ cho tối ưu hóa" điểm, tôi sẽ trao cho bạn tiền thưởng EOD trừ khi ai đó thổi tâm trí của tôi trước đó. – mabi

1

tùy chọn Tối ưu hóa:

1) đăng ký thông báo khi thư mục thay đổi: https://docs.oracle.com/javase/tutorial/essential/io/notification.html này có thể làm việc trong nền

2) (ít tối ưu) sử dụng bộ nhớ đệm của các thư mục không thay đổi (trong một số hệ thống tập tin): sử dụng thời gian sửa đổi cuối cùng của thư mục để lưu trữ thư mục không thay đổi kể từ lần gọi cuối cùng

Sử dụng grepcode, tôi không thể tìm thấy cách tương đối được triển khai, tôi nghĩ rằng nó có thể được thực thi nguyên bản. Tôi đoán nó được thực hiện với các hoạt động chuỗi đơn giản của các giá trị đã được kéo và tôi không nghĩ rằng nó đang truy cập stat() ở tất cả. Bạn có thể kiểm tra nó mặc dù, làm cho một mã giả (mà không làm việc bất cứ điều gì hữu ích) có và không có relativize và đo lường tác động thực sự khi đi qua rất nhiều tập tin. Hơn bạn có thể chắc chắn bạn không bị mất hiệu suất nhiều do relativize

+0

'relativize()' là JVM + OS phụ thuộc, trong trường hợp của tôi nó được thực hiện thông qua 'sun.nio.fs.UnixPath'. Mã được biên dịch lại rất khó để theo dõi. – mabi

+0

tạo mã thử nghiệm (duyệt qua thư mục không làm gì hữu ích) có và không có các hoạt động tương đối và thử nghiệm. Nếu bạn nhận được + 30% hiệu suất ít hơn đã relativize, bạn nên cố gắng tìm ra cách để sửa chữa rằng –

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