根据InfoPath team blog里介绍的File Attachment Control的内容,写了两个类来处理文件的编码与解码。

public class InfoPathAttachmentEncoder { private string base64EncodedFile = string.Empty; private string fullyQualifiedFileName; /// <summary> /// Creates a encoder to create an InfoPath attachement string /// </summary> /// <param name="fullyQualifiedFileName"></param> public InfoPathAttachmentEncoder(string fullyQualifiedFileName) { if (fullyQualifiedFileName == string.Empty) throw new ArgumentException("Must specify file name", "fullyQualifiedFileName"); if (!File.Exists(fullyQualifiedFileName)) throw new FileNotFoundException("File does not exist: " + fullyQualifiedFileName, fullyQualifiedFileName); this.fullyQualifiedFileName = fullyQualifiedFileName; } /// <summary> /// Returns a Base64 encoded string /// </summary> /// <returns>String</returns> public string ToBase64String() { if (base64EncodedFile != string.Empty) return base64EncodedFile; // This memory stream will hold the InfoPath file attachment buffer before Base64 encoding MemoryStream ms = new MemoryStream(); // get the file information using (BinaryReader br = new BinaryReader(File.Open(fullyQualifiedFileName, FileMode.Open, FileAccess.Read, FileShare.Read))) { string fileName = Path.GetFileName(fullyQualifiedFileName); uint fileNameLength = (uint)fileName.Length + 1; byte[] fileNameBytes = Encoding.Unicode.GetBytes(fileName); using (BinaryWriter bw = new BinaryWriter(ms)) { // Write InfoPath attachment signature bw.Write(new byte[] { 0xC7, 0x49, 0x46, 0x41 }); // Write the default header information bw.Write((uint)0x14); // size bw.Write((uint)0x01); // version bw.Write((uint)0x00); // reserved // Write the file size bw.Write((uint)br.BaseStream.Length); // Write the size of the file name bw.Write((uint)fileNameLength); // Write the file name (Unicode encoded) bw.Write(fileNameBytes); // Write the file name terminator (which is two nulls in Unicode) bw.Write(new byte[] {0,0}); // Iterate through the file reading data and writing it to the outbuffer byte[] data = new byte[64*1024]; int bytesRead = 1; while (bytesRead > 0) { bytesRead = br.Read(data, 0, data.Length); bw.Write(data, 0, bytesRead); } } } // This memorystream will hold the Base64 encoded InfoPath attachment MemoryStream msOut = new MemoryStream(); using (BinaryReader br = new BinaryReader(new MemoryStream(ms.ToArray()))) { // Create a Base64 transform to do the encoding ToBase64Transform tf = new ToBase64Transform(); byte[] data = new byte[tf.InputBlockSize]; byte[] outData = new byte[tf.OutputBlockSize]; int bytesRead = 1; while (bytesRead > 0) { bytesRead = br.Read(data, 0, data.Length); if (bytesRead == data.Length) tf.TransformBlock(data, 0, bytesRead, outData, 0); else outData = tf.TransformFinalBlock(data, 0, bytesRead); msOut.Write(outData, 0, outData.Length); } } msOut.Close(); return base64EncodedFile = Encoding.ASCII.GetString(msOut.ToArray()); } }
public class InfoPathAttachmentDecoder
{ private const int SP1Header_Size = 20; private const int FIXED_HEADER = 16; private int fileSize; private int attachmentNameLength; private string attachmentName; private byte[] decodedAttachment; /// <summary> /// Accepts the Base64 encoded string /// that is the attachment /// </summary> public InfoPathAttachmentDecoder(string theBase64EncodedString) { byte [] theData = Convert.FromBase64String(theBase64EncodedString); using(MemoryStream ms = new MemoryStream(theData)) { BinaryReader theReader = new BinaryReader(ms); DecodeAttachment(theReader); } } private void DecodeAttachment(BinaryReader theReader) { //position the reader to get the filesize byte[] headerData = new byte[FIXED_HEADER]; headerData = theReader.ReadBytes(headerData.Length); fileSize = (int)theReader.ReadUInt32(); attachmentNameLength = (int)theReader.ReadUInt32() * 2; byte[] fileNameBytes = theReader.ReadBytes(attachmentNameLength); //InfoPath defaults to UTF8 encoding. Encoding enc = Encoding.Unicode; attachmentName = enc.GetString(fileNameBytes, 0, attachmentNameLength - 2); decodedAttachment = theReader.ReadBytes(fileSize); } public void SaveAttachment(string saveLocation) { string fullFileName = saveLocation; if(!fullFileName.EndsWith(Path.DirectorySeparatorChar.ToString())) { fullFileName += Path.DirectorySeparatorChar; } fullFileName += attachmentName; if(File.Exists(fullFileName)) File.Delete(fullFileName); FileStream fs = new FileStream(fullFileName, FileMode.CreateNew); BinaryWriter bw = new BinaryWriter(fs); bw.Write(decodedAttachment); bw.Close(); fs.Close(); } public string Filename { get{ return attachmentName; } } public byte[] DecodedAttachment { get{ return decodedAttachment; } } }
这样,我们就能根据需要对File Attachment Control来做进一步的控制了。