การใช้งานรายการที่เชื่อมโยงของไดเร็กทอรี FileSystem
ฉันกำลังเขียนคลาส wrapper ใน Java ซึ่งจะแทนที่เมธอดของการนำไปใช้งานที่มีอยู่เพื่อจัดการกับ edge case การใช้งานเต็มรูปแบบซับซ้อนกว่าที่จะต้องโพสต์ไว้ที่นี่เล็กน้อยดังนั้นฉันจึงเขียนคลาสแบบง่ายที่มีเฉพาะส่วนที่ฉันขอความช่วยเหลือเท่านั้น
สรุปปัญหา
ฉันกำลังขยายสองชั้น:
คลาสหนึ่งได้รับการออกแบบเป็นคลาส "การแจงนับ" โดยแยกไดเร็กทอรีบนระบบไฟล์ที่มีลิงก์สัญลักษณ์ไปยังไดเร็กทอรีอื่น (โลกแห่งความจริง: "/ sys / block".). มีสองวิธีscan()
วิธีการสร้างรายการของไดเร็กทอรีย่อย (เชื่อมโยง) และgetFirst()
ส่งกลับองค์ประกอบแรกของรายการ
คลาสที่สองคือคลาส "รายการ" ซึ่งเป็นนามธรรมของไดเร็กทอรีชี้ไปที่แจกแจงโดยคลาสแรก มีสองวิธีgetName()
วิธีการคืนเส้นทางของไดเรกทอรีเป็นสตริงและgetNext()
วิธีการวนซ้ำไปยังองค์ประกอบถัดไป
ข้อ จำกัด
- เข้ากันได้กับ JDK 8 หรือรุ่นก่อนหน้า
- อาจถือว่าการใช้งานแบบเธรดเดียว
- ตัวสร้างอาจเปลี่ยนแปลงได้ตามความต้องการ
- ต้องใช้ (อย่างน้อย) สองคลาสที่ระบุและสองวิธีในแต่ละคลาส
จุดเน้นของการทบทวน
scan()
วิธีคือการต่อสู้ของฉันที่นี่ ฉันคิดว่าฉันอาจมีวิธีแก้ปัญหาที่ซับซ้อนเกินไปในสองวิธี:
try ... catch
บล็อกที่ซ้อนกันในscan()
วิธีนี้ดูเหมือนผิดปกติ ฉันพลาดวิธีจัดการที่ง่ายกว่านี้หรือเปล่า- (อัปเดต: ตอบคำถามที่สองนี้ด้วยตัวเองด้านล่าง) รูปแบบการนำไปใช้นั้นเห็นได้ชัดว่าเป็นรายการที่เชื่อมโยงกันเพียงอย่างเดียวซึ่งฉันกำลังดำเนินการโดยส่งต่อ
ArrayList
การนำไปใช้งาน ฉันนึกภาพออกว่าDirEntry
คลาสที่มีเฉพาะของมันPath
และDirEntry next
อ็อบเจกต์ แต่ความพยายามในการสร้างรายการดังกล่าวดูเหมือนซับซ้อนหรือมีประสิทธิภาพน้อยกว่าวิธีแก้ปัญหาที่ฉันสร้างขึ้น
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();
}
}
}
```
คำตอบ
ฉันได้หาวิธีที่ง่ายกว่าในการทำคำถามที่สองแล้วคือการสร้างรายการที่เชื่อมโยงโดยการทำซ้ำย้อนกลับจากเส้นทางที่สร้างขึ้น
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;
}
// ...
}
```