簡體   English   中英

在 C# 中附加兩個或多個字節數組

[英]Append two or more byte arrays in C#

有沒有最好的(見下文)方法在 C# 中附加兩個字節數組?

假裝我有完全的控制權,我可以使第一個字節數組足夠大以在最后保存第二個字節數組並使用Array.CopyTo函數。 或者我可以遍歷單個字節並進行分配。

有更好的方法嗎? 我無法想象像將字節數組轉換為字符串並加入它們並將它們轉換回來之類的事情會比上面的任何一種方法都好。

在最佳/更好(按順序)方面:

  1. 最快的
  2. 最少的內存消耗

一個限制是我必須在 .NET 2.0 框架中工作。

推薦的兩個選擇是 MemoryStream 和 BlockCopy。 我已經運行了 3 次 10,000,000 次循環的簡單速度測試,並得到以下結果:

3 次運行 10,000,000 次循環的平均值(以毫秒為單位):

  • BlockCopy 時間:1154 ,范圍為 13 毫秒
  • MemoryStream GetBuffer Time:1470,范圍14毫秒
  • MemoryStream ToArray 時間:1895,范圍為 3 毫秒
  • CopyTo 時間:2079,范圍為 19 毫秒
  • 逐字節時間:2203,范圍為10毫秒

List<byte> AddRange超過 1000 萬次循環的結果:List<byte> 時間:16694

相對 RAM 消耗(1 是基線,越高越差):

  • 逐字節:1
  • 塊復制:1
  • 復制到:1
  • 內存流獲取緩沖區:2.3
  • MemoryStream ToArray:3.3
  • 列表<字節>:4.2

測試表明,一般來說,除非您進行大量字節復制 [我就是這樣],否則查看字節副本不值得關注 [例如 1000 萬次運行產生多達 1.1 秒的差異]。

你想要BlockCopy

根據這篇博客文章,它比 Array.CopyTo 更快。

您還可以使用 MemoryStream 的方法。 假設 b1 和 b2 是兩個字節數組,您可以通過以下方式使用 MemoryStream 獲得一個新的 b3:

var s = new MemoryStream();
s.Write(b1, 0, b1.Length);
s.Write(b2, 0, b2.Length);
var b3 = s.ToArray();

這應該可以在沒有 LINQ 的情況下工作,而且實際上要快得多。

創建一個新的MemoryStream ,將一個緩沖區傳遞給構造函數,該緩沖區的大小與合並的緩沖區大小完全相同。 寫入單個數組,然后最后使用緩沖區:

byte[] deadBeef = new byte[] { 0xDE, 0xAD, 0xBE, 0xEF};
byte[] baadF00d = new byte[] { 0xBA, 0xAD, 0xF0, 0x0D};
int newSize = deadBeef.Length + baadF00d.Length;
var ms = new MemoryStream(new byte[newSize], 0, newSize, true, true);
ms.Write(deadBeef, 0, deadBeef.Length);
ms.Write(baadF00d, 0, baadF00d.Length);
byte[] merged = ms.GetBuffer();

.NET 中的許多低級 I/O 函數采用字節數組和偏移量。 這樣做是為了防止不必要的復制。 如果這對性能敏感,請確保您確實需要合並的數組,否則只需使用緩沖區和偏移量。

另一種選擇,雖然我沒有測試過它在速度和內存消耗方面的表現如何,LINQ 方法是否:

byte[] combined = bytesOne.Concat(bytesTwo).Concat(bytesThree).ToArray();

...其中 bytesOne、bytesTwo 和 bytesThree 是字節數組。 由於 Concat 使用延遲執行,因此不應創建任何中間數組,並且在最后構造最終合並數組之前不應復制原始數組。

編輯: LINQBridge將允許您在 2.0 框架中使用 LINQ-to-Objects(這是一個示例)。 我理解您是否不想依賴於此,但這是一種選擇。

如果您有大小不時變化的數組,那么您最好首先使用List<T> 然后你可以調用列表的AddRange()方法。

否則,Array.Copy() 或 Array.CopyTo() 與您可能會看到的任何其他東西一樣好。

你有沒有教過使用 List 或 ArrayList 而不是 Array? 使用這些類型,它們可以通過 InsertRange 增長或縮小和追加

你需要輸出實際上是一個字節數組嗎?

如果沒有,您可以為自己創建一個“智能光標”(類似於 LINQ 所做的):創建一個自定義 IEnumerator<byte> ,它將首先迭代第一個數組,然后繼續第二個數組而不會中斷。

這將在 2.0 框架中快速運行(因為數組的加入幾乎沒有成本),並且使用的 RAM 不會超過數組已經消耗的內存。

使第一個數組足夠大以包含第二個數組並使用 Array.CopyTo 的第一個選項最終與手動迭代每個項目並進行分配大致相同。 Array.CopyTo() 只是讓它更簡潔。

與上述相比,轉換為字符串並返回數組將非常緩慢。 並且可能會使用更多內存。

暫無
暫無

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

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