因为需求,要通过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;
}
以上