2013年9月17日 星期二

[轉貼] 在.NET中運行外部程序的3種方法

    在win32中有ShellExecute方法可以使我們啟動外部的應用程序,在 .NET FrameWork 中我們可以使用Process類來完成類似的功能。
Process在System.Diagnostics中,所以別忘了:
    using System.Diagnostics;
1) 用Process的靜態方法Start
//啟動記事本
Process.Start("notepad.exe");
//啟動記事本,並打開temp.txt文件
        Process.Start("notepad.exe",@"d:\temp.txt");
    此方法最簡單,但功能有限
2) 用帶有ProcessStartInfo參數的 Start方法
             ProcessStartInfo startInfo = new ProcessStartInfo("notepad.exe");
             startInfo.Arguments=@" d:\temp.txt ";
//啟動時最小化
             startInfo.WindowStyle = ProcessWindowStyle.Minimized;
             startInfo.Verb="open";
         Process.Start(startInfo);
3)實例化Process類
             Process process=new Process();
             process.StartInfo.FileName="notepad.exe";
             process.StartInfo.Verb="open";
process.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
             process.StartInfo.Arguments=@" d:\temp.txt";
         process.Start();
第2種方法和第3種方法差不多,他們的可選的功能就比較多了。

[轉貼] 使用|DataDirectory| 的煩惱

Ado.net2.0中新增加了一個MagicValue,可以在應用程序的配置文件的數據庫鏈接串種使用|DataDirectory| ,例如

 <connectionStrings>
        <add name="ConnectionString" connectionString="data  source=.\SQLEXPRESS;Integrated  Security=SSPI;AttachDBFilename=|DataDirectory|data.mdf;User  Instance=true" providerName="System.Data.SqlClient" />
 </connectionStrings>
原來一直使用ASP.net開發web應用,asp.net 2.0特有幾個特殊的文件夾App_Data就是其中一個,web應用的數據庫大可以放在這個下面,一直工作的很好。......知道有一天開始寫winform的程序,^_^,當然也想享受這種方便啦,可是發現Windows應用項目中不支持特殊的文件夾,根本沒有這種東西!沒關係咱自己建,還叫App_Data,運行發現數據庫連不上,從錯誤信息中來看,原來Winform中把|DataDirectory|翻譯成了程序啟動目錄apppath\bin\debug(或release),後面不帶App_Data!數據庫文件倒是自動複製倒了運行目錄下(帶著App_Data的目錄)沒關係,咱自己加上,把上面的鏈接串改成這樣
 <connectionStrings>
        <add name="ConnectionString" connectionString="data  source=.\SQLEXPRESS;Integrated  Security=SSPI;AttachDBFilename=|DataDirectory|App_Data\data.mdf;User  Instance=true" providerName="System.Data.SqlClient" />
 </connectionStrings>
一運行,哈哈,鏈接成功了。試著錄入幾個數據,保存,ok沒問題!退出,再運行,一看傻眼了,剛才錄入的數據不見了!研究半天明白了,原來每次運行,.net都自動複製了一份數據庫到運行目錄,所以上次的數據就都丟失了!想到兩個解決辦法,1,把數據庫的屬性中的「複製到輸出目錄」設置為「不複製」,這樣Debug和Release編譯版本各用各的數據庫,原始的數據庫始終是空的!(好像也有用)2,鏈接到程序目錄中的App_Data下的數據庫。由於對第一種解決辦法,自我感覺有點兒迷惑和Webform中的經驗不一致,所以決定用第二種,Google了一下,有位我不認識的老外^_^給出了解決辦法http://blogs.msdn.com/dataaccess/archive/2005/10/28/486273.aspx,就是在程序啟動時,設置AppDomain.CurrentDomain.setData(「DataDirectory」,我的目錄字符串);Winform的程序那當然是在Main函數中了,廢話不說了,我的代碼如下
string p = AppDomain.CurrentDomain.BaseDirectory;
            if (p.IndexOf("\\bin\\") > 0)
            {
                if (p.EndsWith("\\bin\\Debug\\"))
                    p = p.Replace("\\bin\\Debug", "");
                if (p.EndsWith("\\bin\\Release\\"))
                    p = p.Replace("\\bin\\Release", "");
            }

            if (!p.EndsWith("App_Data\\"))
                p = p + "App_Data\\";
            AppDomain.CurrentDomain.SetData("DataDirectory", p);
思想就是去掉調試期間和生產期間的不同,這樣要注意的是,發佈程序的時候,數據庫也要放到App_Data目錄下面。  

[轉貼] 通過HtmlAgilityPack+XPath來優化網頁採集


今天特別學習和實踐了一下HtmlAgilityPack和XPath,並作下筆記。

1.下載HtmlAgilityPack.dll並將其添加引用到項目中,然後在代碼中聲明引用。
引用:
using HtmlAgilityPack;

2.下載獲取HTML頁面的步驟和我上篇文章裡介紹的差不多,都是先用WebClient或者WebRequest類來下載HTML頁面然後處理成字符串。

3.與上次不同的是,這裡分析和抓取HTML節點中的數據不再是之前那種STRING字符串操作的方式,而是封裝成一個HtmlDocument對象,通過HtmlDocument中的方法來索引你需要抓取HTML節點,進而取出節點中的值。

4.若需要抓取的節點有ID,類似「<div id='post_list'>value</div>」這種,那很簡單只需調用GetElementbyId方法根據節點ID即可獲取所需節點。從而通過HtmlNode中的InnerText或Attribute屬性來獲取你想要的值。
CODE:
//實例化HtmlAgilityPack.HtmlDocument對像
HtmlDocument doc = new HtmlDocument();
//載入HTML
doc.LoadHtml(mainData);

//根據HTML節點NODE的ID獲取節點
HtmlNode navNode = doc.GetElementbyId("post_list");

5.但很多情況下HTML節點是沒有ID的,那就需要通過XPATH語言來查找匹配所需節點(XPath教程)。以抓取博客園首頁文章為例,通過查看博客園HTML可以發現博客園首頁裡的文章列表都是放在一個ID為"post_list"的"<div>"節點中的。
 
這樣的話就可以通過調用GetElementbyId方法來定位到這個節點了。

6.在獲取到"post_list"節點後,接下來就可以調用SelectSingleNode方法通過XPATH表達式來索引出需要抓取的節點,從而抓取到文章的標題和鏈接地址。
(PS:在博客園首頁"post_list"節點裡,平均每4個DIV就是一篇新的文章可以利用這一規律遍歷出首頁所有文章)
CODE:
//實例化HtmlAgilityPack.HtmlDocument對像
HtmlDocument doc = new HtmlDocument();
//載入HTML
doc.LoadHtml(mainData);

//根據HTML節點NODE的ID獲取節點
HtmlNode navNode = doc.GetElementbyId("post_list");
//根據XPATH來索引節點
//div[2]表示文章鏈接a位於post_list裡面第3個div節點中
HtmlNode navNode2 = navNode.SelectSingleNode("//div[2]/h3/a");
//獲取文章鏈接地址
string articleTitle = navNode2.Attributes["href"].Value.ToString();
//獲取文章標題
string articleName = navNode2.InnerText;
對比一下之前使用string截取字符串的方法:
//以"<a class=\"titlelnk\" href=\""作為抓取點開始採集
mainData=mainData.Substring(mainData.IndexOf("<a class=\"titlelnk\" href=\"") + 26);

//獲取文章頁面的鏈接地址
string articleAddr = mainData.Substring(0,mainData.IndexOf("\""));

//獲取文章標題
string articleTitle = mainData.Substring(mainData.IndexOf("target=\"_blank\">") + 16,
                                               mainData.IndexOf("</a>") - mainData.IndexOf("target=\"_blank\">") - 16);
可見與之前相比,使用HtmlAgilityPack.HtmlDocument類來實現前台HTML的分析和採集在頁面編碼和數據分析上面處理更加合理、優化,代碼也更加簡潔。

目前只是粗淺地學了一下HtmlAgilityPack提取HTML節點數值的應用,更多應用以及採集速度的優化處理等方面尚未仔細研究,還望高人指點。

如果可能盡量使用接口(介面)來編碼


如果可能盡量使用接口來編程  
.NET框架包括類和接口,在編寫程序的時候,你可能知道正在用.NET的哪個類。然而,在這種情況下如果你用.NET支持的接口而不是它的類來編程時,代碼會變得更加穩定、可用性會更高。請分析下面的代碼:  
private void LoadList (object []items, ListBox l)  
{  
 for(int i = 0; i < items.Length; i++)  
  l.Items.Add(items[i].ToString());  
}  
這個函數從一個可為任何對象的數組中加載ListBox,這段代碼被限定為只能使用數組。假想過些時候你發現那些對像存在數據庫中,或別的集合中。那麼你需要修改程序來使用不同的集合類型。如果你用ICollection接口來寫那段程序,你就不用修改那段程序了,對於任何實現ICollection接口的類型它都能很好的工作:  
private void LoadList (ICollection items,ListBox l)  
{  
  foreach(object o in items)  
  l.Items.Add(o.ToString());  
}  
ICollection被數組和所有System.Collection中的集合實現。此外,多維數組也支持ICollection接口。如果那還不夠的話,數據庫.NET類同樣支持ICollection接口。用接口寫的這個函數不用需改就可以才許多中情況下使用。  

[轉貼] C#圖片處理高級應用(裁剪,縮放,清晰度,浮水印)


前言
需求源自項目中的一些應用,比如相冊功能,通常用戶上傳相片後我們都會針對該相片再生成一張縮略圖,用於其它頁面上的列表顯示。隨便看一下,大部分網站基本都是將原圖等比縮放來生成縮略圖。但完美主義者會發現一些問題,比如顯示排版時想讓相片縮略圖列表非常統一、整齊、和美觀,比如要求每張縮略圖大小固定為120 x 90且不拉伸變形怎麼辦?再比如用戶頭像如何讓縮略圖比原圖更清晰?或是如何在上傳的圖片下加一個半透明的LOGO水印?
OK,本文根據自己的項目代碼描述以上問題的解決方案,所謂C#圖片處理高級應用,感覺有點標題黨了,這些功能並無多大技術含量。全部基於.Net Framework類庫完成,代碼中包含了C#圖片處理的一些基礎知識,與大家分享,個人能力有限,不足之處還請及時指正。
提高縮略圖清晰度
(原圖200*200,12.3k)(處理後80*80,17.7k)
之前一直認為縮略圖不可能比原圖清晰,直到某天一位產品的同事給我看某網站的效果。於是開始尋找.NET下實現代碼,仔細觀察縮略圖確實比原圖更清晰了一些,但代價是縮略圖文件比原圖更大,所以如果你想讓一張佔滿顯示器屏幕的超大圖片更清晰,那麼圖片佔用空間和網絡流量就必需考慮了,如果是互聯網應用,建議縮略圖在200像素以內的使用該方法。當然如果哪位有更好的代碼即能讓圖片文件大小變化不大又讓圖片更清晰還請分享。
圖片裁剪
(原圖256*192)(裁剪要求100*100)
(原圖256*192)(裁剪要求90*120)
(原圖256*192)(裁剪要求120*90)
(原圖146*256)(裁剪要求100*100)
 
(原圖146*256)(裁剪要求90*120)
(原圖146*256)(裁剪要求120*90)
算法:以原圖中心作為裁剪中心,最大範圍的對原圖進行裁剪,然後對裁剪結果等比縮放。
圖片水印
僅演示了效果,如需要變更字體、水印透明度、位置等可自行在代碼或方法中擴展。
代碼
封裝了幾個通用的方法,如發現有BUG或漏洞還請及時指正。
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
  
namespace WuJian.Common
{
    /// <summary>
    /// 圖片處理類
    /// 吳劍 2008-07-02 創建
    /// 吳劍 2011-01-21 修改
    /// </summary>
    public class PTImage
    {
        #region 正方型裁剪並縮放
        /// <summary>
        /// 正方型裁剪
        /// 以圖片中心為軸心,截取正方型,然後等比縮放
        /// 用於頭像處理
        /// </summary>
        /// <remarks>吳劍 2010-11-23</remarks>
        /// <param name="postedFile">原圖HttpPostedFile對像</param>
        /// <param name="fileSaveUrl">縮略圖存放地址</param>
        /// <param name="side">指定的邊長(正方型)</param>
        /// <param name="quality">質量(範圍0-100)</param>
        public static void CutForSquare(System.Web.HttpPostedFile postedFile, string fileSaveUrl, int side, int quality)
        {
            //創建目錄
            string dir = Path.GetDirectoryName(fileSaveUrl);
            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);
  
            //原始圖片(獲取原始圖片創建對象,並使用流中嵌入的顏色管理信息)
            System.Drawing.Image initImage = System.Drawing.Image.FromStream(postedFile.InputStream, true);
  
            //原圖寬高均小於模版,不作處理,直接保存
            if (initImage.Width <= side && initImage.Height <= side)
            {
                initImage.Save(fileSaveUrl, System.Drawing.Imaging.ImageFormat.Jpeg);
            }
            else
            {
                //原始圖片的寬、高
                int initWidth = initImage.Width;
                int initHeight = initImage.Height;
  
                //非正方型先裁剪為正方型
                if (initWidth != initHeight)
                {
                    //截圖對像
                    System.Drawing.Image pickedImage = null;
                    System.Drawing.Graphics pickedG = null;
  
                    //寬大於高的橫圖
                    if (initWidth > initHeight)
                    {
                        //對像實例化
                        pickedImage = new System.Drawing.Bitmap(initHeight, initHeight);
                        pickedG = System.Drawing.Graphics.FromImage(pickedImage);
                        //設置質量
                        pickedG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                        pickedG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                        //定位
                        Rectangle fromR = new Rectangle((initWidth - initHeight) / 2, 0, initHeight, initHeight);
                        Rectangle toR = new Rectangle(0, 0, initHeight, initHeight);
                        //畫圖
                        pickedG.DrawImage(initImage, toR, fromR, System.Drawing.GraphicsUnit.Pixel);
                        //重置寬
                        initWidth = initHeight;
                    }
                    //高大於寬的豎圖
                    else
                    {
                        //對像實例化
                        pickedImage = new System.Drawing.Bitmap(initWidth, initWidth);
                        pickedG = System.Drawing.Graphics.FromImage(pickedImage);
                        //設置質量
                        pickedG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                        pickedG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                        //定位
                        Rectangle fromR = new Rectangle(0, (initHeight - initWidth) / 2, initWidth, initWidth);
                        Rectangle toR = new Rectangle(0, 0, initWidth, initWidth);
                        //畫圖
                        pickedG.DrawImage(initImage, toR, fromR, System.Drawing.GraphicsUnit.Pixel);
                        //重置高
                        initHeight = initWidth;
                    }
  
                    //將截圖對像賦給原圖
                    initImage = (System.Drawing.Image)pickedImage.Clone();
                    //釋放截圖資源
                    pickedG.Dispose();
                    pickedImage.Dispose();
                }
  
                //縮略圖對像
                System.Drawing.Image resultImage = new System.Drawing.Bitmap(side, side);
                System.Drawing.Graphics resultG = System.Drawing.Graphics.FromImage(resultImage);
                //設置質量
                resultG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                resultG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                //用指定背景色清空畫布
                resultG.Clear(Color.White);
                //繪製縮略圖
                resultG.DrawImage(initImage, new System.Drawing.Rectangle(0, 0, side, side), new System.Drawing.Rectangle(0, 0, initWidth, initHeight), System.Drawing.GraphicsUnit.Pixel);
  
                //關鍵質量控制
                //獲取系統編碼類型數組,包含了jpeg,bmp,png,gif,tiff
                ImageCodecInfo[] icis = ImageCodecInfo.GetImageEncoders();
                ImageCodecInfo ici = null;
                foreach (ImageCodecInfo i in icis)
                {
                    if (i.MimeType == "image/jpeg" || i.MimeType == "image/bmp" || i.MimeType == "image/png"|| i.MimeType == "image/gif")
                    {
                        ici = i;
                    }
                }
                EncoderParameters ep = new EncoderParameters(1);
                ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)quality);
  
                //保存縮略圖
                resultImage.Save(fileSaveUrl, ici, ep);
  
                //釋放關鍵質量控制所用資源
                ep.Dispose();
  
                //釋放縮略圖資源
                resultG.Dispose();
                resultImage.Dispose();
  
                //釋放原始圖片資源
                initImage.Dispose();
            }
        }
  
        /// <summary>
        /// 正方型裁剪
        /// 以圖片中心為軸心,截取正方型,然後等比縮放
        /// 用於頭像處理
        /// </summary>
        /// <remarks>吳劍 2010-11-23</remarks>
        /// <param name="postedFile">原圖HttpPostedFile對像</param>
        /// <param name="fileSaveUrl">縮略圖存放地址</param>
        /// <param name="side">指定的邊長(正方型)</param>
        /// <param name="quality">質量(範圍0-100)</param>
        public static void CutForSquare(System.IO.Stream fromFile, string fileSaveUrl, int side, int quality)
        {
            //創建目錄
            string dir = Path.GetDirectoryName(fileSaveUrl);
            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);
  
            //原始圖片(獲取原始圖片創建對象,並使用流中嵌入的顏色管理信息)
            System.Drawing.Image initImage = System.Drawing.Image.FromStream(fromFile, true);
  
            //原圖寬高均小於模版,不作處理,直接保存
            if (initImage.Width <= side && initImage.Height <= side)
            {
                initImage.Save(fileSaveUrl, System.Drawing.Imaging.ImageFormat.Jpeg);
            }
            else
            {
                //原始圖片的寬、高
                int initWidth = initImage.Width;
                int initHeight = initImage.Height;
  
                //非正方型先裁剪為正方型
                if (initWidth != initHeight)
                {
                    //截圖對像
                    System.Drawing.Image pickedImage = null;
                    System.Drawing.Graphics pickedG = null;
  
                    //寬大於高的橫圖
                    if (initWidth > initHeight)
                    {
                        //對像實例化
                        pickedImage = new System.Drawing.Bitmap(initHeight, initHeight);
                        pickedG = System.Drawing.Graphics.FromImage(pickedImage);
                        //設置質量
                        pickedG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                        pickedG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                        //定位
                        Rectangle fromR = new Rectangle((initWidth - initHeight) / 2, 0, initHeight, initHeight);
                        Rectangle toR = new Rectangle(0, 0, initHeight, initHeight);
                        //畫圖
                        pickedG.DrawImage(initImage, toR, fromR, System.Drawing.GraphicsUnit.Pixel);