1. 程式人生 > >編寫和Mono相容.Net程式系列----最常見的不相容場景和基本解決辦法

編寫和Mono相容.Net程式系列----最常見的不相容場景和基本解決辦法

    對於同樣的任務,不同的平臺通常都會有自己的做法,表現的內容通常類似,這種做法對程式設計師的影響是很大的。同樣,即使在.Net框架下工作,程式設計師也同樣面臨挑戰,好在.Net平臺在設計這在早期就意識到這些問題,.Net本身就提供瞭解決方案,只是,平臺相容的程式碼要麼蹩腳,有麼太複雜。現在就讓我們以儘可能小的的代價,以儘可能優美的編碼方式提升程式的相容性。     

  相容性問題通常可以分為有限的場景,每一個場景中只要遵守一定的規則,就能解決問題:

  場景一,檔案系統分割符的問題,Windows使用以碟符開始的檔案系統,並且使用“\”作為目錄分隔符,而Unix族系統使用"/"作為檔案系統的開始,並且使用"/"作為目錄分隔符。

    有多種方法可以解決這個問題,第一種方法,使用軟實現而不是硬實現,如果程式設計師使用字串相加的方式自己組建路徑這屬於硬實現。分隔符不同,硬實現就不能跨平臺;如果使用,System.IO.Path類的Combine方法組建目錄路徑,那麼這屬於軟實現,Combile使用平臺特有的分隔符組建最終路徑。第二種方法,使用平臺分隔符變數和String.Format函式組建最終路徑,這是推薦方法,因為我覺得這樣更實用,System.IO.Path.Separate 常量代表了平臺獨立的分隔符,比如要表示當前路徑下的Data/Demo.xml,你可以這樣做:System.Format("{1}{0}{2}{0}{3}",System.IO.Path.Separate,System.AppDomain.CurrentDomain.BaseDirectory,Data,"Demo.xml")。有時,這仍然會帶來爭議,System.IO.Path下有很多常量很有用。第三種辦法最簡單,只要設定設定IO_MAP=ALL環境變數(針對Linux平臺),Mono執行時根據這個變數決定是否要做跨平臺眏射,必要的時候,Mono會自己將"\"替換成"/"。但是,一旦你使用了絕對路徑或者路徑中包含碟符,那麼通常,程式仍是不可移植的。解決檔案系統不相容的幾個法寶:使用相對路徑、使用執行時偵測路徑、使用Path.Combine方法、使用路徑常量(System.IO.Path下)、以及終極法寶IO_MAP環境變數。

    場景二,換行符差異,Unix族使用"\n"作為換行符,windows使用"\r\n"作為換行符。說道這裡,可能有朋友不同意,因為在Windows下,我們似乎從來也不使用"\r\n",事實是Windows在內部使用"\r\n",但是Windows同意"\n"語義,Windows期待我們使用"\r\n"至少記事本程式是這樣的。在必要時候,Windows會自己默默的轉換,這主要發生在RichTextBox控制元件相關的應用。因為換行符導致的任何問題,你都只需要寫字板開啟然後儲存,問題就OK了。在處理換行符的問題上,記事本和寫字板有很大的不同,寫字板程式識別 回車符(ASCII=13)、換行符(ASCII=10)以及標準的"\r\n"(回車符合換行符並舉),更有趣的是,如果是前兩種情況,在儲存的時候,系統會自動將單字元"\r"或者"\n"轉化為"\r\n"。但是,對於記事本而言,記事本既不識別"\r"也不識別"\n",她只識別標準的"\r\n",這不能說明記事本不好,實際上正好相反,記事本程式被設計成能夠有效的自動甄別內容編碼型別的文字處理軟體,因此不管是ASCII、GB2312還是UTF8,他都能準確的認出來,但是在寫字板中卻常常出現亂碼,有時記事本自作聰明的做法也讓人很無奈,特別是記事本程式有時會在檔案的第一個位元組處加上特殊標記,這可是苦壞了一些命令列程式,主要是不使用Windows API存取的軟體(依賴Dos介面的軟體),Javac有時也會受到它的影響。這是一個說明編碼問題有時很棘手的例子,我設計了一個簡單程式來表現記事本和寫字板之間的不同:

using System;
susing System.IO;
namespace ConsoleHelper
{
    class Program
    {
        static void Main(string[] args)
        {
            using(FileStream demo=new FileStream("OK.txt",FileMode.Create)){
                for (int i = 0; i < 100; ++i)
                {
                    demo.WriteByte(Convert.ToByte('A'));
                    demo.WriteByte(10);//10 is Return's Ascii code ,13 is NewLine's Ascii code
                    demo.WriteByte(Convert.ToByte('B'));
                }
            }
        }
    }
}
編譯程式,執行後 用記事本瀏覽->用寫字板瀏覽->不修改儲存->用記事本瀏覽

實驗時先用10做一遍,然後換成13在再做一遍,你會發現很有趣。這是記事本和寫字板的一個故事,還有很多,基本上都是由於編碼問題或者程式善意卻錯誤的推斷導致的。

有些說遠了,轉回正題,對於跨平臺程式碼的要求很簡單:用軟編碼而不是硬編碼,不要自己猜測換行符是"\r","\n"或者"\r\n",用System.Environment.NewLine常量代替即可。

  一點知識,希望能共同分享。