2012-06-05 11 views
2

我有包含存檔二進制消息的文件。一個小文件大約600MB,包含近9000條消息。每條消息都以我知道的特定四字節標誌開始,它表示消息標題的前四個字節(因此必須被捕獲)。消息標題是所有消息的固定大小。消息頭後跟一個在頭中標識的大小的有效載荷。一旦找到特定消息頭的開頭,我就知道頭的末尾有多少個字節,並可以用它來提取消息中的字節數,我需要解析這個存檔文件並隔離每個消息以進行處理,確保包含從四字節標誌的第一個字節到指定消息長度結束的所有字節。消息之間有一些填充不同。是否有任何有效的方法來查找文件中特定4字節塊的所有實例的第一個字節?

由於文件的大小,我不希望(也可能無法在所有情況下)將該文件作爲單個數組使用。因此,我正在尋找像RandomAccessFileFileInputStream之類的東西。似乎並不是一個簡單的任務,即掃描文件以查找特定的字節序列,然後將該序列中第一個字節的每個字節都採用已知的長度。 RandomAccessFile,特別是read(byte[])seek()方法看起來像他們將允許我實現一個解決方案。

爲了給出一個想法,我目前的實現包含一個名爲findFlag()的方法,該方法在RandomAccessFile中佔據一個開始位置。它尋找那個位置並從那裏讀取四個字節。如果找到該標誌,則返回startPos。否則,它會遞歸地調用它自己,移動到startPos + 1並重復,直到找到該標誌。因爲我知道我讀的數據消息的一部分的最後一個字節,我就開始尋找有:

file.seek(startPos); 

byte[] possibleFlag = new byte[4]; 

file.read(possibleFlag, 0, possibleFlag.length); 

if (Arrays.equals(ByteUtils.intToBytes(Message.FLAG), possibleFlag)) { 
    return startPos; 
} 
else { 
    return findFlag(startPos + 1); 
} 

我俯瞰的東西,無論是在爪哇(Java 6中或更早),或在一個屢試不爽的外部庫(如Apache庫或類似的)?如果不是,是否有更好的解決方案來處理Java中的二進制數據或者任何特別適合我的問題的方法?

+0

你看過http://stackoverflow.com/questions/644737/are-there-any-java-frameworks-for-binary-file-parsing? Preon似乎是你可能考慮的事情。 – Ewald

+0

@Ewald不知道Preon會有多大幫助。在我將這些信息隔離之前,我正在閱讀的文件沒有一致的格式。唯一給出的事實是相同的四字節序列表示文件中每條消息的開始。 –

+0

我認爲,*你喜歡的東西*很有效。只要讀取字節流檢查標記字節等。你還想要什麼? – Torious

回答

2

使用java.nio.channels.FileChannel掃描文件時,它使用較少的中間副本將文件映射到內存中。 benchmark of alternatives

+0

就提供的功能而言,'RandomAccessFile'和'FileChannel'之間似乎沒有太大區別。無論哪種方式,我仍然會滾動我自己的「下一個字節序列索引的搜索文件」方法。 –

+0

我現在已經發布了一個關於我如何使用'RandomAccessFile'的代碼片段。如何使用FileChannel來改進我現有的代碼? –

1

這整個方法似乎無效。你怎麼知道魔術字節不會出現在別的地方?例如在有效載荷或填充中。我希望你考慮到這一點。

擺脫遞歸。 Java不會執行尾呼叫消除。迭代版本應該更清晰,更快。

限制分配數量。爲文件中的每個字節分配兩個數組是完全不可接受的。

如果您使用FileChannel,則不必擔心緩衝區大小和分配情況。您可以使用MappedByteBuffer.getInt(int)遍歷文件並將其與Message.FLAG進行比較。這只是一個簡單的循環。

0

這在我看來非常低效。文件上最昂貴的操作是隨機部分 - 來回移動內部指針。你可以爲每個字節做到這一點。 +4,-3,+4,-3等...表演死亡華爾茲。只需向前移動就可以完成。開始僅搜索簽名的第一個字節而不是整個序列。如果匹配,則測試下一個字節。如果有任何失敗,只需重新開始搜索第一個字節即可。行中的4個成功意味着你有你的簽名。一直以來,你只是繼續前進。不惜任何代價避免尋找。另外,除非你絕對不在乎你的處理需要多長時間,否則你不應該僅僅因爲功能而忽略FileChannel。引用的統計數據是每100MB討論MINUTES,我可以支持這一觀察。 FileChannel比RandomAccessFile快兩倍,讀取大小比較快 - 您需要最小的一個:)

儘管遞歸通常被認爲是無畏的程序員的標誌,但這個特定的用法很容易讓您的虛擬機受到打擊,如果你爲其提供幾百MB的不包含任何簽名的數據。

相關問題