我有一個名為filelist.txt. 此檔案串列包含一個檔案串列,這些檔案根據其目錄前綴分組排列。內容的順序很重要,因為檔案必須以特定的檔案名開始和結束,并且第一個子組必須首先出現。例如,該檔案如下所示:
config.txt
../../linux/a.txt
../../linux/c.txt
../../linux/d.txt
../../linux/b.txt
../../certificates/../../d.txt
../../certificates/../../a.txt
../../certificates/../../c.txt
../../certificates/../..b.txt
../../bin/b.txt
../../bin/a.txt
properties.server
我想知道的是,在保持子組的整體順序的同時,以干凈有效的方式在這些子組中進行排序的最佳方法是什么?
我撰寫了這段代碼,它可以按子組過濾并對其進行排序:
try(Stream<String> lines = Files.lines(Paths.get("src/filelist.txt"))){
List<String> linez = lines.filter(l -> l.contains("linux")).sorted().collect(Collectors.toList());
BufferedWriter bw = new BufferedWriter(new FileWriter("src/output.txt"));
for(String line : linez){
bw.write(line "\n");
}
bw.close();
我可以有一個List<String>包含我所有行的檔案,我可以過濾原始檔案行,對它們進行排序,然后將它們添加到此串列中。
有幾件事我不喜歡:
- 我沒有覆寫原始檔案,我正在寫入一個新檔案。我想看看是否有辦法覆寫而不是寫入新檔案。
- 似乎有點遲鈍。如果添加了新的目錄前綴怎么辦?然后我將不得不再次編輯此代碼以過濾和排序新的目錄前綴組。此外,根據每個過濾器為每個子組制作一堆不同的串列會感覺很奇怪,而不是做類似的事情
lines.filter(...).sort().filter(...).sort().filter(...),但我認為這種語法還沒有意義,因為一旦應用過濾器,在排序之后我無法取消應用過濾器。能夠過濾,就地排序,然后應用另一個過濾器和排序,等等,這將是非常好的。
我在這里有什么選擇?
uj5u.com熱心網友回復:
流不是最好的方法(至少不是整個作業;也許是其中的一部分)。下面使用查看每一行的方法,如果到最后一個組件的路徑與之前讀取的路徑相同,則將其添加到串列中,如果不是,則對該路徑串列進行排序,然后將它們添加到排序結果,因此每個前綴組的順序不變,但每個組最終都已排序。
覆寫輸入檔案只是使用同一個檔案進行讀取和寫入的問題 - 只需確保在打開它進行寫入之前讀取所有內容。下面只是在處理檔案之前將檔案讀入串列。
import java.util.ArrayDeque;
import java.nio.file.Path;
import java.nio.file.Files;
import java.io.IOException;
import java.io.PrintWriter;
public class Demo {
public static void main(String[] args) {
try {
Path datafile = Path.of(args[0]);
var lines = Files.readAllLines(datafile);
var sorted = new ArrayDeque<String>(lines.size());
// Add first line
sorted.addLast(lines.get(0));
// Iterate through all the remaining but the last line
var block = new ArrayDeque<Path>();
for (int i = 1; i < lines.size() - 1; i ) {
Path p = Path.of(lines.get(i));
if (!block.isEmpty()
&& !p.getParent().equals(block.getLast().getParent())) {
// Current path has a different prefix than the current
// block. Sort block and add it to output
block.stream()
.sorted()
.forEachOrdered(sp ->
sorted.addLast(sp.toString()));
// And reset for a new path prefix
block.clear();
}
block.addLast(p);
}
// Handle the last block of paths
block.stream()
.sorted()
.forEachOrdered(sp -> sorted.addLast(sp.toString()));
// Add last line
sorted.addLast(lines.get(lines.size() - 1));
// Overwrite the original input file
Files.write(datafile, sorted);
} catch (IOException e) {
System.err.println(e);
System.exit(1);
}
}
}
uj5u.com熱心網友回復:
這基于Shawn 的回答,但通過直接對原始串列中受影響的組進行排序來簡化操作。
try {
Path datafile = Path.of(args[0]);
var lines = Files.readAllLines(datafile);
// ensure that the list is mutable
if(lines.getClass() != ArrayList.class) lines = new ArrayList<>(lines);
int first = 1; // skip first line
int last = lines.size() - 1; // and last line
if(first >= last) return;
Path previous = Path.of(lines.get(first));
for (int i = first 1; i < last; i ) {
Path p = Path.of(lines.get(i));
if(!p.getParent().equals(previous.getParent())) {
lines.subList(first, i).sort(null);
first = i;
previous = p;
}
}
// Handle the last block of paths
if(first < last) lines.subList(first, last).sort(null);
// Overwrite the original input file
Files.write(datafile, lines);
} catch (IOException e) {
System.err.println(e);
System.exit(1);
}
請注意,回傳的串列型別Files.lines未指定,但ArrayList在實踐中始終是一個。該解決方案可以保護自己免受回傳串列不可變但在現實生活中不執行復制操作的假設情況。所以它在形式上是正確和有效的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/411321.html
標籤:
