Triển khai Danh sách được Liên kết của các thư mục FileSystem
Tôi đang viết các lớp trình bao bọc trong Java để ghi đè các phương thức của một triển khai hiện có, để xử lý một trường hợp cạnh. Việc triển khai đầy đủ phức tạp hơn một chút so với nhu cầu được đăng ở đây, vì vậy tôi đã viết một lớp đơn giản hóa chỉ chứa những phần tôi đang yêu cầu hỗ trợ.
Tóm tắt vấn đề
Tôi đang mở rộng hai lớp:
Một lớp được thiết kế như một lớp "liệt kê", trừu tượng hóa một thư mục trên hệ thống tệp chứa các liên kết tượng trưng đến các thư mục khác. (Thế giới thực: "/ sys / block".). Nó có hai phương thức, một scan()
phương thức để tạo danh sách các thư mục con (được liên kết) và một phương thức getFirst()
để trả về phần tử đầu tiên của danh sách.
Lớp thứ hai là lớp "entry", trừu tượng hóa thư mục trỏ đến được liệt kê bởi lớp đầu tiên. Nó có hai phương thức, một getName()
phương thức để trả về đường dẫn của thư mục dưới dạng chuỗi và một getNext()
phương thức để lặp tới phần tử tiếp theo.
Ràng buộc
- Khả năng tương thích với JDK 8 trở xuống
- Sử dụng đơn luồng có thể được giả định
- Cấu tạo có thể được thay đổi theo yêu cầu.
- Phải triển khai (ít nhất) hai lớp được chỉ định và hai phương thức trên mỗi lớp.
Trọng tâm xem xét
Các scan()
phương pháp là cuộc đấu tranh của tôi ở đây. Tôi nghĩ rằng tôi có thể đã phức tạp hóa giải pháp theo hai cách:
- Các
try ... catch
khối lồng nhau trongscan()
phương thức có vẻ không bình thường. Tôi có thiếu một cách đơn giản hơn để xử lý điều này không? - (CẬP NHẬT: Tự trả lời câu hỏi thứ hai này, bên dưới.) Mẫu được triển khai rõ ràng là một danh sách được liên kết đơn lẻ mà tôi đang làm việc bằng cách chuyển xung quanh một
ArrayList
triển khai. Tôi có thể tưởng tượngDirEntry
lớp chỉ chứa nóPath
và mộtDirEntry next
đối tượng, nhưng việc cố gắng tạo một danh sách như vậy có vẻ phức tạp hơn hoặc kém hiệu quả hơn so với cách giải quyết mà tôi đã tạo.
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class DeviceList {
/**
* Class representing a parent directory which contains symbolic links to other
* directories
*/
static class DirEnumerator {
private Path dirPath;
private List<DirEntry> entryList = Collections.emptyList();
public DirEnumerator(String path) {
dirPath = FileSystems.getDefault().getPath(path);
}
/**
* Scans the directory for entries
*
* @return The number of entries found
*/
public int scan() {
try (Stream<Path> paths = Files.walk(dirPath)) {
List<Path> linkedDirs = paths.filter(Files::isSymbolicLink).map(p -> {
try {
return Files.readSymbolicLink(p);
} catch (IOException e) {
return p;
}
}).collect(Collectors.toList());
this.entryList = new ArrayList<>();
for (int i = 0; i < linkedDirs.size(); i++) {
this.entryList.add(new DirEntry(entryList, linkedDirs.get(i), i));
}
return this.entryList.size();
} catch (IOException e) {
this.entryList = Collections.emptyList();
return 0;
}
}
/**
* Gets the first entry in the scanned list
*
* @return The first entry if it exists; null otherwise
*/
public DirEntry getFirst() {
return entryList.isEmpty() ? null : entryList.get(0);
}
}
/**
* Class representing a directory
*/
static class DirEntry {
private List<DirEntry> entryList;
private Path path;
private int index;
public DirEntry(List<DirEntry> entryList, Path path, int i) {
this.entryList = entryList;
this.path = path;
this.index = i;
}
/**
* Gets the path name of the directory entry
*
* @return a string representing the path
*/
public String getName() {
return this.path.toString();
}
/**
* Gets the next entry in the list
*
* @return the next entry if it exists; null otherwise
*/
public DirEntry getNext() {
int nextIndex = index + 1;
return nextIndex < entryList.size() ? entryList.get(nextIndex) : null;
}
}
public static void main(String[] args) {
// Test on any directory containing symbolic links to other directories
DirEnumerator de = new DirEnumerator("/sys/block");
int n = de.scan();
System.out.println("Found " + n + " directories.");
DirEntry e = de.getFirst();
while (e != null) {
System.out.println("Directory: " + e.getName());
e = e.getNext();
}
}
}
```
Trả lời
Tôi đã tìm ra một cách đơn giản hơn để thực hiện câu hỏi thứ hai, xây dựng Danh sách được liên kết bằng cách lặp lại từ các đường dẫn đã tạo.
static class DirEnumerator {
private Path dirPath;
private DirEntry first = null;
// ...
public int scan() {
try (Stream<Path> paths = Files.walk(dirPath)) {
List<Path> linkedDirs = paths.filter(Files::isSymbolicLink).map(p -> {
try {
return Files.readSymbolicLink(p);
} catch (IOException e) {
return p;
}
}).collect(Collectors.toList());
this.first = null;
int i = linkedDirs.size();
while (i-- > 0) {
this.first = new DirEntry(linkedDirs.get(i), first);
}
return linkedDirs.size();
} catch (IOException e) {
this.first = null;
return 0;
}
}
// ...
}
static class DirEntry {
private Path path;
private DirEntry next;
public DirEntry(Path path, DirEntry next) {
this.path = path;
this.next = next;
}
// ...
}
```