原帖地址http://blog.sina.com.cn/s/blog_7016da1e0100wr2p.html
VS2003已经装好,可以开始做了。
第一步,做好Xml模板,这个直接在Word中另存为Xml格式就可,这个Xml可用Word打开,也要用记事本打开。
第二步,用Word打开Xml模板,在表格中要填数据的地方做好标记,如图所示
第三步,读取Xml模板
string modePath = HttpContext.Current.Server.MapPath("同业对标专家库.xml");
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(modePath);
string docstr = xmlDoc.InnerXml.ToString();
第四步,将模板中相应位置的值替换掉
docstr = docstr.Replace("{branch_name}",this.LabelDW.Text);
docstr = docstr.Replace("NAME",this.NAME.Value);
docstr = docstr.Replace("SEX",this.SEX.Value);
docstr = docstr.Replace("BIRTHDAY",this.BIRTHDAY.Value);
docstr = docstr.Replace("PLACE",this.PLACE.Value);
第五步,替换照片。照片导出是比较麻烦的部分。照片在Xml(Word转换)中以Base64编码保存,在上面的模板中,“userphoto”代表照片,在Xml中,userphoto的整个代码是<w:r><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:hint="fareast"/><wx:font wx:val="宋体"/></w:rPr><w:t>{userphoto}</w:t></w:r>
替换照片时要把整个代码替换
string userphotoXml = "<w:r><w:rPr><w:rFonts w:ascii=\"宋体\" w:h-ansi=\"宋体\" w:hint=\"fareast\" /><wx:font wx:val=\"宋体\" /></w:rPr><w:t>userphoto</w:t></w:r>";
string PhotoXml = "<w:r><w:pict><w:binData w:name=\"wordml://02000001.jpg\" xml:space=\"preserve\">";
//中间加Base64位编码的图片信息
picStr = Convert.ToBase64String(pic);//pic为照片的byte[]格式,由数据库中读出
PhotoXml +=picStr;
PhotoXml +="</w:binData><v:shape id=\"_x0000_i1025\" type=\"#_x0000_t75\" style=\"75pt;height:100pt\"><v:imagedata src=\"wordml://02000001.jpg\" o:title=\"11163428_012248\"/> </v:shape></w:pict></w:r>";
docstr = docstr.Replace(userphotoXml,PhotoXml);
第六步,将Xml模板保存为Word
xmlDoc.InnerXml = docstr;
string filename = this.LabelDW.Text+"同业对标专家库.doc";
filename = HttpContext.Current.Server.MapPath(filename);
xmlDoc.Save(filename);
第七步,导出文档
private void FileDownload(string FullFileName)
{
FileInfo DownloadFile = new FileInfo(FullFileName);
Response.Clear();
Response.ClearHeaders();
Response.Buffer= true;
Response.ContentType= "application/octet-stream";
Response.AppendHeader( "Content-Disposition ", "attachment;filename= " +HttpUtility.UrlEncode("同业对标专家库压缩包.rar",System.Text.Encoding.UTF8));
Response.AppendHeader( "Content-Length ",DownloadFile.Length.ToString());
Response.WriteFile(DownloadFile.FullName);
Response.Flush();
Response.End();
}
至此,导出带格式Word完成,在本机运行成功。另外,多个文档打包导出,先用上述方法逐个生成文档,再打包保存,再导出下载。
打包实现:
在网上下了一个ICSharpCode.SharpZipLib.dll。
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Core;
/// <summary>
/// 压缩
/// </summary>
/// <param name="filesPath">要压缩的文件路径</param>
/// <param name="zipFilePath">压缩完文件存放路径</param>
private void CreateZipFile(string filesPath, string zipFilePath,string branchid)
{
if (!Directory.Exists(filesPath))
{
}
else
{
try
{
//*****读取文件
string[] filenames = Directory.GetFiles(filesPath);
using (ZipOutputStream s = new ZipOutputStream(File.Create(zipFilePath)))
{
s.SetLevel(9); // 压缩级别 0-9
//s.Password = "123"; //Zip压缩文件密码
byte[] buffer = new byte[4096]; //缓冲区大小
foreach (string file in filenames)
{
ZipEntry entry = new ZipEntry(Path.GetFileName(file));
entry.DateTime = DateTime.Now;
s.PutNextEntry(entry);
using (FileStream fs = File.OpenRead(file))
{
buffer = new byte[fs.Length];
int sourceBytes;
do
{
sourceBytes = fs.Read(buffer, 0, buffer.Length);
s.Write(buffer, 0, sourceBytes);
} while (sourceBytes > 0);
}
}
s.Finish();
s.Close();
}
}
catch (Exception ex)
{
}
}
}
打包下载也在本地运行成功,但布署到服务器(Win2003)上时,报错了,导出单个文档时不出下载保存对话框,而是将文档的XmL格式读取在页面上;导出压缩包时,报错The XML Page cannot be displayed
布署在同事(Win XP)电脑上也报同样的错。我不能理解为什么,只能归结于系统不能识别文档到底是Xml格式还是Word格式,将Response.ContentType= "application/octet-stream";这句换成Word格式或Xml格式都不行,依然报错。折腾了很久,最后决定放弃下载文档的方式,将文档保存在数据库,从数据库中导出下载。
////将导出文件保存到数据库中
SaveAsBLOB(filename,dr["branch_id"].ToString());
private void SaveAsBLOB(string filename,string sid)
{
string fileShortName = filename.Substring(filename.LastIndexOf('\\')+1);
System.Data.OracleClient.OracleConnection oc = new System.Data.OracleClient.OracleConnection(System.Configuration.ConfigurationSettings.AppSettings["DBConnString"].ToString());
byte[] buffer = null;
string sFileType = "",sFileName = "";
FileStream fs = new FileStream(filename,FileMode.Open);
buffer = new byte[fs.Length];
fs.Read(buffer,0,(int)fs.Length);
sFileType="text/xml";
sFileName = TellHow.StringUtil.FileNameStringFunc.getFileName(filename);
try
{
System.Data.OracleClient.OracleCommand cmdSql = new System.Data.OracleClient.OracleCommand();
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Remove(0,sb.Length);
sb.AppendFormat(" update pu_zjinfo set AttachName='"+sFileName+"',AttachCont=:AttachCont");
sb.AppendFormat(" where branch_id='"+sid+"'");
cmdSql.CommandText = sb.ToString();
System.Data.OracleClient.OracleParameter attachCont=new System.Data.OracleClient.OracleParameter();
attachCont.Value=buffer;
attachCont.ParameterName="AttachCont";
attachCont.OracleType=System.Data.OracleClient.OracleType.Blob;
attachCont.Size=buffer.Length;
cmdSql.Parameters.Add(attachCont);
//cmdSql.Parameters.Add("@ImageData",OracleType.Blob,buffer.Length).Value = buffer;
cmdSql.Connection = oc;
oc.Open();
cmdSql.ExecuteNonQuery();
oc.Close();
}
catch(Exception e)
{
Response.Write("<script language='javascript'>");
Response.Write("alert('导出失败,原因是:"+e.Message+"!');");
Response.Write("</script>");
}
fs.Flush();
fs.Close();
}
这样,终于能够在WinXP 上实现下载。正准备更新到服务器时,又发现了一个新的问题,在弹出的文件下载框上多点击了几次取消后,再点击“导出”时
报错:"该进程无法访问文件“D:\工作\DBPMIS\Experts\zip\南昌供电公司同业对标专家库.doc”,因为该文件正由另一进程使用。
导出时生成在服务器的文档发生了死锁。可能在某处操作文档后未释放,解决方法:干脆在文档保存在数据库后删除,以绝后患。
//保存到数据库后,将文件删除
if(File.Exists( filename))
File.Delete(filename);
终于大功告成!
最后的最后,客户使用时发现导出后的文档在“工作简历”栏没有换行,希望能换行。这个功能分析找到实现方法,“工作简历”用户输入时使用的TextArea控件,TextArea控件本身有换行符\r\n,根据换行符将内容分开,再按格式替换
//工作简历,工作简历格式要求有换行
string gzjlStr = dr["GZJL"].ToString();//工作简历原值
gzjlStr = gzjlStr.Replace("\r\n","^");//先将换行符换成特殊符号
string[] gzjlArray = gzjlStr.Split('^');
string gzjl=gzjlArray[0];//用来替换“工作经历”(GZJL</w:t></w:r></w:p>)的字符串
gzjl+="</w:t></w:r></w:p>";
//从第二个开始,
for (int i =1;i<gzjlArray.Length;i++)
{
gzjl+="<w:p><w:pPr><w:rPr><w:rFonts w:ascii=\"宋体\" w:h-ansi=\"宋体\" w:hint=\"fareast\"/><wx:font wx:val=\"宋体\"/></w:rPr></w:pPr>";
//上一句表示换行
gzjl+="<w:r><w:rPr><w:rFonts w:ascii=\"宋体\" w:h-ansi=\"宋体\" w:hint=\"fareast\"/><wx:font wx:val=\"宋体\"/></w:rPr><w:t>";
gzjl += gzjlArray[i];
gzjl+="</w:t></w:r></w:p>";
}
docstr= docstr.Replace("GZJL</w:t></w:r></w:p>",gzjl);