2012年12月14日 星期五

走到最後還能留在身邊的,都要珍惜

在網路看到一段 Java Code,正想要好好品味一下時,才發現身邊只剩下那台跟著我許多年的 NB,因為他太老了,跑微軟的作業系統更顯吃力,所以才變節投靠 Ubuntu ,早些年前,他身上還貼著正版的微軟 XP 序號、標籤、標語,當年的繁華光景,連「華碩品質堅若石頭」的彩帶我都還留著,如今卻落魄到同我為伍,不經讓我想起「老人與狗」這本書...

我問他,你跑得快嗎?他搖搖頭。
我再問他,你可以跑 Java 嗎?他也搖搖頭。

看到他一臉徬徨無助的眼神,讓我升起悲憫之心,於是我決定好好教他,讓他可以「跑 Java」。


於是,我在深夜裡,冒著外頭的刮風下雪,來到爪哇旗艦店,一進門,就看到親切的業務向我正面迎來,並單手向我熱情的招呼著,同時遞送上來一杯熱騰騰的咖啡。沒多久,我就在展示間看到今年最流行的第七代 Java,型號是七架。望著七架流線的造型,彷彿可以感受到風在我臉上吹拂,速度在我腳下奔馳的快感。我當下就決定買下,並轉送給我的 NB,這種感覺,就好比當年淑珍買積架送給致中的心情是一模一樣的,「天下父母心,花別人的錢最開心」。















印象中,要能夠在 Ubuntu上跑 Java,是要花蠻多功夫的,但我的業務員告訴我一個簡單的方法,叫做 PPA (Personal Package Archive)。只要三行指令,就可以辦到好。

sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java7-installer

原來有一段小故事是這樣的。在 Ubuntu 的世界裡,會有一個叫做「軟體中心」,伴隨著每六個月推出新版本的檔期,都可以在裡面找到最新的套件,而這些套件都是經過 Ubuntu 團隊審核過才放上去的。問題,就在於我們所需要的軟體,是否可以慢慢等待到審核通過後才能使用呢?如果我要的七架已經問世,但又不想等待半年後才拿到,這時就可以使用 PPA  的方式來取得,但風險則是沒通過審核,所以不保證安裝完後是否會影響系統的穩定性。這跟我要買 iPhone 的道理是一樣的,在美國新版的已經問世,但台灣還沒正式開賣,所以只好透過「水貨」的管道來取得。

透過那三行指令,我終於讓我的 NB 可以跑 Java 了,但我發現一個很大的問題,他不認識中文。於是,我又開始「ㄠ」我的業務員,同樣也是得到三行簡單好用的指令來完成中文環境的開發。

# cd /usr/lib/jvm/java-6-sun/jre/lib/fonts
# mkdir fallback
# ln -s /usr/share/fonts/truetype/wqy/wqy-zenhei.ttc

看著他正在努力的奔跑著,我笑了,我睡了....



參考:
01:INSTALL ORACLE JAVA 7 IN UBUNTU VIA PPA REPOSITORY
02:解决ubuntu下java中文字体显示方框问题
03:What Is An Ubuntu PPA & Why Would I Want To Use One?
04:快速添加 Ubuntu PPA 源

2012年12月13日 星期四

與 Split 更親近一點

先前在使用 C# 對字串進行切割 (split) 動作時,常常會希望把空白的字串過濾掉,只留下字串長度不是 0 的。而這工作其實也不難,就是將  split 後所得到的字串陣列,在你要用時用迴圈一筆一筆去濾掉空白的陣列元素。

剛好今天看到 「StringSplitOptions 列舉型別」介紹了其中的「RemoveEmptyEntries」成員,可以限定傳回值不會加入包含了空字串的陣列元素,有這麼好康的事情就來試試效果如何。於是寫了一個簡單的測試程式,沒想到添加了這作法還真是簡潔啊, 而且他從 .net 2.0 就開始支援了。

class Program
{
    static void Main(string[] args)
    {
        string strTest1 = "b,a,c,,";
        char[] charSeprator = new char[] { ',' };

        string strTest2 = "BB[x]CC[x]AA[x]";
        string [] strSeprator=new string[]{"[x]"};

       //以字元來切割
        foreach (string str in strTest1.Split(charSeprator, StringSplitOptions.RemoveEmptyEntries))
            Console.WriteLine(str);

       //以字串來切割
        foreach (string str in strTest2.Split(strSeprator, StringSplitOptions.RemoveEmptyEntries))
            Console.WriteLine(str);

        Console.ReadLine();

    }
}

如果開發環境是.net 3.5以上的版本,還可以更進一步去將 split 的結果進行排序後再取出。例如:

strTest2.Split(strSeprator, StringSplitOptions.RemoveEmptyEntries).OrderBy(g=>g)

就可將陣列進行排序。


參考:
01:StringSplitOptions 列舉型別
02:Extension Methods (C# Programming Guide)

2012年12月11日 星期二

String,StringBuffer,StringBuilder 的三角關係

不管是在 Java 或是 C#,對於 String 這物件應該都不陌生。但如果考量是在字串串接的用途上時, String 的效能可真的就顯得遜色許多。

String 物件一旦在記憶體被配置之後,他就不能夠再改變了,所以他常常被說成是 immutable object。但我們卻很習慣寫成這樣:


三行程式寫完後,請求了三塊新的記憶體配置,也同時浪費了兩塊記憶體。

針對這個問題,Java 提供了 StringBuffer 物件,讓我們可以對字串加加減減,也不會另外再要一塊新的記憶體位址來存放。在這物件當中,Java 還考慮到多執行緒的問題,也就是說,不同的執行緒不會同時對同一個 StringBuffer 物件做新增或是修改的動作,例如當執行緒 A 在使用 「StringBuffer 甲」的時候,執行緒 B 必須等到執行緒 A 完成「StringBuffer 甲」的處理動作 之後才能使用,這就是我們常說的 thread-safe。

對於 Java 所提供的 StringBuffer 物件,針對字串串接的執行校能上,的確可以非常明顯地看到提昇,但一般對程式設計師來說,大部分時機其實可能都不需要考量多執行緒的問題,如果不考慮多執行緒的情況下,減少多餘的判斷處理,是否還有機會再提昇字串串接的效能呢?

果真,在 JDK 1.5. 之後,開始出現了新的物件 StringBuilder ,他與 StringBuffer 的用途幾乎如出一轍,唯一的不同是減少了多執行緒的考量。日後如果只是在寫單一執行緒的程式考量下,StringBuilder 會是較好的選擇。「StringBuffer vs. StringBuilder performance comparison」文章作者Daniel 針對 StringBuilder 與 StringBuffer 兩者間的效能寫了一段簡單的程式來比較,而我自己也透過他的程式在自己電腦上得到了下面數據:


從數據上看來, StringBuilder 已經比 StringBuffer 提昇了一倍以上的效能,當然這兩者更遠遠超過 String 的字串串接。

同樣的情況,也出現在 微軟的 C# 裡。在字串串接的情況下, StringBuilder 遠比 String 的效能提昇很多,唯一讓我不解的,是這次微軟的身上少了 StringBuffer 的味道...,我很認真的想知道這次微軟為何沒收錄 StringBuffer 這物件,但迄今依舊無解。而微軟的 StringBuilder,同樣也是不考慮多執行緒,可以在微軟的官方文件「StringBuilder Class」看到 Thread Safety 的聲明:

Any public static (Shared in Visual Basic) members of this type are thread safe.
Any instance members are not guaranteed to be thread safe.

可從上面申明中知道,C# 裡面的 StringBuilder 並不是 thread-safe。

另一個有趣的地方,是從 JDK 釋出的時程來看看,彷彿 .net 在 2003年時釋出的 .net 1.1, 已經比 Java 更早公佈 StringBuilder 物件了!


經由這一次的整理,可以知道 String 在字串串接上所面臨的效能瓶頸,並透過 Daniel 的程式在定量上可以得到支撐。此外,也可以更清楚去分別依據是否為單一執行緒來正確抉擇 StringBuilder 或 StringBuffer。

參考:
01:StringBuffer vs. StringBuilder performance comparison
02:StringBuilder Class
03:Java JDK (Java Development Kit) Releases Dates and Release Differences
04:Java SE 6全方位學習
05:StringBuilder和StringBuffer的差別及清空內容方式
06:StringBuilder vs StringBuffer
07:Why use StringBuilder? StringBuffer can work with multiple thread as well as one thread?
08:StringBuffer and StringBuilder
09:Is the C# '??' operator thread safe?
10:如何:增進 Visual C# .NET 中的字串串連效能
11:Daniel 簡單測試程式

2012年12月7日 星期五

當 SSRS 遇到 VSS 時應該知道的事

最近接收了一包  SQL Server Reporting Service (SSRS) 所開發的報表,因為這包報表程式沒有使用任何的版本管控。富有正義感且集聚勇氣於一身的我,就當仁不讓地主動請纓要做好版本管控,於是我就用了最簡單的 Visual SourceSafe(VSS) 來控管這包報表。

其實做這事情真的沒有甚麼難度,一下子就把報表全部加到 VSS 裡面去了。但當我一執行報表時,竟然出現:


拒絕存取路徑 'D:\MyCode\bin\Debug\新世代青年生命成長營.rdl'

我想,是不是 「新世代青年生命成長營.rdl」 這隻檔案被設為唯讀所造成的,於是手動去把唯讀取消,再執行一次,結果還是一樣。於是我網路上找了很一陣子,發現有一篇微軟的文章:「修正: 在組建中,清除,伺服器專案錯誤報告,或預覽中 SQL Server 2008 R2 和出價等作業」,原來 SSRS 有 hotfix 啊,於是造著說明去下載,蠻肥的,約2百多M,沒想到更新完後再重試,竟然還是一樣。

在一股不理智的衝動下,我誤刪了 \bin 資料夾。但只要重新佈署一次,這個 \bin 資料夾自己又會重新生出來,且回覆正常了。但過些時日,這問題又會再跑出來一次,我刪除 \bin 資料夾後又可以正常。

當我閱讀了「FISERV TAP - Checking it RDL Source Sets Output Folder to Read Only」,發現這問題在 SSRS 與 VSS 搭配在一起,就很容易發生。解決方法可以參考該篇文章,但我覺得自己最省力氣的,還是刪除 \bin 資料夾。

參考:
01:修正: 在組建中,清除,伺服器專案錯誤報告,或預覽中 SQL Server 2008 R2 和出價等作業
02:FISERV TAP - Checking it RDL Source Sets Output Folder to Read Only
03:Access to the Path Error in Visual Studio
04:修正: 在組建中,清除,伺服器專案錯誤報告,或預覽中 SQL Server 2008 R2 和出價等作業

2012年11月9日 星期五

關於 Reporting Service 的報表資料

不管是使用 SQL Server 的 Business Intelligence Development Studio 或是 Visual Studio 2012 開發 Reporting Service 報表,應該對於報表資料  (Report Data) 這視窗不陌生。


可是,當我不小心按了「X」把他關閉後,卻再也怎麼找不回來了。找了好久才發現,要呼叫他之前竟還要先做一個動作。首先,必須先將專案裡的任何一支報表打開,然後在該報表的設計頁面點一下,主要是讓設計頁面目前是被聚焦(focus)的,這時,再點選最上面功能列裡的「檢視(View)」,在檢視頁籤中,最下面就會出現「報表資料(Report Data)」,點選後就可以找回自己的報表資料視窗了。

關於要在「檢視」功能列中出現「報表資料」選項,還得先點選設計頁面才行的作法,這 UI 的設計邏輯真的會讓人混淆,或許不需這麼複雜,永遠都出現在「檢視」功能列中不就好了嗎?而且加上這限制,還真的想不出有何特別意義。

參考:
01:停駐報表設計師中的報表資料窗格 (SSRS)

2012年11月6日 星期二

由VS2003 升級後的專案無法使用 Update Panel

將專案從 VS2003 升級到 VS2005 後,原本想要試試微軟新功能 Update Panel,但竟然一點效果也沒有,是不是我哪裡弄錯了呢?自己也是照著書本上一行一行打的啊?於是在 google 上開始打著 Update Panel 無路用之類的關鍵字,哈哈,還竟然真的查到許多人在討論這件事。

原來這故事,要從 XHTML 開始說起。話說 HTML 稱霸網壇數十年早已不是甚麼新鮮事,他嚴然已成為一種標準通用的標記語言,但他的缺點就是太鬆散了。大小寫不分,有沒有結束的封閉符號也不管,人這麼聰明,看懂是沒問題,但機器這麼笨,大寫小寫傻傻分不清楚。美其名是為了提昇機器的效率,其實是掩蓋機器沒那麼聰明的事實,所以大家訂了一個更嚴格的約定,都用小寫、一定要有封閉符號...,諸如此類的規定,只是為了讓機器能夠減少去做多餘的判斷,快速的達成我們所要的結果。這項別稱為近代人類的不平等條約,就是 XHTML(詳見:wiki 說明的 XHTML)。


目前 XHTML 的版本大致分為以下幾類:

  • XHTML 1.0 Strict(嚴格版): 是參照「HTML 4.01 Strict」改編,但不包括被棄用的元素。
  • XHTML 1.0 Transitional(過渡版): 是參照「HTML 4.01 Transitional」改編,包括已於Strict版本被棄用的呈現性元素(例如<center>, <font>等)。
  • XHTML 1.0 Frameset(框架版): 是參照「HTML 4.01 Frameset」改編,並允許於網頁中定義框架元素。
  • XHTML 1.1
  • XHTML Basic
然而,在微軟 .Net 1.0 、.Net 1.1 的年代裡,還是依循著早期 HTML 的快樂好日子,我的程式也是隨便寫寫,他也睜一隻眼閉一隻眼讓我過。但好景不常,隨著 .Net 2.0 降臨,開始要求要符合 XHTML 的規範,這也難怪從 VS2003 升級到 VS2005 後的程式碼,處處可見紅字。

如果專案是從 .Net 1.0、.Net 1.1 透過自動升級精靈升級到 2.0 以後的版本,為了讓先前已經寫好的程式能夠順利的渡過這青黃不接的階段,微軟提出了三種方案讓你選擇,而這個設定,就是在 web.config 檔裡的 xhtmlConformance。這三種方案分別是:


  • Legacy:他就如同早期 .net 1.0、.net 1.1 的 HTML 規範,並不會去限制你一定要遵守 XHTML 的規定。
  • Transitional:他表示要符合等同 XHTML 1.0 Transitional 的規範
  • Strict:他表示要符合更嚴格的 XHTML 1.0 Strict 的規範

而我們升級過後的專案,為了要能夠向下相容、無痛升級,所以就會主動在我們的 web.config 上加上一行:
<system.web>
      <xhtmlConformance mode="Legacy" />
</system.web>

很不巧地,我想要使用的 Update Panel 功能,他卻只能在 Transitional 與 Strict 的模式下才能執行,這也正是為何透過升級而來的專案,會出現 Update Panel  無法正常使用的狀況。所以,這時的處理方式,可以透過修改 xhtmlConformance ,將其改為 Transitional 或 Strict ,就可以讓 Update Panel 正常使用了!如果你看 xhtmlConformance 不順眼,刪了他也是可以,因為他的預設值是 Transitional。

參考:
01:XHTML
02:ASP.NET AJAX & XHTML Conformance
03:Gotcha: Don't use <xhtmlConformance mode="Legacy"/> with ASP.NET AJAX
04:.NET 2.0 Update Panel won't perform partial postbacks on upgraded 1.1 sites

2012年11月5日 星期一

一場誤會

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="jsTest.aspx.cs" Inherits="WebApplication1.jsTest" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>    
  
</head>
<body>
    <form id="form1" runat="server">
    <div>
昔誰持種來 而今佳色開<br>
昔誰持種來 而今佳色開<br>
昔誰持種來 而今佳色開<br>
    </div>

    <script>alert('提示訊息');</script>


    </form>
</body>
</html>

如上很簡單的 HTML 語法,只是好奇的想知道,是先跳出 javascript 的「提示訊息」呢,還是會先顯示「昔誰持種來 而今佳色開」的說明呢?我覺得在剖析 HTML 時,是由上而下的順序,應該會先顯示文字說明,而 javascript 是擺在最後面,所以會放到後面才執行。不只我這麼說,別人也是如是說,請看:「Load and execution sequence of a web page?」對於 mauris 所解釋的內容,真的非常詳細。

但我在 IE8 瀏覽結果時,卻出現如下結果:

而 chrome 與 firefox 則是如下(以 chrome 為例):

這說明了,以上面的範例來說,IE8 是先執行 javascript ,然後再對文字說明做處理;相反地,Chrome 與 FireFox 則是先對文字說明做處理,然後再執行 javascript。但這樣的結果,還真的讓人很疑惑?於是我再測了一下 IE6,沒想到 IE6 的行為,竟然跟 chrome 與 firefox 是一樣的,難道 IE8 是怪胎嗎?或許把過錯都推給 IE8 還蠻多人會覺得理所當然,但直到有一天,我把 jQuery 的版本升級到 1.7.1 之後,IE8 的處理結果竟也跟其他瀏覽器都一致了。原來事情的始末,竟是 jQuery 1.6.4 的版本,造成 IE8 在執行 javascript 時的觸發順序都提到最前面了。

在尚未發現主要原因是 jQuery 版本所引起之前,我的作法是在 javascript 標籤屬性裡加上 defer:

<script defer>alert('提示訊息');</script>

defer 這關鍵字,僅支援 IE 瀏覽器,他會讓 javascript 的執行時間延遲到整個頁面都下載完成後才執行。對我而言,只要跳出訊息視窗時不讓背景畫面一片空白,也就可以了。只是沒想到,真正引發問題的原因竟是自己所使用的 jQuery 版本。

IE8,我錯了,請您原諒~



參考:
01:Load and execution sequence of a web page?
02:姚博文 Script中defer的作用
03:asp.net弹出信息框——没有用ScriptManager
04:HTML <script> 标签的 defer 属性