簡體   English   中英

什么放在二進制數據文件的標題中

[英]What to put in a binary data file's header

我有一個模擬讀取我們創建的大型二進制數據文件(10到100的GB)。 出於速度原因,我們使用二進制 這些文件是系統相關的,從我們運行的每個系統上的文本文件轉換而來,所以我不關心可移植性。 這些文件當前是POD結構的許多實例,用fwrite編寫。

我需要更改結構,所以我想添加一個文件版本號的標題,它會隨着結構的變化而增加。 由於我這樣做,我想添加一些其他信息。 我正在考慮結構的大小,字節順序,以及創建二進制文件的代碼的svn版本號。 還有什么其他有用的東西可以添加嗎?

根據我的經驗,對你需要的數據進行二次猜測總是浪費時間。 重要的是以可擴展的方式構建元數據 對於XML文件,這很簡單,但二進制文件需要更多考慮。

我傾向於將元數據存儲在文件END的結構中,而不是開頭。 這有兩個好處:

  • 可以輕松檢測到截斷/未終止的文件。
  • 元數據頁腳通常可以附加到現有文件而不會影響其讀取代碼。

我使用的最簡單的元數據頁腳看起來像這樣:

struct MetadataFooter{
  char[40] creatorVersion;
  char[40] creatorApplication;
  .. or whatever
} 

struct FileFooter
{
  int64 metadataFooterSize;  // = sizeof(MetadataFooter)
  char[10] magicString;   // a unique identifier for the format: maybe "MYFILEFMT"
};

在原始數據之后,元數據頁腳和文件頁腳被寫入。

在讀取文件時,請搜索end-sizeof(FileFooter)。 閱讀頁腳,並驗證magicString。 然后,根據metadataFooterSize回顧並讀取元數據。 根據文件中包含的頁腳大小,您可以使用缺少字段的默認值。

正如KeithB指出的那樣,您甚至可以使用這種技術將元數據存儲為XML字符串,從而提供完全可擴展的元數據的優勢,以及二進制數據的緊湊性和速度。

對於大型二進制文件,我會認真對待HDF5(Google for it)。 即使它不是您想要采用的東西,它也可能指出您在設計自己的格式時有一些有用的方向。

對於大型二進制文件,除了版本號之外,我傾向於記錄計數和CRC,原因是大型二進制文件隨着時間的推移或在傳輸期間比較小的二進制文件更容易被截斷和/或損壞。 我最近驚恐地發現Windows根本不能處理這個問題,因為我使用資源管理器將幾百個文件中的2TB復制到連接的NAS設備上,並發現每個副本上有2-3個文件被損壞(不完全復制)。

如果稍后將其他結構寫入二進制文件,則該文件類型的標識符將非常有用。 也許這可能是一個短字符串,所以你可以通過查看文件(通過十六進制編輯器)看到它包含的內容。

如果它們那么大,我會在文件開頭保留一個健康的空間(64K?)空間,並將元數據放在XML格式中,然后是文件結束字符(Ctrl-Z表示DOS / Windows,ctrl-D for unix?)。 這樣,您可以使用適用於XML的各種工具集輕松地檢查和解析元數據。

否則我會選擇其他人已經說過的內容:文件創建的時間戳,創建它的機器的標識符,基本上你可以想到的任何其他用於診斷的東西。 理想情況下,您將包含結構格式本身的定義。 如果您經常更改結構,那么維護適當版本的代碼以閱讀各種格式的舊數據文件會非常困難。

正如@highpercomp所提到的HDF5的一大優勢在於,您只需要擔心結構格式的變化,只要您對名稱和數據類型有一些約定即可。 結構名稱和數據類型都存儲在文件本身中,因此您可以將C代碼吹到smithereens並且無關緊要,您仍然可以從HDF5文件中檢索數據。 它讓你不用擔心數據的格式 ,更多地關注數據結構 ,即我不關心字節序列,這是HDF5的問題,但我確實關心字段名稱等。

我喜歡HDF5的另一個原因是你可以選擇使用壓縮,這需要花費很少的時間,並且如果數據正在緩慢變化或者大部分相同,除了一些錯誤的有趣之處外,可以給你巨大的存儲空間。

@rstevens說“文件類型的標識符”......聲音建議。 傳統上,這被稱為幻數,並且在文件中,不是濫用的術語(與代碼不同,它是濫用的術語)。 基本上,它是一些數字 - 通常至少4個字節,我通常確保這些字節中至少有一個不是ASCII - 您可以使用它來驗證文件是否是您期望的類型,並且混淆的可能性很小。 您還可以在/ etc / magic(或本地等效項)中編寫規則,以報告包含幻數的文件是您的特殊文件類型。

您應該包含文件格式版本號。 但是,我建議不要使用代碼的SVN號碼。 當文件格式沒有時,您的代碼可能會更改。

由於我對電信設備配置和固件升級的經驗表明,您只需要在開始時(這很重要)從版本(標頭的固定部分)開始實際需要幾個預定義字節。 其余標題是可選的,通過指示正確的版本,您可以始終顯示如何處理它。 這里重要的是你最好在文件末尾放置標題的'變量'部分。 如果您在標頭上計划操作而不修改文件內容本身。 這也簡化了“追加”操作,應該重新計算變量頭部分。

很高興有固定大小標頭的功能(在開始時):

  • 常見的“長度”字段(包括標題)。
  • 類似於CRC32(包括標題)。

好吧,對於變量部分XML或標題中的一些漂亮的可擴展格式是個好主意,但它真的需要嗎? 我在ASN編碼方面有很多經驗......在大多數情況下,它的使用率都超過了。

好吧,當你看到RFC 2126 (第4.3章)中描述的TPKT格式之類的東西時,也許你會有額外的理解。

除了架構版本控制所需的任何信息之外,如果要解決問題,請添加可能有價值的詳細信息。 例如:

  • 創建和更新文件的時間戳(如果適用)。
  • 來自構建的版本字符串(理想情況下,您有一個版本字符串,在每個“官方”構建中自動遞增...這與文件架構版本不同)。
  • 創建文件的系統的名稱,以及可能與您的應用相關的其他統計信息

我們發現這非常有用(a)獲取我們原本不得不要求客戶提供的信息以及(b)獲取正確的信息 - 令人驚訝的是,有多少客戶報告他們正在運行不同版本的軟件而不是數據聲稱!

您可以考慮將文件偏移量放在標題中的固定位置,這會告訴您實際數據在文件中的開始位置。 這樣可以在需要時更改標題的大小。

在幾種情況下,我將值0x12345678放入標題中,以便我可以檢測文件格式是否與正在處理它的機器的字節順序相匹配。

我的變化結合了Roddy和Jason S的方法。

總之 - 將格式化的文本元數據放在文件的末尾,以確定其存儲在別處的長度。

1)在文件的開頭放置一個長度字段,以便在結束時知道元數據的長度,而不是假定固定的長度。 這樣,要獲取元數據,您只需讀取固定長度的初始字段,然后從文件末尾獲取元數據blob。

2)使用XML或YAML或JSON作為元數據。 如果在末尾附加元數據,這是特別有用/安全的,因為沒有人閱讀文件會自動認為它只是因為XML以XML開頭。

這種方法的唯一缺點是當你的元數據增長時,你必須更新文件的頭部和尾部,但是其他部分可能仍然會被更新。 如果它只是像上次訪問日期一樣更新瑣事,那么元數據長度不會改變,所以它只需要就地更新。

如果要在標題中放置版本號,則可以在需要更改POD結構或向標題添加新字段時隨時更改該版本。

因此,現在不要在標題中添加內容,因為它可能很有趣。 您只需創建必須維護的代碼,但這些代碼幾乎沒有實際價值。

對於大型文件,您可能希望添加數據定義,因此您的文件格式將成為自我描述的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM