파일 시스템 디렉토리의 링크 된 목록 구현

Aug 16 2020

엣지 케이스를 처리하기 위해 기존 구현의 메서드를 재정의하는 Java로 래퍼 클래스를 작성하고 있습니다. 전체 구현은 여기에 게시해야하는 것보다 조금 더 복잡하므로 도움을 요청하는 부분 만 포함 된 단순화 된 클래스를 작성했습니다.

문제 요약

두 클래스를 확장하고 있습니다.

"열거"클래스로 설계된 하나의 클래스는 다른 디렉토리에 대한 심볼릭 링크를 포함하는 파일 시스템의 디렉토리를 추상화합니다. (실제 : "/ sys / block".). 여기에는 scan()(연결된) 하위 디렉터리 목록을 생성 하는 메서드와 목록의 getFirst()첫 번째 요소를 반환하는 두 가지 메서드가 있습니다.

두 번째 클래스는 첫 번째 클래스에 의해 열거 된 가리키는 디렉터리를 추상화하는 "엔트리"클래스입니다. 여기에는 getName()디렉터리 경로를 문자열로 반환하는 getNext()메서드 와 다음 요소로 반복 하는 메서드 의 두 가지 메서드가 있습니다.

제약

  • JDK 8 또는 이전 버전과의 호환성
  • 단일 스레드 사용을 가정 할 수 있습니다.
  • 생성자는 필요에 따라 변경 될 수 있습니다.
  • 최소한 두 개의 지정된 클래스와 각각에 대해 두 개의 메서드를 구현해야합니다.

검토의 초점

scan()방법은 여기 내 투쟁이다. 두 가지 방법으로 솔루션을 지나치게 복잡하게 만들 수 있다고 생각합니다.

  • 메서드 의 중첩 된 try ... catch블록 scan()이 비정상적으로 보입니다. 이것을 처리하는 더 간단한 방법을 놓치고 있습니까?
  • (업데이트 : 아래의 두 번째 질문에 자체 답변했습니다.) 구현 된 패턴은 구현을 전달하여 작업중인 단일 연결 목록입니다 ArrayList. 해당 DirEntry클래스 PathDirEntry 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();
        }
    }
}
```

답변

DanielWiddis Aug 16 2020 at 00:27

생성 된 경로에서 거꾸로 반복하여 연결된 목록을 작성하는 두 번째 질문을 수행하는 더 간단한 방법을 알아 냈습니다.

    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;
        }

       // ...
    }
```