Implementasi Linked List dari direktori FileSystem
Saya menulis kelas pembungkus di Java yang mengganti metode implementasi yang ada, untuk menangani kasus tepi. Implementasi lengkapnya sedikit lebih kompleks daripada yang perlu diposting di sini, jadi saya telah menulis kelas sederhana yang hanya berisi bagian-bagian yang saya minta bantuannya.
Ringkasan Masalah
Saya memperluas dua kelas:
Satu kelas dirancang sebagai kelas "enumerasi", mengabstraksi direktori pada sistem file yang berisi tautan simbolis ke direktori lain. (Dunia nyata: "/ sys / block".). Ini memiliki dua metode, scan()
metode untuk menghasilkan daftar subdirektori (tertaut), dan getFirst()
untuk mengembalikan elemen pertama dari daftar.
Kelas kedua adalah kelas "entri", mengabstraksi direktori menunjuk-ke yang disebutkan oleh kelas pertama. Ini memiliki dua metode, getName()
metode untuk mengembalikan jalur direktori sebagai string, dan getNext()
metode untuk beralih ke elemen berikutnya.
Kendala
- Kompatibilitas dengan JDK 8 atau yang lebih lama
- Penggunaan single-threaded dapat diasumsikan
- Konstruktor dapat diubah sesuai kebutuhan.
- Harus mengimplementasikan (setidaknya) dua kelas yang ditentukan dan dua metode pada masing-masing.
Fokus tinjauan
The scan()
metode adalah perjuangan saya di sini. Saya pikir saya mungkin telah memperumit solusi dalam dua cara:
try ... catch
Blok bersarang dalamscan()
metode ini tampak tidak biasa. Apakah saya melewatkan cara yang lebih sederhana untuk menangani ini?- (PEMBARUAN: Jawab sendiri pertanyaan kedua ini, di bawah.) Pola yang diterapkan jelas merupakan daftar tertaut tunggal yang saya kerjakan dengan meneruskan
ArrayList
implementasi. Saya dapat membayangkanDirEntry
kelas yang hanya berisi ituPath
danDirEntry next
objek, tetapi upaya untuk menghasilkan daftar seperti itu tampaknya lebih kompleks atau kurang berkinerja daripada solusi yang saya buat.
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();
}
}
}
```
Jawaban
Saya telah menemukan cara yang lebih sederhana untuk melakukan pertanyaan kedua, membangun Daftar Tertaut dengan mengulang mundur dari jalur yang dihasilkan.
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;
}
// ...
}
```