2014-03-30 50 views
1

我使用下面的代碼來檢索從位於我的計算機系統上的文件的位圖:如何減少c#編碼base64字符串時的內存使用情況?

Bitmap shellThumb = sf.Thumbnail.ExtraLargeBitmap; 

其中SF是ShellFile。

然後我用下面的位圖轉換爲Base64:

public static string ToBase64String(this Bitmap bmp, ImageFormat imageFormat) 
    { 
     string base64String = string.Empty; 


     MemoryStream memoryStream = new MemoryStream(); 
     bmp.Save(memoryStream, imageFormat); 

     memoryStream.Position = 0; 
     byte[] byteBuffer = memoryStream.ToArray(); 

     memoryStream.Close(); 

     base64String = Convert.ToBase64String(byteBuffer); 
     byteBuffer = null; 

     return base64String; 
    } 

然後我用調用此方法如下:

string base64ImageAndTag = shellThumb.ToBase64String(ImageFormat.Png); 

然後我用JSON.Net來寫這個字符串以及將文件的其他屬性添加到另一個項目中使用的JSON文件 - JSON無可替代,因此必須使用它。

string json = JsonConvert.SerializeObject(files.ToArray(), Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); 

其中文件是列表。

我必須讀取指定文件夾中每個文件的縮略圖。

從讀取文件中,我得到一個OutOfMemory異常,並且轉換是寫入JSON文件時的原因。

有沒有辦法更好地編碼位圖,以避免異常?我已經爲這個問題尋找解決方案,但我不確定如何/在哪裏應用任何可能的解決方案來完成這項工作。

非常感謝!

+0

你知道究竟是什麼導致了內存不足的異常嗎? '更糟糕的情況是流(通過base64,CryptoStream與自定義的base64-ICryptoTransform可能有所幫助)圖像文件。沒有必要同時將整個文件(包括很多圖像?)保存在內存中。 – Caramiriel

+0

嗨@Caramiriel,謝謝你的評論!它嘗試寫入json文件時發生異常。我知道它必須是base64字符串,因爲只有在我將其添加到發生異常之後。字符串是一個文件對象的屬性,所以它需要用它的文件對象的屬性來編寫 - 你的意思是,通過同時將整個文件和圖像保存在內存中是什麼意思?我將如何解決這個問題? – sim1

+0

那麼,我不知道是否有這樣的事情(沒有與它合作),但是對於XML,有'XmlWriter'直接寫入流。這將允許您分別編寫每個元素/屬性。一個例子:當你嘗試序列化第二個圖像時,第一個圖像已經在磁盤上(不再在內存中)。也許JSON也有類似的東西。 – Caramiriel

回答

0

你會想壓縮它。如果你想保存位圖格式,你可以使用gzip壓縮圖像(或其他更好的壓縮器)。這也將是無損壓縮,你不會失去任何質量。

如果您可以將其轉換爲jpeg,那可能會給您更高的壓縮率。但要小心,這種壓縮會導致質量損失。

+0

嗨@oleksii,謝謝你的回答。我可以通過編程來壓縮位圖嗎?我會怎麼做? – sim1

+0

@ user2651192,當然可以。位圖是一系列字節。您已將其轉換爲內存流,然後可以對其進行壓縮。請參閱[此鏈接](http://msdn.microsoft.com/en-us/library/system.io.compression.gzipstream.aspx)瞭解如何使用gzip壓縮/解壓縮流(在這種情況下,它是文件流,但它沒關係 - 任何流都可以工作)。 – oleksii

1

減少內存佔用的一種方法是每次對一個對象進行序列化並將它們串入輸出中,而不是試圖在內存中預先生成所有對象(及其Base64字符串)。您可以使用Json.Net中的JsonSerializerJsonTextWriter類來一次處理一個圖像數據。下面是比較兩種序列化方式的簡單示例。您可能會用指向輸出文件的StreamWriter代替StringWriter。在GenerateImageFile內部,您可以將其稱爲ToBase64String方法。

class ImageFile 
{ 
    public string Name { get; set; } 
    public string Base64Image { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var files = new[] { "test.bmp", "test2.bmp" }; 

     // generate all the objects and then serialize. 
     var imageFiles = files.Select(GenerateImageFile); 
     var serialized = JsonConvert.SerializeObject(imageFiles.ToArray(), Formatting.Indented, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }); 
     Console.WriteLine(serialized); 

     // generate objects one at a time. 
     // use JsonSerialzer/JsonTextWriter to "stream" the objects 
     var s = JsonSerializer.Create(new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }); 
     var strWriter = new StringWriter(); 
     using (var writer = new JsonTextWriter(strWriter) { Formatting = Formatting.Indented }) 
     { 
      writer.WriteStartArray(); 
      foreach(var file in files) 
      { 
       var imageFile = GenerateImageFile(file); 
       s.Serialize(writer, imageFile); 
      } 
      writer.WriteEndArray(); 
     } 
     Console.WriteLine(strWriter.GetStringBuilder()); 
    } 

    private static ImageFile GenerateImageFile(string fileName) 
    { 
     return new ImageFile() { Name = fileName, Base64Image = fileName + fileName }; 
    } 
} 
相關問題