diff --git a/GC_DumpControllerLog.md b/GC_DumpControllerLog.md index 78307a0..56e437f 100644 --- a/GC_DumpControllerLog.md +++ b/GC_DumpControllerLog.md @@ -159,3 +159,161 @@ dumpEventLog(Cdb) → parse status & data → close() ``` + +--- + +## ZIP 壓縮處理細節 + +### 輸出檔案 + +**dlgDumpLog.java (舊型號)** +``` +./Log/{SN}_ControllerLog_{YYYY}_{M}_{D}_{H}_{m}_{s}.zip +``` + +**dlgDumpLog2.java (新型號)** +``` +Primary: ./Log/Primary_{SN}_ControllerLog.zip +Secondary: ./Log/Secondary_{SN}_ControllerLog.zip +合併: ./Log/{PrimarySN}_{SecondarySN}_ControllerLog_{YYYY}_{M}_{D}_{H}_{m}_{s}.zip +``` + +### 壓縮前的暫存檔 + +| Page Code | 檔案名稱 | 說明 | +|-----------|----------|------| +| 0x60 | EventPage.bin | Event Log | +| 0x61 | DebugPage.bin | Debug Log | +| 0x62 | DiskMetadataPage.bin | Disk Metadata | +| 0x63 | SpecialLogPage.bin | Special Log | +| 0x64 | TelMesPages.log | Telemetry Messages | + +### compressLog() 流程 (dlgDumpLog.java) + +```java +public void compressLog() { + File[] logs = new File[5]; + for(int i=0; i<=4; i++) { + logs[i] = getFile((byte)(i+0x60)); // 取得 5 個暫存檔 + } + + // 建立 ZIP 檔案 + Calendar rightNow = Calendar.getInstance(); + String filename = "./Log/" + PageDataDB.sSN.trim() + "_ControllerLog_" + + rightNow.get(Calendar.YEAR) + "_" + + (rightNow.get(Calendar.MONTH)+1) + "_" + + rightNow.get(Calendar.DAY_OF_MONTH) + "_" + + rightNow.get(Calendar.HOUR) + "_" + + rightNow.get(Calendar.MINUTE) + "_" + + rightNow.get(Calendar.SECOND) + ".zip"; + + FileOutputStream fout = new FileOutputStream(filename); + ZipOutputStream zout = new ZipOutputStream(fout); + zout.setLevel(5); // 壓縮等級 0-9 + + // 逐一壓縮每個檔案 + for (byte i = 0; i <= 4; i++) { + if(logs[i].exists()) { + ZipEntry ze = new ZipEntry(logs[i].getName()); + FileInputStream fin = new FileInputStream(logs[i]); + zout.putNextEntry(ze); + + // 特殊處理 Page 0x64 (TelMesPages.log) + if(i != 0x4) { + // 一般檔案:直接複製 + for(int c = fin.read(); c != -1; c = fin.read()) { + zout.write(c); + } + } else { + // TelMesPages.log: 每 40 bytes 為一筆記錄 + // 移除空字元 (0x00),只保留有效資料 + byte data; + boolean skipNull = false; + for(int j=0; j < logs[i].length()/40; j++) { + skipNull = false; + for(int k=0; k<40; k++) { + data = (byte)fin.read(); + if(data == 0x0a || skipNull == true) { + skipNull = true; + } else { + zout.write(data); + } + } + zout.write(0x0a); // 加上換行符 + } + } + + zout.closeEntry(); + fin.close(); + logs[i].delete(); // 刪除暫存檔 + } + } + zout.close(); +} +``` + +### compressLog() 流程 (dlgDumpLog2.java) + +```java +// 單一控制器壓縮 +public void compressLog(String sSN) { + String prefix = sSN.equals(PageDataDB.sSN) ? "Primary" : "Secondary"; + String filename = "./Log/" + prefix + "_" + sSN.trim() + "_ControllerLog.zip"; + // ... 同上邏輯 +} + +// 雙控制器合併壓縮 +public void compressLog2() { + File[] logs = new File[2]; + logs[0] = new File(sMaterFileNamePatch); // Primary + logs[1] = new File(sSlaveFileNamePatch); // Secondary + + // 合併成單一 ZIP,內含兩個 ZIP 檔 + String filename = "./Log/" + PageDataDB.sSN.trim() + "_" + + PageDataDB.sSlaveSN.trim() + "_ControllerLog_{timestamp}.zip"; + // ... +} +``` + +### ZIP 結構 + +``` +Archive: {SN}_ControllerLog_2024_3_29_10_30_45.zip +├── EventPage.bin (512 bytes/block) +├── DebugPage.bin (512 bytes/block) +├── DiskMetadataPage.bin (512 bytes/block) +├── SpecialLogPage.bin (512 bytes/block) +└── TelMesPages.log (40 bytes/record, 去除 null) +``` + +### 特殊處理:TelMesPages.log (Page 0x64) + +```java +// 原始資料: 40 bytes/record,包含 null (0x00) 字元 +// 處理邏輯: +// 1. 讀取每 40 bytes +// 2. 跳過開頭的 null 字元 +// 3. 遇到換行符 (0x0a) 後,後續全部視為有效資料 +// 4. 輸出時每筆記錄加上換行符 + +// Example: +// Input: [0x00, 0x00, 0x00, 0x31, 0x32, ..., 0x00, 0x00] +// Output: "12...data\n" +``` + +### Java 類別使用 + +```java +import java.util.zip.ZipOutputStream; +import java.util.zip.ZipEntry; +import java.util.Calendar; + +// 關鍵類別 +ZipOutputStream zout = new ZipOutputStream(fout); +zout.setLevel(5); // 壓縮等級 (0=儲存, 9=最大壓縮) +ZipEntry ze = new ZipEntry(filename); +zout.putNextEntry(ze); +zout.write(byte[] data); +zout.closeEntry(); +zout.close(); +```