我有一個類從目錄、子目錄和檔案中生成樹。并且需要滿足兩個條件。按以下方式對內容進行排序: - 目錄應該放在第一位。- 目錄和檔案按字典順序排序(不區分大小寫)。我在 Windows 系統上作業,下面的代碼作業正常,一切都按我想要的方式排序。目錄在前,并按字典順序排序。但我讀到在 Windows 系統上是按字典順序自動排序的。但是此代碼在 Linux 上不起作用,該行children.sort(Comparator.comparing(file -> file.isDirectory() ? -1 : 1));不起作用并且 files\directory 未按字典順序排序(不區分大小寫)。如何解決linux系統排序條件的問題?如何更改代碼中的排序條件?
import static java.util.Comparator.comparing;
public class TreeNode<T> implements Iterable<TreeNode<T>> {
public T data;
public TreeNode<T> parent;
public List<TreeNode<T>> children;
public boolean isRoot() {
return parent == null;
}
private List<TreeNode<T>> elementsIndex;
public TreeNode(T data) {
this.data = data;
this.children = new LinkedList<TreeNode<T>>();
this.elementsIndex = new LinkedList<TreeNode<T>>();
this.elementsIndex.add(this);
}
public TreeNode<T> addChild(T child) {
TreeNode<T> childNode = new TreeNode<T>(child);
childNode.parent = this;
this.children.add(childNode);
this.registerChildForSearch(childNode);
return childNode;
}
private void registerChildForSearch(TreeNode<T> node) {
elementsIndex.add(node);
if (parent != null)
parent.registerChildForSearch(node);
}
@Override
public String toString() {
return data != null ? data.toString() : "[data null]";
}
@Override
public Iterator<TreeNode<T>> iterator() {
TreeNode<T> iter = new TreeNode<T>((T) this);
return (Iterator<TreeNode<T>>) iter;
}
public static TreeNode<File> createDirTree(File folder) {
if (!folder.isDirectory()) {
throw new IllegalArgumentException("folder is not a Directory");
}
List<File> children = Arrays.asList(folder.listFiles());
children.sort(Comparator.comparing(file -> file.isDirectory() ? -1 : 1));
TreeNode<File> DirRoot = new TreeNode<File>(folder);
for (File file : children) {
if (file.isDirectory()) {
appendDirTree(file, DirRoot);
} else {
appendFile(file, DirRoot);
}
}
return DirRoot;
}
public static void appendDirTree(File folder, TreeNode<File> dirRoot) {
dirRoot.addChild(folder);
List<File> children = Arrays.asList(folder.listFiles());
children.sort(comparing(file -> file.isDirectory() ? -1 : 1));
for (File file : children) {
if (file.isDirectory()) {
appendDirTree(file, dirRoot.children.get(dirRoot.children.size() - 1));
} else {
appendFile(file, dirRoot.children.get(dirRoot.children.size() - 1));
}
}
}
public static void appendFile(File file, TreeNode<File> filenode) {
filenode.addChild(file);
}
public static String renderDirectoryTree(TreeNode<File> tree) {
List<StringBuilder> lines = renderDirectoryTreeLines(tree);
String newline = "\n";
StringBuilder sb = new StringBuilder(lines.size() * 20);
for (StringBuilder line : lines) {
sb.append(line);
sb.append(newline);
}
//System.out.println(sb);
return sb.toString();
}
public static List<StringBuilder> renderDirectoryTreeLines(TreeNode<File> tree) {
List<StringBuilder> result = new LinkedList<>();
result.add(new StringBuilder().append(tree.data.getName() " " calculateFileSize(tree) " bytes"));
Iterator<TreeNode<File>> iterator = tree.children.iterator();
while (iterator.hasNext()) {
List<StringBuilder> subtree = renderDirectoryTreeLines(iterator.next());
if (iterator.hasNext()) {
addSubtree(result, subtree);
} else {
addLastSubtree(result, subtree);
}
}
return result;
}
private static void addSubtree(List<StringBuilder> result, List<StringBuilder> subtree) {
Iterator<StringBuilder> iterator = subtree.iterator();
result.add(iterator.next().insert(0, "├─ "));
while (iterator.hasNext()) {
result.add(iterator.next().insert(0, "│ "));
}
}
private static void addLastSubtree(List<StringBuilder> result, List<StringBuilder> subtree) {
Iterator<StringBuilder> iterator = subtree.iterator();
result.add(iterator.next().insert(0, "└─ "));
while (iterator.hasNext()) {
result.add(iterator.next().insert(0, " "));
}
}
public static long calculateFileSize(TreeNode<File> tree) {
long fileSize = 0;
if (tree.data.isDirectory()) {
List<TreeNode<File>> children = tree.children;
for (TreeNode<File> child : children) {
fileSize = calculateFileSize(child);
}
} else {
fileSize = tree.data.length();
}
return fileSize;
}
}
uj5u.com熱心網友回復:
一個簡短的版本可能看起來像這樣。
Comparator<File> lexicographicFileComparator = Comparator.comparing(File::isFile)
.thenComparing(Comparator.naturalOrder());
你寫的File.compareTo甚至不檢查檔案是否存在。我不認為檢查檔案是否存在compareTo或Comparator檢查檔案是否存在。不存在的檔案應該先過濾。
我認為您的示例過度使用靜態方法。TreeNode應該是一個抽象類,而您有一個呼叫的實作FileTreeNode來替換您的靜態方法。
這是一個例子
樹節點
public abstract class TreeNode<N extends TreeNode<N, T>, T> implements Iterable<N> {
private static <N extends TreeNode<N, ?>> Stream<CharSequence> renderBranch(N node) {
Stream.Builder<CharSequence> result = Stream.builder();
result.add(node.printNode());
Iterator<N> iterator = node.getChildren().iterator();
while (iterator.hasNext()) {
Stream<CharSequence> subtree = renderBranch(iterator.next());
Iterator<CharSequence> subtreeIterator = subtree.iterator();
String branchSplit = "├─ ";
String branchSpacer = "│ ";
if (!iterator.hasNext()) {
branchSplit = "└─ ";
branchSpacer = " ";
}
result.add(branchSplit subtreeIterator.next());
while (subtreeIterator.hasNext()) {
result.add(branchSpacer subtreeIterator.next());
}
}
return result.build();
}
private final T data;
private final N parent;
private final List<N> children;
public TreeNode(T data) {
this(data, null);
}
protected TreeNode(T data, N parent) {
this.data = data;
this.parent = parent;
children = initChildren();
}
/**
* Called in constructor to initialize the children list.
*/
protected abstract List<N> initChildren();
/**
* Used to avoid unsafe casting.
*
* @return This
*/
protected abstract N instance();
/**
* TreeNode knows how to print the tree, but not how to print the current element. This way the child class can decide how it wants to be printed in the tree;
*
* @return readable text representation of node.
* @see TreeNode#renderBranch()
*/
protected abstract CharSequence printNode();
/**
* @return Returns a string representation of the entire branch starting at this node.
*/
public String renderBranch() {
Stream<CharSequence> lines = renderBranch(instance());
return lines.collect(Collectors.joining("\n"));
}
/**
* @return Returns a stream of the entire branch starting at this node
*/
public Stream<N> streamBranch() {
return Stream.concat(Stream.of(instance()), getChildren().stream().flatMap(TreeNode::streamBranch));
}
public T getData() {
return data;
}
public N getParent() {
return parent;
}
public List<N> getChildren() {
return children;
}
public boolean isRoot() {
return parent == null;
}
@Override
public String toString() {
return data != null ? data.toString() : "[data null]";
}
@Override
public Iterator<N> iterator() {
// No clue what you want to do here, but your method will not work.
return children.iterator();
}
}
檔案樹節點
public class FileTreeNode extends TreeNode<FileTreeNode, File> {
public FileTreeNode(File root) {
super(root);
}
protected FileTreeNode(File data, FileTreeNode parent) {
super(data, parent);
}
public long calculateFileSize() {
return streamBranch().mapToLong(value -> value.getData().length()).sum();
}
@Override
protected CharSequence printNode() {
return getData().getName() " " calculateFileSize() " bytes";
}
@Override
protected List<FileTreeNode> initChildren() {
File file = getData();
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null) {
return Arrays.stream(files)
.sorted(Comparator.comparing(File::isFile).thenComparing(Comparator.naturalOrder()))
.map(path -> new FileTreeNode(path, this))
.toList();
}
}
return Collections.emptyList();
}
@Override
protected FileTreeNode instance() {
return this;
}
}
用法
File file = new File("C:\\dir");
FileTreeNode rootNode = new FileTreeNode(file);
System.out.println(rootNode.renderBranch());
通過這種方式,您也可以輕松地TreeNode為其他類實作結構。例如File已經過時并被替換,Path所以也許你將來會想要一個PathTreeNode。誰知道。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/379973.html
