正文

如何将论坛附件直接以文件形式保存,并读取照片文件的Exif信息2006-05-19 11:42:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/Csharpsky/14341.html

分享到:

废话少说,直接进入主题:
      准备工作:下载PhotoProperties类库(http://www.codeproject.com/cs/media/photoproperties.asp),用于读取Exif信息,在Components中引用该类库

1、修改web.config配置文件,在forums/forums下增加一个配置项
      uploadFilesPath="/Upload/"
      值可以自行修改,用来保存用户上传的文件;

2、修改数据库
      forums_PostAttachments表增加如下字段
      DiskFileName nvarchar(256),  保存附件在硬盘上的文件名
      Exif  nvarchar(200),    用于保存照片附件的Exif信息
      CheckGuid nvarchar(50)     用于保存检测的Guid
      注意:我们修改的最终方案是会删除原有的Content字段的

      修改存储过程:

create procedure forums_PostAttachment_Add 
(
    @PostID int,
    @UserID int,
    @ForumID int,
    @Filename nvarchar(256),
    @DiskFileName nvarchar(256),
    @ContentType nvarchar(50),
    @ContentSize int,
    @Exif nvarchar(500),
    @CheckGuid nvarchar(50)
)
AS
BEGIN

    IF EXISTS (SELECT PostID FROM forums_PostAttachments WHERE PostID = @PostID)
        RETURN

    INSERT INTO 
        forums_PostAttachments
    (
        PostID,
        ForumID,
        UserID,
        [FileName],
        DiskFileName,
        ContentType,
        ContentSize,
        Exif,
        CheckGuid
    )
    VALUES
    (
        @PostID,
        @ForumID,
        @UserID,
        @Filename,
        @DiskFileName,
        @ContentType,
        @ContentSize,
        @Exif,
        @CheckGuid
    )

END

GO
SET QUOTED_IDENTIFIER OFF 
GO
SET ANSI_NULLS ON 
GO

SET QUOTED_IDENTIFIER ON 
GO
SET ANSI_NULLS ON 
GO


     
3、修改系统配置管理类Components项目下的Configuration/ForumConfiguration.cs文件:
      1)在头部增加一变量

string uploadFilesPath="/Upload/";       2)在LoadValuesFromConfigurationXml方法里增加以下代码,读取配置文件中的值: uploadFilesPath = attributeCollection["uploadFilesPath"].Value;      3)给ForumConfiguration类增加UploadFilesPath属性:  public string UploadFilesPath { get { return uploadFilesPath; } }
      配置文件部分完成。

4、修改Components项目下的PostAttachment类
      增加如下引用:
using System.IO;
using JSG.PhotoPropertiesLibrary;
      增加如下变量:      string exif;
string diskFileName;        
string checkGuid;     
     增加如下方法: /**//// <summary>
        /// 获取文件的Exif信息
        /// </summary>
        /// <param name="postedFile"></param>
        /// <returns></returns>
        private string GetExif(string ContentType,string FullFileName) 
        {
                        
            string imgFilePath = FullFileName;
            string exif="";
            
            try
            {
                PhotoProperties pp = new PhotoProperties();

                pp.Initialize();
                pp.Analyze(imgFilePath);
                        
                if(ContentType.ToLower() == "image/pjpeg")
                {
                    //Exif Version
                    exif += "Exif版本:" +  pp.GetTagDatum(36864).PrettyPrintValue;

                    //制造商
                    exif += " 制造商:" + pp.GetTagDatum(271).PrettyPrintValue;

                    //型号
                    exif += " 型号:" + pp.GetTagDatum(272).PrettyPrintValue;

                    //拍摄时间
                    exif += " 拍摄时间:" + pp.GetTagDatum(36868).PrettyPrintValue;

                    //暴光时间:
                    exif += "<BR>暴光时间:" +  pp.GetTagDatum(33434).PrettyPrintValue + "秒";

                    //光圈
                    exif += " 光圈:" + pp.GetTagDatum(33437).PrettyPrintValue;

                    //ISO
                    exif += "  ISO:" + pp.GetTagDatum(34855).PrettyPrintValue;

                    //分辨率
                    exif += " 分辨率:" +  pp.GetTagDatum(282).PrettyPrintValue + "/" +  pp.GetTagDatum(283).PrettyPrintValue;
                }
            }
            catch{}

            return exif;
        }       在构造函数的最下面增加:
string uploadPath = HttpContext.Current.Server.MapPath("~" + AspNetForums.Configuration.ForumConfiguration.GetConfig().UploadFilesPath);
            uploadPath += "\" + Users.GetUser().UserID.ToString() + "\";
            if(!System.IO.Directory.Exists(uploadPath))
            {
                System.IO.Directory.CreateDirectory(uploadPath);
            }
        
            //HttpContext.Current.User.Identity
            
            diskFileName =  System.Guid.NewGuid().ToString() + System.IO.Path.GetExtension(postedFile.FileName);
            uploadPath += diskFileName;
            
            postedFile.SaveAs(uploadPath);
exif = GetExif(contentType,uploadPath);
checkGuid = System.Guid.NewGuid().ToString();      
      最后增加3个属性,代码如下:
        /**//// <summary>
        /// 磁盘文件名(文件保存在硬盘上的物理文件名)
        /// 37AE8655-05F8-4ed9-A771-35B41F0222DE.ext
        /// </summary>
        public string DiskFileName
        {
            get
            {
                return diskFileName;
            }
            set
            {
                diskFileName = value;
            }
        }

        /**//// <summary>
        /// 照片Exif信息
        /// </summary>
        public string Exif 
        {
            get 
            {
                return exif;
            }
            set 
            {
                exif = value;
            }
        }

        /**//// <summary>
        /// 用于判断是否要以attachment形式让用户下载附件
        /// </summary>
        public string CheckGuid
        {
            get
            {
                return checkGuid;
            }
            set
            {
                checkGuid = value;
            }
        }
5、下面要修改的是负责系统数据库操作的SqlDataProvider项目,用于完成对新增加字段的数据库操作,修改如下:
    找到public override void AddPostAttachment(Post post, PostAttachment attachment)方法: //增加DiskFileName字段,用于附件在硬盘上的保存文件名,
//类似1990ffb3-3992-4438-b7e2-2bca963d969f.jpg
//该文件名不暴露给最终用户
myCommand.Parameters.Add("@DiskFileName", SqlDbType.NVarChar, 256).Value = attachment.DiskFileName;
//注释掉对Content的操作
//myCommand.Parameters.Add("@Content", SqlDbType.Image).Value = attachment.Content;

//增加照片Exif信息与用于验证的CheckGuid字段
myCommand.Parameters.Add("@Exif",SqlDbType.NVarChar,500).Value = attachment.Exif;
myCommand.Parameters.Add("@CheckGuid",SqlDbType.NVarChar,500).Value = attachment.CheckGuid;     注意:这里需要注释掉对Content字段的操作,因为虽然数据字段还在,但上面修改的存储过程中,我们已经删除了对Content字段的操作;

6、修改Components项目下的ForumsDataProvider类中的PopulatePostAttachmentFromIReader方法,完成从数据库到对象的转换,修改如下: //删除Content字段,附件内容不再保存到数据库,而是直接以文件形式保存到硬盘
// attachment.Content      = (byte[]) reader["Content"];

//增加DiskFileName字段,用于附件在硬盘上的保存文件名,
//类似1990ffb3-3992-4438-b7e2-2bca963d969f.jpg
//该文件名不暴露给最终用户
attachment.DiskFileName = (string) reader["DiskFileName"].ToString();

//增加照片Exif信息与用于验证的CheckGuid字段
if(reader["Exif"] != DBNull.Value)
{
    attachment.Exif        = (string) reader["Exif"];
}
attachment.CheckGuid    = (string) reader["CheckGuid"].ToString();

7、到此数据的操作部分已经都完成了,下面要做的就是修改显示部分,系统最终显示帖子内容是通过Controls下的TextPost类完成的,我们要修改的代码当然也在这里了。
      找到InitializeSkin方法中的body.Text = post.FormattedBody;,在他下面增加如下代码:
            //判断附件的mime类型是否为图片,如果为图片,那么直接调用DisplayImage方法生成显示图片的HTML代码
            //此处可扩充直接显示附件为Flash等其他类型的文件
            string Attachment=post.AttachmentFilename;
            if (Attachment!="" && Attachment!=null)
            {
                AspNetForums.Components.PostAttachment attachment = Posts.GetAttachment(post.PostID);
                string contentType = attachment.ContentType;
                if (contentType=="image/pjpeg" 
                    || contentType=="image/gif"
                    || contentType=="image/bmp" 
                    || contentType=="image/x-png" )
                {
                    
                    body.Text += DisplayImage(Globals.GetSiteUrls().PostAttachment(post.PostID) + "&guid=" + attachment.CheckGuid);          
                
                    //显示Exif信息
                    if(attachment.Exif.Length>0)
                    {
                        body.Text += "<span class=exif>" + attachment.Exif + "</span>";
                    }
                }
            }      DisplayImage方法很简单,代码如下,自己可以修改该代码,给图片增加边框等 /**//// <summary>
/// 如果附件为图片类型,那么调用该方法,生成显示图片的HTML代码
/// </summary>
/// <param name="ImageFilePath">要显示的图片路径</param>
/// <returns></returns>
public string DisplayImage(string ImageFilePath)
    {
                return "<a href='" + ImageFilePath + "' target='_blank'><img  src="" + ImageFilePath + "" border=0></a>";
        }
8、修改附件下载部分,Controls项目下的DownloadPostAttachment类,代码如下:
              System.Web.HttpContext.Current.Response.Clear();
            System.Web.HttpContext.Current.Response.ContentType = attachment.ContentType;
            

            //判断用户从QueryString提交的Guid值是否和数据库的CheckGuid是否相同
            //如果相同,那么不以attachment的形式输出,直接显示文件(通常提供该Guid值的情况都是为图片附件)
            //如果不同,那么以attachment形式输出,直接由用户下载
            if(forumContext.CheckGuid != attachment.CheckGuid)
            {
                System.Web.HttpContext.Current.Response.AppendHeader("content-disposition", "attachment; filename="" + System.Web.HttpUtility.UrlEncode(attachment.FileName,System.Text.Encoding.UTF8) + """);
            }

            //System.Web.HttpContext.Current.Response.OutputStream.Write(attachment.Content, 0, attachment.Length);
                        
            string diskFileName = System.Web.HttpContext.Current.Server.MapPath("~/" + AspNetForums.Configuration.ForumConfiguration.GetConfig().UploadFilesPath + "/" + attachment.UserID.ToString() + "/" + attachment.DiskFileName);
            System.Web.HttpContext.Current.Response.WriteFile(diskFileName);
            System.Web.HttpContext.Current.Response.End();

9、最后要修改的是ForumContext类,要对该类增加一个属性,用于读取通过QueryString传递的Guid值,找到Components项目下的ForumContext类,
      首先增加一变量: string checkGuid =  "";     在构造函数的最下面增加: checkGuid = context.Request.QueryString["guid"];     在最下面增加属性: //CheckGuid 判断是否合法的显示文件请求
public string CheckGuid { get { return checkGuid; } }

至此,我们的修改工作已经全部完成,下面要做的就是对原有的数据库进行升级,将Content字段中的数据保存到硬盘,下面的代码比较简单了,直接贴出代码
在web项目下增加一个页面,后台的操作代码如下,代码比较简单,都是直接操作数据库的。不要忘记增加对PhotoProperties的引用, using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

using System.IO;
using JSG.PhotoPropertiesLibrary;

namespace AspNetForums.Update
{
    /**//// <summary>
    /// update_20040807 的摘要说明。
    /// </summary>
    public class update_20040807 : System.Web.UI.Page
    {
        protected System.Web.UI.WebControls.Button Button1;
    
        private void Page_Load(object sender, System.EventArgs e)
        {
            // 在此处放置用户代码以初始化页面
        }

        Web 窗体设计器生成的代码#region Web 窗体设计器生成的代码
        override protected void OnInit(EventArgs e)
        {
            //
            // CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
            //
            InitializeComponent();
            base.OnInit(e);
        }
        
        /**//// <summary>
        /// 设计器支持所需的方法 - 不要使用代码编辑器修改
        /// 此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {    
            this.Button1.Click += new System.EventHandler(this.Button1_Click);
            this.Load += new System.EventHandler(this.Page_Load);

        }
        #endregion

        private void Button1_Click(object sender, System.EventArgs e)
        {
            
            string ConnectionString = "database=forums;server=dbserver;User ID=sa;Password=;";

            SqlConnection myConn = new SqlConnection(ConnectionString);
            myConn.Open();

            
            
            string select="select * from forums_PostAttachments";
            SqlCommand myComm = new SqlCommand(select,myConn);

            SqlDataReader dr = myComm.ExecuteReader();
            string DiskFileName,CheckGuid,Exif;
            string UpdateString="Update forums_PostAttachments SET DiskFileName='{0}',Exif='{1}',CheckGuid='{2}' where PostID={3}";
            string UserID;
            byte[] fileContent;
            FileStream fs=null;







            SqlConnection myConn2 = new SqlConnection(ConnectionString);
            myConn2.Open();



            while(dr.Read())
            {
                UserID=dr["UserID"].ToString();
                fileContent = (byte[])dr["Content"];
                DiskFileName = Server.MapPath("~/" + AspNetForums.Configuration.ForumConfiguration.GetConfig().UploadFilesPath + "/" + UserID + "/" + System.Guid.NewGuid().ToString()) + System.IO.Path.GetExtension(dr["FileName"].ToString());
                
                CheckGuid = System.Guid.NewGuid().ToString();

                fs=new FileStream(DiskFileName ,FileMode.Create,FileAccess.Write, FileShare.ReadWrite);
                fs.Write(fileContent,0,fileContent.Length);
                fs.Close();
                Exif = GetExif(DiskFileName);

                SqlCommand myComm2 = new SqlCommand(string.Format(UpdateString,System.IO.Path.GetFileName(DiskFileName),Exif,CheckGuid,dr["PostID"].ToString()),myConn2);
                myComm2.ExecuteNonQuery();
                
            }
            dr.Close();        
        }


        private string GetExif(string diskFileName) 
        {
            
            string imgFilePath = diskFileName;
            PhotoProperties pp = new PhotoProperties();

            string exif="";
            try
            {
                pp.Initialize();
                pp.Analyze(imgFilePath);
            
                //Exif Version
                exif += "Exif版本:" +  pp.GetTagDatum(36864).PrettyPrintValue;

                //制造商
                exif += " 制造商:" + pp.GetTagDatum(271).PrettyPrintValue;

                //型号
                exif += " 型号:" + pp.GetTagDatum(272).PrettyPrintValue;

                //拍摄时间
                exif += " 拍摄时间:" + pp.GetTagDatum(36868).PrettyPrintValue;


                //暴光时间:
                exif += "<BR>暴光时间:" +  pp.GetTagDatum(33434).PrettyPrintValue + "秒";

                //光圈
                exif += " 光圈:" + pp.GetTagDatum(33437).PrettyPrintValue;

                //ISO
                exif += "  ISO:" + pp.GetTagDatum(34855).PrettyPrintValue;

                //分辨率
                exif += " 分辨率:" +  pp.GetTagDatum(282).PrettyPrintValue + "/" +  pp.GetTagDatum(283).PrettyPrintValue;
            }
            catch{}

            return exif;
        }
    }
}

      别忘了最后一步工作,删除forums_PostAttachments表中的Content字段,因为我们不再需要他了。
      完工!    

阅读(4170) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册