在開發 Java 通訊錄應用時,常遇到資料量過大導致介面載入緩慢的問題。使用者希望將儲存在 TXT 文件中的聯繫人記錄,以每頁 20 筆的方式分頁顯示,並提供上一頁、下一頁導航功能。
分頁邏輯本質上與資料庫分頁查詢一致:根據當前頁碼計算資料的起始與結束索引,僅讀取該範圍內的記錄。對於 TXT 文件,可採用「全量讀取後切片」或「流式讀取定位」兩種策略。
// 讀取所有行到 List
List<String> allLines = Files.readAllLines(Paths.get("D:/AddressBook.txt"), StandardCharsets.UTF_8);
int pageSize = 20;
int totalPages = (int) Math.ceil((double) allLines.size() / pageSize);
// 獲取指定頁面資料 (page 從 1 開始)
public List<String> getPageData(int page) {
int start = (page - 1) * pageSize;
int end = Math.min(start + pageSize, allLines.size());
return allLines.subList(start, end);
}
public List<String> readPage(String filePath, int page, int pageSize) throws IOException {
List<String> result = new ArrayList<>();
try (RandomAccessFile raf = new RandomAccessFile(filePath, "r")) {
long fileLength = raf.length();
long avgLineLength = estimateAvgLineLength(raf); // 預估平均行長
long startPos = (page - 1) * pageSize * avgLineLength;
raf.seek(Math.max(0, startPos));
// 略過不完整行
if (startPos > 0) raf.readLine();
String line;
while ((line = raf.readLine()) != null && result.size() < pageSize) {
result.add(line);
}
}
return result;
}
JTextArea 搭配 JScrollPane 展示分頁內容若需支援排序、篩選(如按性別查詢)後的分頁,建議先將符合條件的記錄索引收集到列表,再對索引列表進行分頁切片,避免重複掃描文件。
public class AddressBookPager {
private final String filePath;
private final int pageSize;
private List<Integer> lineOffsets; // 儲存每行起始偏移量
public AddressBookPager(String filePath, int pageSize) {
this.filePath = filePath;
this.pageSize = pageSize;
buildIndex();
}
private void buildIndex() throws IOException {
lineOffsets = new ArrayList<>();
try (RandomAccessFile raf = new RandomAccessFile(filePath, "r")) {
long offset = 0;
String line;
while ((line = raf.readLine()) != null) {
lineOffsets.add((int) offset);
offset = raf.getFilePointer();
}
}
}
public List<String> getPage(int page) throws IOException {
List<String> pageData = new ArrayList<>();
int startIdx = (page - 1) * pageSize;
if (startIdx >= lineOffsets.size()) return pageData;
try (RandomAccessFile raf = new RandomAccessFile(filePath, "r")) {
for (int i = startIdx; i < lineOffsets.size() && i < startIdx + pageSize; i++) {
raf.seek(lineOffsets.get(i));
pageData.add(raf.readLine());
}
}
return pageData;
}
}
採用索引映射方式可實現 O(1) 定位,大幅提升大文件分頁效能。實際專案中建議搭配 SwingWorker 異步載入,避免阻塞 UI 執行緒。