引言
在项目中遇到了这么一个问题。移动端上传的图片,在我asp.net后边接收,但却转换不成图片保存。于是我把接收到的二进制流转换成字符串的形式显示出来。结果大吃一惊。ios传过来的二进制流不是纯图片的,还有一些图片的格式,名称等。
显示如下:
<span style="font-size:18px;">--Boundary+6638A777949A1B1A
Content-Disposition: form-data; name="file"; filename="20160523171643.png"
Content-Type: image/png
�PNG
IHDR < m �Su sRGB ��� iDOT 7 ( 7 6 T�gf�� @ IDATxd�ٖ7�e��VW�RJMg2�1�HRY��s{�s`7B�X��`f ����7�����������÷��#���on>�(;���:|ה|�{i=ʮi�������������悲K�PF�����=u�m�ȿ9z������[�}��=������N���k��҇8x���H�S��w�K��x��]p��1��z�9x��͡�m�as{��d��-L�n�閶w�'yH��H��G_w��h�|������
]�[�J�}ݜp=������hO��,��:5�#y�58ݓ���t�v������<>���#��wo���w� ���}�.��8x����';/7G^lw���ޜ�>|�9�}�9��js��j��e�
��o7gܟ}"}|�9���6_>��|���.:��\��\�W&ei: }��N�'�W�
Zկ�ӽ�S~$O(�7�w����tO�|���zwg{�[xt�{ye|R�n��/����I�!�C���
�����A�\y�;��pl��Ci{lߟ��z@�<span style="color:#FF0000;"><strong>(这里的乱码,是图片的数据部分)</strong></span>
--Boundary+6638A777949A1B1A--
</span>
问题及解决方案
那么问题来了,怎么分开处理呢?通过各种查询、实验。终于解决了这个问题,基本思路是用正则表达式来匹配里面的键值,如conten-type,filename,匹配完后中间的部分都是图片流数据,就可以直接转换成图片保存起来了。
实体类代码
<span style="font-size:18px;">using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace Model
{
public class MultipartParser
{
private byte[] requestData;
public MultipartParser(Stream stream)
{
this.Parse(stream, Encoding.UTF8);
// ParseParameter(stream, Encoding.UTF8);
}
public MultipartParser(Stream stream, Encoding encoding)
{
this.Parse(stream, encoding);
}
private void Parse(Stream stream, Encoding encoding)
{
this.Success = false;
// Read the stream into a byte array
byte[] data = ToByteArray(stream);
requestData = data;
// Copy to a string for header parsing
string content = encoding.GetString(data);
// The first line should contain the delimiter
int delimiterEndIndex = content.IndexOf("\r\n");
if (delimiterEndIndex > -1)
{
string delimiter = content.Substring(0, content.IndexOf("\r\n"));
// Look for Content-Type
Regex re = new Regex(@"(?<=Content\-Type:)(.*?)(?=\r\n\r\n)");
Match contentTypeMatch = re.Match(content);
// Look for filename
re = new Regex(@"(?<=filename\=\"")(.*?)(?=\"")");
Match filenameMatch = re.Match(content);
// Did we find the required values?
if (contentTypeMatch.Success && filenameMatch.Success)
{
// Set properties
this.ContentType = contentTypeMatch.Value.Trim();
this.Filename = filenameMatch.Value.Trim();
// Get the start & end indexes of the file contents
int startIndex = contentTypeMatch.Index + contentTypeMatch.Length + "\r\n\r\n".Length;
byte[] delimiterBytes = encoding.GetBytes("\r\n" + delimiter);
int endIndex = IndexOf(data, delimiterBytes, startIndex);
int contentLength = endIndex - startIndex;
// Extract the file contents from the byte array
byte[] fileData = new byte[contentLength];
Buffer.BlockCopy(data, startIndex, fileData, 0, contentLength);
this.FileContents = fileData;
this.Success = true;
}
}
}
private void ParseParameter(Stream stream, Encoding encoding)
{
this.Success = false;
// Read the stream into a byte array
byte[] data;
if (requestData.Length == 0)
{
data = ToByteArray(stream);
}
else { data = requestData; }
// Copy to a string for header parsing
string content = encoding.GetString(data);
// The first line should contain the delimiter
int delimiterEndIndex = content.IndexOf("\r\n");
if (delimiterEndIndex > -1)
{
string delimiter = content.Substring(0, content.IndexOf("\r\n"));
string[] splitContents = content.Split(new[] {delimiter}, StringSplitOptions.RemoveEmptyEntries);
foreach (string t in splitContents)
{
// Look for Content-Type
Regex contentTypeRegex = new Regex(@"(?<=Content\-Type:)(.*?)(?=\r\n\r\n)");
Match contentTypeMatch = contentTypeRegex.Match(t);
// Look for name of parameter
Regex re = new Regex(@"(?<=name\=\"")(.*)");
Match name = re.Match(t);
// Look for filename
re = new Regex(@"(?<=filename\=\"")(.*?)(?=\"")");
Match filenameMatch = re.Match(t);
// Did we find the required values?
if (name.Success || filenameMatch.Success)
{
// Set properties
//this.ContentType = name.Value.Trim();
int startIndex;
if (filenameMatch.Success)
{
this.Filename = filenameMatch.Value.Trim();
}
if(contentTypeMatch.Success)
{
// Get the start & end indexes of the file contents
startIndex = contentTypeMatch.Index + contentTypeMatch.Length + "\r\n\r\n".Length;
}
else
{
startIndex = name.Index + name.Length + "\r\n\r\n".Length;
}
//byte[] delimiterBytes = encoding.GetBytes("\r\n" + delimiter);
//int endIndex = IndexOf(data, delimiterBytes, startIndex);
//int contentLength = t.Length - startIndex;
string propertyData = t.Substring(startIndex - 1, t.Length - startIndex);
// Extract the file contents from the byte array
//byte[] paramData = new byte[contentLength];
//Buffer.BlockCopy(data, startIndex, paramData, 0, contentLength);
MyContent myContent = new MyContent();
myContent.Data = encoding.GetBytes(propertyData);
myContent.StringData = propertyData;
myContent.PropertyName = name.Value.Trim();
if (MyContents == null)
MyContents = new List<MyContent>();
MyContents.Add(myContent);
this.Success = true;
}
}
}
}
private int IndexOf(byte[] searchWithin, byte[] serachFor, int startIndex)
{
int index = 0;
int startPos = Array.IndexOf(searchWithin, serachFor[0], startIndex);
if (startPos != -1)
{
while ((startPos + index) < searchWithin.Length)
{
if (searchWithin[startPos + index] == serachFor[index])
{
index++;
if (index == serachFor.Length)
{
return startPos;
}
}
else
{
startPos = Array.IndexOf<byte>(searchWithin, serachFor[0], startPos + index);
if (startPos == -1)
{
return -1;
}
index = 0;
}
}
}
return -1;
}
private byte[] ToByteArray(Stream stream)
{
byte[] buffer = new byte[32768];
using (MemoryStream ms = new MemoryStream())
{
while (true)
{
int read = stream.Read(buffer, 0, buffer.Length);
if (read <= 0)
return ms.ToArray();
ms.Write(buffer, 0, read);
}
}
}
public List<MyContent> MyContents { get; set; }
public bool Success
{
get;
private set;
}
public string ContentType
{
get;
private set;
}
public string Filename
{
get;
private set;
}
public byte[] FileContents
{
get;
private set;
}
}
public class MyContent
{
public byte[] Data { get; set; }
public string PropertyName { get; set; }
public string StringData { get; set; }
}
} </span>
asp.net后台代码
<span style="font-size:18px;">using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ITSMToJson
{
public partial class updateFile: System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//假数据
//FileStream photo = new FileStream("d://test.jpg", FileMode.Open);
//byte[] buffer = new byte[photo.Length];
//photo.Read(buffer, 0, buffer.Length);
//获得IOS传过来的二进制流
Stream sourceStream = Request.InputStream;
MultipartParser model = new MultipartParser(sourceStream);//实例化MultipartParse
string Filename = model.Filename; //获得图片名称
byte[] FileContents = model.FileContents; //获得图片流数据
//获得Web服务上File虚拟路径相对应的物理文件路径
string Path = HttpContext.Current.Server.MapPath("/File") + "//" + DateTime.Now.ToString("yyyyMMdd");
//查看路径是否存在,如果不存在,则创建路径
if (!Directory.Exists(Path))
{
DirectoryInfo foler = Directory.CreateDirectory(Path);
}
//得到要目的文件路径
string filenameaddress = Path+"//"+Filename;
//将图片流显示成图片并保存起来
FileStream targetStream = new FileStream(filenameaddress, FileMode.Create);
targetStream.Write(FileContents, 0, FileContents.Length);
System.Drawing.Image img = System.Drawing.Image.FromStream(targetStream);
targetStream.Close();
sourceStream.Close();
}
}
}</span>
小结
在此还要感谢提供思路和代码的网友。代码就是不断地积累,还要不断总结经验和技术,分享给大家。