2013-10-17 37 views
3

我正在尋找最快的方法來生成將在文本文件輸出中使用的日期/時間的長列表。什麼,我想實現的一個例子:什麼是在Android中格式化大量日期/時間對象的最快方式?

1,2013年10月17日00:00:00,數據,數據
2,2013年10月17日00:00:01,數據,數據
3,2013-10-17 00:00:02,數據,數據
....

這是我必須遵守的格式,無法更改。這些數據可以很容易地達到100,000以上。什麼我目前做的是:

//text_output is a printstream to SD card 
logged_time = Calendar.getInstance(); 
dateFormat = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss"); 
// these values are gathered from a device via bluetooth 
logged_time.set(year, month, day, hour, minute, second); 

while(I_still_have_lines_to_process){ 
    // print the line 
    text_output.print(line_count + "," + dateFormat.format(logged_time.getTime()) + data etc.) 
    // add the sample rate to calculate next date/time 
    logged_time.add(Calendar.SECOND, sample_rate); 
} 

我發現,對於25萬線這一過程大約需要單獨的格式50秒。我也必須解析數據本身並通過藍牙傳輸。如果我能加快速度,用戶體驗將大大改善。有沒有更快的方法來做到這一點?

感謝您的閱讀!

+0

感謝您的回覆。藍牙通信實際上比較快,因爲我只是每行傳輸幾個字節。我還研究了一些解決方案,這些數據在數據進入時獨自坐在一個asynctask中,然後放在一起。但是,我發現我以這種方式快速耗盡內存,因爲我最終得到了一些數據副本 – Brian

+0

只是要確定 - 您確定格式化是問題而不是I/O?你有沒有分析過它,並發現大部分時間都花在'format()'上? –

+1

您是否嘗試過使用StringBuilder追加所有數據並僅打印/傳輸數據一次? – Mikel

回答

3

我重寫了你的代碼,我真的可以運行和測試,並以下面的代碼結束。這很粗糙,但適用於我,我會把我的工作放在上面。如果出現與您的實際行爲不符的情況,請通過它。

private static final int SAMPLE_RATE = 1; 

public static void main(String[] args) { 
    long time = System.currentTimeMillis(); 

    Calendar logged_time = Calendar.getInstance(); 
    Format dateFormat = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss"); 

    try (BufferedWriter writer = Files.newBufferedWriter(Paths.get("out.txt"), StandardCharsets.UTF_8)) { 
     for (int i = 0; i < 100000; i++) { 
      // print the line 
      writer.write(i + ", " + dateFormat.format(logged_time.getTime())); 
      writer.newLine(); 

      // add the sample rate to calculate next date/time 
      logged_time.add(Calendar.SECOND, SAMPLE_RATE); 
     } 
    } catch (IOException e) { 
     throw new RuntimeException(e); 
    } 

    System.out.println(System.currentTimeMillis() - time + " ms"); 
} 

當我在我的機器上運行這個時,我平均得到1000毫秒。

簡單地改變

dateFormat.format(logged_time.getTime()) 

dateFormat.format(logged_time) 

導致了平均730毫秒。您無需每次都製作新的對象Date

但我們可以做得更好!有重複的工作lot - 我們不必一次又一次地格式化整個日期。讓我們緩存大部分格式化的日期,並只檢查當秒溢出時是否需要重新格式化它:

private static final int SAMPLE_RATE = 1; 

public static void main(String[] args) { 
    long time = System.currentTimeMillis(); 

    Calendar logged_time = Calendar.getInstance(); 
    Format dateFormatNoSecs = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:"); 
    Format dateFormatSecs = FastDateFormat.getInstance("ss"); 

    String lastFormattedDateNoSecs = dateFormatNoSecs.format(logged_time); 
    int lastSecs = logged_time.get(Calendar.SECOND); 

    try (BufferedWriter writer = Files.newBufferedWriter(Paths.get("out.txt"), StandardCharsets.UTF_8)) { 
     for (int i = 0; i < 100000; i++) { 
      int secs = logged_time.get(Calendar.SECOND); 
      if (secs < lastSecs) { 
       // at least minutes changed, we need to reformat it 
       lastFormattedDateNoSecs = dateFormatNoSecs.format(logged_time); 
      } 
      // print the line 
      writer.write(i + ", " + lastFormattedDateNoSecs + dateFormatSecs.format(logged_time)); 
      writer.newLine(); 

      // add the sample rate to calculate next date/time 
      logged_time.add(Calendar.SECOND, SAMPLE_RATE); 
      lastSecs = secs; 
     } 
    } catch (IOException e) { 
     throw new RuntimeException(e); 
    } 

    System.out.println(System.currentTimeMillis() - time + " ms"); 
} 

610毫秒。

最後微優化:自定義手動格式化程序秒。奇怪的是,DecimalFormat對於秒格式化要比FastDateFormat慢。但是,一個簡單的開關是最快的:

public class TwoDigitIntegerFormatter { 

    public static String format(int number) { 
     assert (number >= 0) && (number <= 99); 

     switch (number) { 
      case 0: return "00"; 
      case 1: return "01"; 
      case 2: return "02"; 
      case 3: return "03"; 
      case 4: return "04"; 
      case 5: return "05"; 
      case 6: return "06"; 
      case 7: return "07"; 
      case 8: return "08"; 
      case 9: return "09"; 
      default: return String.valueOf(number); 
     } 
    } 

} 

我們可以手動保持第二計數,太:

private static final int SAMPLE_RATE = 1; 

public static void main(String[] args) { 
    long time = System.currentTimeMillis(); 

    Calendar logged_time = Calendar.getInstance(); 
    Format dateFormatNoSecs = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:"); 

    String lastFormattedDateNoSecs = dateFormatNoSecs.format(logged_time); 
    int secs = logged_time.get(Calendar.SECOND); 

    try (BufferedWriter writer = Files.newBufferedWriter(Paths.get("out.txt"), StandardCharsets.UTF_8)) { 
     for (int i = 0; i < 100000; i++) { 
      if (secs > 59) { 
       // at least minutes changed, we need to reformat it 
       lastFormattedDateNoSecs = dateFormatNoSecs.format(logged_time); 
       secs %= 60; 
      } 
      writer.write(i + ", " + lastFormattedDateNoSecs + TwoDigitIntegerFormatter.format(secs)); 
      writer.newLine(); 

      // add the sample rate to calculate next date/time 
      logged_time.add(Calendar.SECOND, SAMPLE_RATE); 
      secs += SAMPLE_RATE; 
     } 
    } catch (IOException e) { 
     throw new RuntimeException(e); 
    } 

    System.out.println(System.currentTimeMillis() - time); 
} 

510毫秒。即使你的代碼不完全一樣,你也可以使用這個解決方案的想法來幫助你自己。

+0

嗨Slanec, 非常感謝你的詳細迴應!除了其他一些更改外,我還使用了其中一些提示,並能夠將循環時間減少約75%。首先,通過爲H/M/S/D/M/YY設置變量(使用calendar.get(calendar.second)等),我擺脫了使用日期格式的問題。然後,我通過附加這些變量來手動創建字符串在將字符串存儲在字符串數組列表之前,將適當的破折號和分號轉換爲字符串生成器。然後我將stringbuilder的長度設置爲0並移到下一行。 – Brian

+1

最後,我把所有這些代碼放回到它自己的asynctask中,因爲只要設備連接就知道必要的信息。現在,我們不需要花費約54秒的時間來處理25萬條線路,我只需要14秒! – Brian

相關問題