程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 看我如何快速學習.Net(高可用數據采集平台),快速學習數據采集

看我如何快速學習.Net(高可用數據采集平台),快速學習數據采集

編輯:C#入門知識

看我如何快速學習.Net(高可用數據采集平台),快速學習數據采集


最近文章:高可用數據采集平台(如何玩轉3門語言php+.net+aauto)、高並發數據采集的架構應用(Redis的應用)

項目文檔:關鍵詞匹配項目深入研究(二)- 分表思想的引入

吐槽:本人也是非常討厭拿來主義的,有些培訓每個細節都提到過,主管還找我要實際案例,而不是去安排合適的人去做這件事情,有點過於拿來主義了,有點擔心。

好消息的是:高並發數據采集的架構應用(Redis的應用)團隊已經實現了,不過有部分代碼還是我寫的,值得喝彩下,說明團隊的能力還是不錯的。

最近有時間,我也是用.net完成高可用數據采集平台(如何玩轉3門語言php+.net+aauto)服務的編碼工作。

 

正文開始

要想快速學習某一件事情,我們就得必須做好規劃。

首先我們先來分析下要實現該項目需要哪些方面的技術,我們從哪裡開始分析呢,當然有系統分析師幫你做啦!

所需的技術

1. Microsoft Studio 2010 IDE以及.Net Framework基礎知識的了解

2. 如何利用C#創建服務,服務安裝以及卸載

3. SQLite的基礎應用以及C#如何使用SQLite

4. C#定時器的應用

5. C#的多線程應用以及線程池的應用

6. 操作系統信號量,互斥同步鎖概念以及C#如何使用信號量、互斥同步鎖

7. C#文件操作,ini配置文件讀取技術

8. C# WEB API的調用,以及異步處理知識和C# TASK的了解應用

9. 數據傳輸解析技術,以及C#如何解析JSON

10. 其它常用應用,比如DataSet、DataTable、DataRow、Dictionary、List、KeyValuePair、String等

這些點看起來好恐怖,要想做好應用這些只是小小的一部分,但相對於菜鳥或者學生們就等於天書了,但是我只有一個星期的事情。

只要我們有目的去做事,任何事都不會有阻礙,廢話少說,等下閒我啰嗦了。

 

1. Microsoft Studio 2010 IDE以及.Net Framework基礎知識的了解

     這點我竟然列為了重點,有些人有可能對這點不重視,但是我相信很多有經驗的人都會同我一樣非常重視這點。

    Microsoft Studio 2010 IDE都不用說了,這個大家都是專家,我為什麼會選擇博客園寫文章,是因為我在上學的時候看了一本博客園出版的書,講的是設計模式的應用,覺得非常的不錯,當時博客園是.Net技術平台的佼佼者。

   Microsoft Studio 2010 IDE最主要的一點,就是選擇框架,選擇項目適合的框架。

   .Net Framework 主要也是注意下為什麼有那麼多版本,了解下他們互相是否有關系,比如從2.0升到4.0是否能夠平穩的過渡。

   2. 如何利用C#創建服務,服務安裝以及卸載

    我也是看了一篇博客而學來的,非常不錯,我也把地址貼出來:http://www.cnblogs.com/aierong/archive/2012/05/28/2521409.html

   我也是主要用了(a) 利用.net框架類ServiceBase,步驟參考上面博客的地址:安裝的時候注意下選擇好對應版本的installutil。

    代碼貼出來

public partial class MainService : ServiceBase
    {
        readonly System.Timers.Timer _timer_request;

        readonly System.Timers.Timer _timer_upload;
       
        WorkProcess work = new WorkProcess(10);
       
        public MainService()
        {
            InitializeComponent();

            //install db table
            TaskModel.install();

            _timer_upload  = _timer_request = new System.Timers.Timer(5000)
            {
                AutoReset = true,
                Enabled = true
            };

            _timer_request.Elapsed += delegate(object sender, ElapsedEventArgs e)
            {
                Logger.log("Start Request Data From Api");

                try
                {
                    TaskResponse response = TaskFactory.createFromApi();
                    TaskModel.save(response);
                }
                catch (Exception ex)
                {
                    Logger.error(ex.Message);
                }

                Logger.log("End Request Data From Api");
            };

            _timer_upload.Elapsed += delegate(object sender, ElapsedEventArgs e)
            {
                Logger.log("Start Upload Data To Api");
                try
                {
                    if (!work.wait())
                    {
                        work.doing();
                    }
                }
                catch (Exception ex)
                {
                    Logger.error(ex.Message);
                }
                Logger.log("End Upload Data To Api");
               
            };
         
        }

        protected override void OnStart(string[] args)
        {
            _timer_request.Enabled = true;
            _timer_upload.Enabled = true;  
        }

        protected override void OnStop()
        {
            _timer_request.Enabled = false;
            _timer_upload.Enabled = false;
        }
    }

  

3. SQLite的基礎應用以及C#如何使用SQLite

   也是一樣,有博客就是好,推薦代碼直接拷貝一份過來。http://www.cnblogs.com/OnlyVersion/p/3746086.html

   我也貼個相對精簡的吧。

class DB
    {
        /// <summary>        
        /// 獲得連接對象        
        /// </summary>     
        /// <returns>SQLiteConnection</returns>       
        public static SQLiteConnection GetSQLiteConnection(){

            string str = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            var con = new SQLiteConnection("Data Source=" + str + @"\" + "DataBase" + @"\" + "InfoServiceDb.db");
            return con;       
       }

        /// <summary>
        /// 准備操作命令參數
        /// </summary>
        /// <param name="cmd">SQLiteCommand</param>
        /// <param name="conn">SQLiteConnection</param>
        /// <param name="cmdText">Sql命令文本</param>
        /// <param name="data">參數數組</param>
        private static void PrepareCommand(SQLiteCommand cmd, SQLiteConnection conn, string cmdText, Dictionary<String, String> data)
        {
            if (conn.State != ConnectionState.Open)
                conn.Open();
            cmd.Parameters.Clear();
            cmd.Connection = conn;
            cmd.CommandText = cmdText;
            cmd.CommandType = CommandType.Text;
            cmd.CommandTimeout = 30;
            if (data != null && data.Count >= 1)
            {
                foreach (KeyValuePair<String, String> val in data)
                {
                    cmd.Parameters.AddWithValue(val.Key, val.Value);
                }
            }
        }

        /// <summary>
        /// 查詢,返回DataSet
        /// </summary>
        /// <param name="cmdText">Sql命令文本</param>
        /// <param name="data">參數數組</param>
        /// <returns>DataSet</returns>
        public static DataSet ExecuteDataset(string cmdText, Dictionary<string, string> data)
        {
            var ds = new DataSet();
            using (SQLiteConnection connection = GetSQLiteConnection())
            {
                var command = new SQLiteCommand();
                PrepareCommand(command, connection, cmdText, data);
                var da = new SQLiteDataAdapter(command);
                da.Fill(ds);
            }
            return ds;
        }

        /// <summary>
        /// 查詢,返回DataTable
        /// </summary>
        /// <param name="cmdText">Sql命令文本</param>
        /// <param name="data">參數數組</param>
        /// <returns>DataTable</returns>
        public static DataTable ExecuteDataTable(string cmdText, Dictionary<string, string> data)
        {
            var dt = new DataTable();
            using (SQLiteConnection connection = GetSQLiteConnection())
            {
                var command = new SQLiteCommand();
                PrepareCommand(command, connection, cmdText, data);
                SQLiteDataReader reader = command.ExecuteReader();
                dt.Load(reader);
            }
            return dt;
        }

        /// <summary>
        /// 返回一行數據
        /// </summary>
        /// <param name="cmdText">Sql命令文本</param>
        /// <param name="data">參數數組</param>
        /// <returns>DataRow</returns>
        public static DataRow ExecuteDataRow(string cmdText, Dictionary<string, string> data)
        {
            DataSet ds = ExecuteDataset(cmdText, data);
            if (ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
                return ds.Tables[0].Rows[0];
            return null;
        }

        /// <summary>
        /// 執行數據庫操作
        /// </summary>
        /// <param name="cmdText">Sql命令文本</param>
        /// <param name="data">傳入的參數</param>
        /// <returns>返回受影響的行數</returns>
        public static int ExecuteNonQuery(string cmdText, Dictionary<string, string> data)
        {
            using (SQLiteConnection connection = GetSQLiteConnection())
            {
                var command = new SQLiteCommand();
                PrepareCommand(command, connection, cmdText, data);
                return command.ExecuteNonQuery();
            }
        }

        /// <summary>
        /// 返回SqlDataReader對象
        /// </summary>
        /// <param name="cmdText">Sql命令文本</param>
        /// <param name="data">傳入的參數</param>
        /// <returns>SQLiteDataReader</returns>
        public static SQLiteDataReader ExecuteReader(string cmdText, Dictionary<string, string> data)
        {
            var command = new SQLiteCommand();
            SQLiteConnection connection = GetSQLiteConnection();
            try
            {
                PrepareCommand(command, connection, cmdText, data);
                SQLiteDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection);
                return reader;
            }
            catch
            {
                connection.Close();
                command.Dispose();
                throw;
            }
        }

        /// <summary>
        /// 返回結果集中的第一行第一列,忽略其他行或列
        /// </summary>
        /// <param name="cmdText">Sql命令文本</param>
        /// <param name="data">傳入的參數</param>
        /// <returns>object</returns>
        public static object ExecuteScalar(string cmdText, Dictionary<string, string> data)
        {
            using (SQLiteConnection connection = GetSQLiteConnection())
            {
                var cmd = new SQLiteCommand();
                PrepareCommand(cmd, connection, cmdText, data);
                return cmd.ExecuteScalar();
            }
        }
}

4. C#定時器的應用

  參考1.創建服務的代碼

  主要兩個定時器:

         1. 用於請求服務端要待處理事項

         2. 用於上傳已處理事項的數據到服務器。

5. C#的多線程應用以及線程池的應用

     多線程和線程池的概念這兒略過,本次應用只使用了.Net Framework中提供ThreadPool

    ThreadPool:http://www.cnblogs.com/xugang/archive/2010/04/20/1716042.html ,這篇博客很好的介紹了基礎知識。

    我也貼一下,本次應用的代碼:

public class WorkProcess
    {
        public static int iCount = 0;
        public static int iMaxCount = 0;

        public WorkProcess(int MaxCount)
        {
            iMaxCount = MaxCount;
        }

        //線程池裡的線程將調用Beta()方法
        public void execute(Object state)
        {
            Interlocked.Increment(ref iCount);
            try
            {
                TaskState taskState = (TaskState)state;
                string lockedStr = string.Format("task.locked.{0}.{1}", taskState.taskId, taskState.uploadId);

                lock (lockedStr)
                {
                    TaskUpload.work(taskState);
                }
                int iX = 10000;
                Thread.Sleep(iX);
            }
            catch (Exception e)
            {
                Logger.error(e.Message);
            }
            finally
            {
                Interlocked.Decrement(ref iCount);
            }
           
        }

        public bool wait()
        {
             int threadNumber = 0;  
            //獲取當前線程數  
             threadNumber = Interlocked.Exchange(ref iCount, iCount);

             Logger.log(string.Format("Thread Num:{0}",threadNumber));

             if (threadNumber <= iMaxCount)
             {
                 return false;
             }
             return true;

        }

        public void doing()
        {
            string sql = "SELECT task.id as id,task_upload.id as uploadId FROM task LEFT JOIN task_upload ON task.id=task_upload.task_id WHERE status=:status AND upload_status=:upload_status LIMIT 10";
            Dictionary<string, string> data = new Dictionary<string, string>();
            data.Add(":status", "DONE");
            data.Add(":upload_status", "WAIT");
            DataTable dt = DB.ExecuteDataTable(sql, data);

            foreach (DataRow row in dt.Rows)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(this.execute), new TaskState((int)row["id"], (int)row["uploadId"]));
            }  
        }
    }

6. 操作系統信號量,互斥同步鎖概念以及C#如何使用信號量、互斥同步鎖

   本次應用使用了信號量,主要作用是防止無限制的往線程池裡面PUSH任務,適當的等待下任務的處理進度。

7. C#文件操作,ini配置文件讀取技術

    本次應用主要使用文件存儲一些必要的調試信息以及錯誤信息。

public class Logger
    {
        private static readonly string ErrorFileName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @"\" +"logs"+@"\"+ "error.txt";
        private static readonly string LogFileName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @"\" + "logs" + @"\" + "log.txt";
        
        public static void log(string msg)
        {
            StreamWriter sw = File.AppendText(LogFileName);
            sw.WriteLine(string.Format("{0}:{1}",DateTime.Now,msg));
            sw.Flush();
            sw.Close();
        }

        public static void error(string msg)
        {
            StreamWriter sw = File.AppendText(ErrorFileName);
            sw.WriteLine(string.Format("{0}:{1}", DateTime.Now, msg));
            sw.Flush();
            sw.Close();
        }
    }

Ini配置讀取是為了更好的成為一個獨立的構件,源碼來源博客園的其他作者。

/// <summary>
    /// IniFiles的類
    /// </summary>
    public class IniFiles
    {
        public string FileName; //INI文件名
        //聲明讀寫INI文件的API函數
        [DllImport("kernel32")]
        private static extern bool WritePrivateProfileString(string section, string key, string val, string filePath);
        [DllImport("kernel32")]
        private static extern int GetPrivateProfileString(string section, string key, string def, byte[] retVal, int size, string filePath);

        public static IniFiles config(){

            string configFileName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)+@"\config.ini";

            return new IniFiles(configFileName);
        }

        //類的構造函數,傳遞INI文件名
        public IniFiles(string AFileName)
        {
            // 判斷文件是否存在
            FileInfo fileInfo = new FileInfo(AFileName);
            //Todo:搞清枚舉的用法
            if ((!fileInfo.Exists))
            { //|| (FileAttributes.Directory in fileInfo.Attributes))
                //文件不存在,建立文件
                System.IO.StreamWriter sw = new System.IO.StreamWriter(AFileName, false, System.Text.Encoding.Default);
                try
                {
                    sw.Write("#表格配置檔案");
                    sw.Close();
                }
                catch
                {
                    throw (new ApplicationException("Ini文件不存在"));
                }
            }
            //必須是完全路徑,不能是相對路徑
            FileName = fileInfo.FullName;
        }
        //寫INI文件
        public void WriteString(string Section, string Ident, string Value)
        {
            if (!WritePrivateProfileString(Section, Ident, Value, FileName))
            {
                throw (new ApplicationException("寫Ini文件出錯"));
            }
        }
        //讀取INI文件指定
        public string ReadString(string Section, string Ident, string Default)
        {
            Byte[] Buffer = new Byte[65535];
            int bufLen = GetPrivateProfileString(Section, Ident, Default, Buffer, Buffer.GetUpperBound(0), FileName);
            //必須設定0(系統默認的代碼頁)的編碼方式,否則無法支持中文
            string s = Encoding.GetEncoding(0).GetString(Buffer);
            s = s.Substring(0, bufLen);
            return s.Trim();
        }
 
        //讀整數
        public int ReadInteger(string Section, string Ident, int Default)
        {
            string intStr = ReadString(Section, Ident, Convert.ToString(Default));
            try
            {
                return Convert.ToInt32(intStr);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return Default;
            }
        }
 
        //寫整數
        public void WriteInteger(string Section, string Ident, int Value)
        {
            WriteString(Section, Ident, Value.ToString());
        }
 
        //讀布爾
        public bool ReadBool(string Section, string Ident, bool Default)
        {
            try
            {
                return Convert.ToBoolean(ReadString(Section, Ident, Convert.ToString(Default)));
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return Default;
            }
        }
 
        //寫Bool
        public void WriteBool(string Section, string Ident, bool Value)
        {
            WriteString(Section, Ident, Convert.ToString(Value));
        }
 
        //從Ini文件中,將指定的Section名稱中的所有Ident添加到列表中
        public void ReadSection(string Section, StringCollection Idents)
        {
            Byte[] Buffer = new Byte[16384];
            //Idents.Clear();
 
            int bufLen = GetPrivateProfileString(Section, null, null, Buffer, Buffer.GetUpperBound(0),
                  FileName);
            //對Section進行解析
            GetStringsFromBuffer(Buffer, bufLen, Idents);
        }
 
        private void GetStringsFromBuffer(Byte[] Buffer, int bufLen, StringCollection Strings)
        {
            Strings.Clear();
            if (bufLen != 0)
            {
                int start = 0;
                for (int i = 0; i < bufLen; i++)
                {
                    if ((Buffer[i] == 0) && ((i - start) > 0))
                    {
                        String s = Encoding.GetEncoding(0).GetString(Buffer, start, i - start);
                        Strings.Add(s);
                        start = i + 1;
                    }
                }
            }
        }
        //從Ini文件中,讀取所有的Sections的名稱
        public void ReadSections(StringCollection SectionList)
        {
            //Note:必須得用Bytes來實現,StringBuilder只能取到第一個Section
            byte[] Buffer = new byte[65535];
            int bufLen = 0;
            bufLen = GetPrivateProfileString(null, null, null, Buffer,
             Buffer.GetUpperBound(0), FileName);
            GetStringsFromBuffer(Buffer, bufLen, SectionList);
        }
        //讀取指定的Section的所有Value到列表中
        public void ReadSectionValues(string Section, NameValueCollection Values)
        {
            StringCollection KeyList = new StringCollection();
            ReadSection(Section, KeyList);
            Values.Clear();
            foreach (string key in KeyList)
            {
                Values.Add(key, ReadString(Section, key, ""));
            }
        }
        ////讀取指定的Section的所有Value到列表中,
        //public void ReadSectionValues(string Section, NameValueCollection Values,char splitString)
        //{  string sectionValue;
        //  string[] sectionValueSplit;
        //  StringCollection KeyList = new StringCollection();
        //  ReadSection(Section, KeyList);
        //  Values.Clear();
        //  foreach (string key in KeyList)
        //  {
        //    sectionValue=ReadString(Section, key, "");
        //    sectionValueSplit=sectionValue.Split(splitString);
        //    Values.Add(key, sectionValueSplit[0].ToString(),sectionValueSplit[1].ToString());
 
        //  }
        //}
        //清除某個Section
        public void EraseSection(string Section)
        {
            if (!WritePrivateProfileString(Section, null, null, FileName))
            {
                throw (new ApplicationException("無法清除Ini文件中的Section"));
            }
        }
        //刪除某個Section下的鍵
        public void DeleteKey(string Section, string Ident)
        {
            WritePrivateProfileString(Section, Ident, null, FileName);
        }
        //Note:對於Win9X,來說需要實現UpdateFile方法將緩沖中的數據寫入文件
        //在Win NT, 2000和XP上,都是直接寫文件,沒有緩沖,所以,無須實現UpdateFile
        //執行完對Ini文件的修改之後,應該調用本方法更新緩沖區。
        public void UpdateFile()
        {
            WritePrivateProfileString(null, null, null, FileName);
        }
 
        //檢查某個Section下的某個鍵值是否存在
        public bool ValueExists(string Section, string Ident)
        {
            StringCollection Idents = new StringCollection();
            ReadSection(Section, Idents);
            return Idents.IndexOf(Ident) > -1;
        }
 
        //確保資源的釋放
        ~IniFiles()
        {
            UpdateFile();
        }
    }

我們也是主要學習下使用方式就好了。

8. C# WEB API的調用,以及異步處理知識和C# TASK的了解應用

    C# WEB API的調用也是參考了博客園的知識:http://www.cnblogs.com/r01cn/archive/2012/11/20/2779011.html

    主要也是使用了HttpClient。

    代碼如下:

public static TaskResponse createFromApi()
        {
            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Accept.Add(
               new MediaTypeWithQualityHeaderValue("application/json")
             );
            string readUri = IniFiles.config().ReadString("uri","read","");      
            HttpResponseMessage response = client.GetAsync(readUri).Result;

            if (response.IsSuccessStatusCode)
            {
                // Parse the response body. Blocking!
                var taskString = response.Content.ReadAsStringAsync().Result;
              
                StringReader sr = new StringReader(taskString.ToString());
                JsonSerializer serializer = new JsonSerializer();
                TaskResponse taskResponse = (TaskResponse)serializer.Deserialize(new JsonTextReader(sr),typeof(TaskResponse));
               
                Logger.log(string.Format("nick:{0},Type:{1}", taskResponse.nick, taskResponse.type));
                return taskResponse;               
            }
            else
            {
                Logger.error(string.Format("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase));
                throw new Exception(string.Format("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase));
            }
        }

        public static bool upload(string jsonData)
        {
            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Accept.Add(
               new MediaTypeWithQualityHeaderValue("application/json")
             );

            string uploadUri = IniFiles.config().ReadString("uri", "upload", "");
            List<KeyValuePair<String, String>> paramList = new List<KeyValuePair<String, String>>();
            paramList.Add(new KeyValuePair<string, string>("data",jsonData));

            var response = client.PostAsync(uploadUri, new FormUrlEncodedContent(paramList)).Result;
            if (response.IsSuccessStatusCode)
            {
                var responseString = response.Content.ReadAsStringAsync().Result;
                Logger.log(responseString.ToString());
                return true;
            }
            else
            {
                Logger.error(string.Format("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase));
                return false;
            }

        }

9. 數據傳輸解析技術,以及C#如何解析JSON

   數據傳輸技術已經經歷過很多時代,不過現在的時代用json還是相當比較普及的,比如現在的手機行業的普及,JSON的傳輸方式再一次被推向浪的高潮。

  C# json解析,我使用了第三方包Newtonsoft.Json,原因很簡單,我覺得易用,哪個好用我就選哪個。

  使用方法參考 8.C# WEB API的調用,以及異步處理知識和C# TASK的了解應用

 

10. 其它常用應用,比如DataSet、DataTable、DataRow、Dictionary、List、KeyValuePair、String等

     因為這些是基礎,多使用,摸清他們的關系,基本講求到會用就行了,當然性能優化的另說了,你要糾結的話那就去糾結吧。

 

總結:

     要想成功做好一件事情,是要有目的的去做去學,像我這樣能把所有的都列清楚,一步一步的走吧,相信你離成功將會不遠了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved