Implementazione dell'elenco collegato delle directory del FileSystem
Sto scrivendo classi wrapper in Java che sovrascrivono i metodi di un'implementazione esistente, al fine di gestire un caso limite. L'implementazione completa è un po' più complessa di quanto debba essere pubblicata qui, quindi ho scritto una classe semplificata contenente solo le parti su cui richiedo assistenza.
Riepilogo del problema
Sto estendendo due classi:
Una classe progettata come classe di "enumerazione", astraendo una directory su un filesystem che contiene collegamenti simbolici ad altre directory. (Mondo reale: "/sys/block".). Ha due metodi, un scan()
metodo per generare l'elenco delle sottodirectory (collegate) e un metodo getFirst()
per restituire il primo elemento dell'elenco.
La seconda classe è una classe "entry", che astrae la directory puntata enumerata dalla prima classe. Ha due metodi, un getName()
metodo per restituire il percorso della directory come una stringa e un getNext()
metodo per iterare all'elemento successivo.
Vincoli
- Compatibilità con JDK 8 o versioni precedenti
- Si può presumere l'uso a thread singolo
- I costruttori possono essere modificati come richiesto.
- Deve implementare (almeno) le due classi specificate ei due metodi su ciascuna.
Focus della revisione
Il scan()
metodo è la mia lotta qui. Penso di aver complicato eccessivamente la soluzione in due modi:
try ... catch
I blocchi annidati nelscan()
metodo sembrano insoliti. Mi sto perdendo un modo più semplice per gestirlo?- (AGGIORNAMENTO: risposta automatica a questa seconda domanda, di seguito.) Il modello implementato è ovviamente un elenco collegato singolarmente su cui sto lavorando passando
ArrayList
un'implementazione. Posso immaginare che laDirEntry
classe contenga solo la suaPath
e unDirEntry next
oggetto, ma i tentativi di generare un tale elenco sembrano ancora più complessi o meno performanti della soluzione alternativa che ho creato.
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();
}
}
}
```
Risposte
Ho trovato un modo più semplice per fare la seconda domanda, costruendo l'elenco collegato iterando all'indietro dai percorsi generati.
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;
}
// ...
}
```