Implémentation de la liste chaînée des répertoires FileSystem
J'écris des classes wrapper en Java qui remplacent les méthodes d'une implémentation existante, afin de gérer un cas limite. L'implémentation complète est un peu plus complexe que ce qui doit être publié ici, j'ai donc écrit une classe simplifiée contenant uniquement les parties pour lesquelles je demande de l'aide.
Résumé du problème
Je prolonge deux classes :
Une classe conçue comme une classe "d'énumération", faisant abstraction d'un répertoire sur un système de fichiers qui contient des liens symboliques vers d'autres répertoires. (Monde réel : "/sys/block".). Il a deux méthodes, une scan()
méthode pour générer la liste des sous-répertoires (liés) et une getFirst()
pour retourner le premier élément de la liste.
La deuxième classe est une classe "d'entrée", faisant abstraction du répertoire pointé énuméré par la première classe. Il a deux méthodes, une getName()
méthode pour renvoyer le chemin du répertoire sous forme de chaîne et une getNext()
méthode pour parcourir l'élément suivant.
Contraintes
- Compatibilité avec JDK 8 ou antérieur
- Une utilisation à un seul filetage peut être supposée
- Les constructeurs peuvent être modifiés selon les besoins.
- Doit implémenter (au moins) les deux classes spécifiées et les deux méthodes sur chacune.
Objet de l'examen
La scan()
méthode est mon combat ici. Je pense que j'ai peut-être trop compliqué la solution de deux manières:
try ... catch
Les blocs imbriqués dans lascan()
méthode semblent inhabituels. Me manque-t-il un moyen plus simple de gérer cela?- (MISE À JOUR : auto-répondu à cette deuxième question, ci-dessous.) Le modèle implémenté est évidemment une liste à liens uniques sur laquelle je travaille en faisant passer une
ArrayList
implémentation. Je peux imaginer laDirEntry
classe ne contenant que sonPath
et unDirEntry next
objet, mais les tentatives de génération d'une telle liste semblent encore plus complexes ou moins performantes que la solution de contournement que j'ai créée.
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();
}
}
}
```
Réponses
J'ai trouvé un moyen plus simple de répondre à la deuxième question, en construisant la liste chaînée en itérant en arrière à partir des chemins générés.
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;
}
// ...
}
```