因爲需求,要通過rabbitmq進行郵件的發送,郵件中可能會包含有附件,所以就涉及到文件轉爲流進行傳輸,在傳輸過程中會將要傳輸的數據進行序列化,但是直接將流文件使用Newtonsoft.json進行序列化會出現錯誤
Error getting value from 'ReadTimeout' on 'System.IO.FileStream'.
查了一下,是不支持這樣直接對流文件進行序列化的,最後在stackoverflow上找到了解決方案
public class MemoryStreamJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(MemoryStream).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var bytes = serializer.Deserialize<byte[]>(reader);
return bytes != null ? new MemoryStream(bytes) : new MemoryStream();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var bytes = ((MemoryStream)value).ToArray();
serializer.Serialize(writer, bytes);
}
}
新建以上的一個轉換類,在使用的時候
//序列化
var json = JsonConvert.SerializeObject(ms, Formatting.Indented, new MemoryStreamJsonConverter());
//反序列化
var ms2 = JsonConvert.DeserializeObject<MemoryStream>(json, new MemoryStreamJsonConverter());
在寫入的時候將Stream類型的對象進行序列化爲json字符串,然後在讀取隊列內容的地方使用反序列化的方法將文件重新轉換爲流文件即可。
以上遇到一個問題就是。這邊要發送郵件的附件是Dictionary<string,Stream> 類型的對象,但是直接傳輸這樣的對象是沒辦法正確解析的,上面的方法只支持Stream類型的轉換,所以後來的解決方法是將Dictionary<string,Stream> 再轉爲流文件進行序列化傳輸即可。
解析完成之後再將流對象轉換爲Dictionary<string,Stream> 即可。
相關代碼如下:
1、文件轉爲流
/// <summary>
/// 將文件轉換成stream
/// </summary>
/// <param name="Path">文件路徑</param>
/// <returns></returns>
public static Stream ConvertToStream(string Path)
{
if (File.Exists(Path))
{
FileStream stream = new FileInfo(Path).OpenRead();
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, 0, Convert.ToInt32(stream.Length));
stream.Flush();
stream.Close();
Stream result = new MemoryStream(buffer);
return result;
}
return null;
}
/// <summary>
/// 將對象轉爲stream
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static Stream ConvertObjectToStream(object obj)
{
byte[] buff;
using (MemoryStream ms = new MemoryStream())
{
IFormatter iFormatter = new BinaryFormatter();
iFormatter.Serialize(ms, obj);
buff = ms.GetBuffer();
Stream stream = new MemoryStream(buff);
return stream;
}
}
2、流轉爲對象
//先將流轉爲字節
public static byte[] StreamToBytes(Stream stream)
{
byte[] bytes = new byte[stream.Length];
stream.Read(bytes, 0, bytes.Length);
// 設置當前流的位置爲流的開始
stream.Seek(0, SeekOrigin.Begin);
return bytes;
}
/// <summary>
/// 將一個序列化後的byte[]數組還原
/// </summary>
/// <param name="Bytes"></param>
/// <returns></returns>
public static object BytesToObject(byte[] Bytes)
{
using (MemoryStream ms = new MemoryStream(Bytes))
{
IFormatter formatter = new BinaryFormatter();
return formatter.Deserialize(ms);
}
}
//obj轉爲dictionary
public static Dictionary<string, Stream> ConvertFromObject(object obj)
{
if (obj is Dictionary<string, Stream>)
return (Dictionary<string, Stream>)obj;
return null;
}
//流轉爲dictionary
public static Dictionary<string, Stream> GetDictionaryByStream(Stream stream)
{
byte[] buff = StreamToBytes(stream);
Dictionary<string, Stream> dir = ConvertFromObject(BytesToObject(buff));
return dir;
}
以上