Реализация связанного списка каталогов файловой системы
Я пишу классы-оболочки на Java, которые переопределяют методы существующей реализации для обработки крайнего случая. Полная реализация немного сложнее, чем должно быть здесь, поэтому я написал упрощенный класс, содержащий только те части, по которым я запрашиваю помощь.
Резюме проблемы
Я расширяю два класса:
Один класс разработан как класс «перечисления», абстрагирующий каталог в файловой системе, который содержит символические ссылки на другие каталоги. (Реальный мир: «/ 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;
}
// ...
}
```