2013-03-13 35 views
0

我在解析文本文件(應用ETL方法)相關的小型開發項目。我創建了一個在我的本地機器上正確運行的演示代碼,但是當我將它部署到Apache Tomcat容器時,它會產生很多與內存溢出,類型轉換等有關的錯誤。解析文本文件:效率和性能

這是一般事實:

這是file structure(筆記指定了每個單元的數據類型和其他相關信息)。

注意RegisterType1重複每位客戶僅能一次,RegisterType2可以重複一次或多次,RegisterType3RegisterType4重複一次。

另請注意,每種寄存器類型的長度都不相同,即:RegisterType1 12個字段,RegisterType2 10個字段等。

正如我前面所說,我目前的解析器是如此糟糕的編碼,它會產生很多錯誤。 This is the actual codethis one(創建數據庫連接並執行查詢的類)。

這是需要解析的example text file

當前開發環境 平臺:爪哇6 集裝箱:Tomcat的7 VPS配置文件:RAM 1.7GB,存儲:20GB,處理器:(英特爾(R)至強(R)CPU X5650 @ 2.67 GHz,24個核心)。

實際問題:

  • 性能比較差
  • 內存溢出
  • 解析錯誤:數據類型轉換,字段之間的分隔符(分號)(例如:...巴黎;弗蘭[這裏分號] CE ; ...)

我想創建一個高效,正確和高性能的解析器。

我需要對此主題提出一些建議。哪種最好的方式來創建一個好的解析器?

在此先感謝您的信息。

Regards,

+1

SO問題應該是自包含和可以理解的,無需轉到外部頁面。這是因爲外部頁面可能會消失,而SO問題應該無限期地保持有效,以便未來的訪問者受益。如果涉及的代碼過多,則不適合SO。 – hyde 2013-03-13 20:17:48

+0

是的 - 也許你有一些特定的部分,你知道是把它拿回來? – ddmps 2013-03-13 20:18:40

+0

在您的本地機器上運行與服務器上完全相同的輸入文件並觀察發生了什麼。 – Axel 2013-03-13 20:18:47

回答

1

在此處張貼您的相關代碼。好吧,我會爲你做一些這樣的事情:

BufferedReader reader = null; 

    ArrayList< String> elements = new ArrayList< String>(); 

    try { 
     reader = new BufferedReader(new FileReader(archivoFuenteDatos)); 
     String text = null; 

     // repeat until all lines is read 
     while ((text = reader.readLine()) != null) { 
     ... 
     elements.add(...); 
     ... 
    } catch(...) ... 

    saveOnDB(elements); 

永遠不要閱讀那樣的大文件。如果需要,您必須同時將所有數據保存在內存中。

  1. 嘗試將每個條目直接寫入數據庫,而不是首先複製到數組列表。這將有望修復OOM。

  2. 配置您的代碼。如果速度夠快,就完成了。

  3. 如果速度不夠快,請創建一個ArrayList。給它一個初始容量n。在寫入數據庫之前,不要將超過n的項目讀入該列表。

編輯: 如果我沒有錯過重要的東西,你複製了你自己的代碼4次。發佈前請重構(代碼太多)。例如,巨大的開關可能會被重構爲這樣的東西:

 while ((text = reader.readLine()) != null) { 
      String[] campos = text.replaceAll(" +", " ").split(";"); 
      int n; 
      switch (text.charAt(0)) { 
       case '1': 
       case '2': 
       case '3': 
        n = campos.length - 1; 
        break; 
       case '4': 
        // what does this mean? It will always give 5! 
        // n = contarPuntoComas(text) == 6 ? 5 : 5; 
        n = 5; 
        break; 
       default: 
        n= 0; 
      } 
      for (int i = 0; i < n; ++i) { 
       elements.add(campos[ i].trim()); 
      } // end for 
     } 
+0

Hi @axel你給了我很多想法來攻擊解析器的實際糟糕表現。 要拆分字符串,你會推薦使用RegEx嗎? 在此先感謝。 – InfZero 2013-03-13 20:38:11

+0

我建議首先運行一個分析器。但恕我直言,問題是ArrayList,因爲每次當前容量不足時都必須一遍又一遍地複製它。另外,您將因此而暫停GC。 – Axel 2013-03-13 20:43:02

+0

另一個建議:如何替換'campos = text.split(「;」);'然後調用每個部分的'replaceAll'來代替'campos = text.replaceAll(「+」,「」) .split(「;」);'並將其他調用移除到'replaceAll'? (但先去ArrayList!) – Axel 2013-03-13 20:47:22