2020年8月21日 星期五

jQuery UI SPA 應用程式 (四) : 檔案處理函式庫

今天繼續幹活, 目標是整理很久之前寫好的 Javascript 函式庫, 我將其中伺服端部分的程式碼刪除以便用在本次專案上. 由於資安限制不能安裝與使用資料庫, 只好用檔案處理方式來協助作業自動化, 因此檔案處理函式庫在整個專案中扮演關鍵角色.

刪減後的函式庫檔案 file.js 如下所示, 此函式庫使用微軟 ActiveX 技術, 因此只能在 IE 瀏覽器上運作 : 


1. 匯入函數 :   

此函數用來讀取 js 程式 (函式) 並執行其中的頂層程式碼.

/*-----------------------------------------------------------------------------
include(filename)
功能 : 
  此函數用來匯入其他外部 Javascript 檔. 僅限於 Client 端之 WSH 應用中.
參數 :                                   
  filename  : 外部 Javascript 檔名 (字串)   
傳回值 :
  無/null
範例 : 
  include("parse.js");    
-----------------------------------------------------------------------------*/
function include(filename) {
  try {
       var FSO=new ActiveXObject ("Scripting.FileSystemObject");
       var TXO=FSO.openTextFile(filename,1);
       var fileData=TXO.readAll();
       eval(fileData);  //執行 JS 檔內容
       TXO.Close();
       TXO = null;
       FSO = null;
      }
  catch (e) {return e.description;}
  }


2. 讀取文字檔案 :     

函式 read_file() 用來讀取文字檔, 傳回整個檔案內容 (字串); read_lines() 則逐行讀取文字檔, 傳回值為檔案中各行依序組成之陣列.

/*-----------------------------------------------------------------------------
read_file(filename)
功能 : 
  此函數用來讀取外部文字檔, 結果以字串傳回.
參數 :                                   
  filename  : 文字檔檔名 (含路徑)   
傳回值 :
  成功傳回檔案內容字串, 失敗傳回原因字串
範例 : 
  var fileData=read_file("test.log");    
-----------------------------------------------------------------------------*/
function read_file(filename) {
  try {
      var FSO=new ActiveXObject("Scripting.FileSystemObject");
      var TXO=FSO.openTextFile(filename,1,false);
      var fileData=TXO.readAll();
      TXO.Close();
      TXO=null;
      FSO=null;
      return fileData;
      }
  catch (e) {return e.description;}
  }
/*-----------------------------------------------------------------------------
read_lines(filename)
功能 : 
  此函數用來讀取外部文字檔, 並以分行符號拆分每列後儲存在陣列中傳回.
參數 :                                   
  filename  : 文字檔檔名 (含路徑)   
傳回值 :
  成功傳回陣列, 失敗傳回原因
範例 : 
  var array_lines=read_lines("test.log");    
-----------------------------------------------------------------------------*/
function read_lines(filename) {
  try {
      var FSO=new ActiveXObject("Scripting.FileSystemObject");
      var TXO=FSO.openTextFile(filename,1,false);
      var array_lines=new Array();
      while (!TXO.atEndOfStream) {
            array_lines.push(TXO.ReadLine());  //讀取每行放入陣列中
            }
      TXO.Close();
      TXO=null;
      FSO=null;
      return array_lines;
      }
  catch (e) {return e.description;}
  }


3. 寫入文字檔 :  

函式 write_file() 將字串以覆蓋或新建方式寫入外部文字檔; append() 是將字串貼附到檔尾; 而prepend() 則是將字串貼附到檔頭. 

/*-----------------------------------------------------------------------------
write_file(filename,text)
功能 : 
  此函數用來將純文字寫入外部文字檔 (覆蓋或新建).
參數 :                                   
  filename  : 文字檔檔名 (含路徑)   
  text      : 檔案內容   
傳回值 :
  成功傳回 1, 失敗傳回原因
範例 : 
  var result=write_file("test.log", "This is a book");    
-----------------------------------------------------------------------------*/  
function write_file(filename,text) {
  try {
      var FSO=new ActiveXObject("Scripting.FileSystemObject");
      var TXO=FSO.openTextFile (filename,2,true); //2=寫入,true=新建
      TXO.Write(text); //寫入檔案
      TXO.Close();
      FSO=null;
      return 1;
      }
  catch(e) {return e.description;}
  }
/*-----------------------------------------------------------------------------
append(filename,text)
功能 : 
  此函數用來將純文字寫入外部文字檔後面(不存在就新建).
參數 :                                   
  filename  : 文字檔檔名 (含路徑)   
  text      : 檔案內容   
傳回值 :
  成功傳回 1, 失敗傳回原因字串
範例 : 
  var result=append("test.log", "This is a book");    
-----------------------------------------------------------------------------*/  
function append(filename,text) {
  try {
      var FSO=new ActiveXObject("Scripting.FileSystemObject");
      var TXO=FSO.openTextFile(filename,8,true); //8=附加,true=新建
      TXO.Write(text); //寫入檔案
      TXO.Close();
      FSO=null;
      return 1;    
      }
  catch(e) {return e.description;}
  }
/*-----------------------------------------------------------------------------
prepend(filename,text)
功能 : 
  此函數用來將純文字寫入外部文字檔前面(不存在就新建).
參數 :                                   
  filename  : 文字檔檔名 (含路徑)   
  text      : 檔案內容   
傳回值 :
  成功傳回 1, 失敗傳回原因字串
範例 : 
  var result=prepend("test.log", "This is a book");    
-----------------------------------------------------------------------------*/  
function prepend(filename,text) {
  var new_text=text + read_file(filename);  //串接
  return write_file(filename,new_text); 
  }


4. 刪除文字檔部分內容 : 

函式 remove_lines() 會刪除文字檔中指定之行數 (0 起始); remove_prelines() 用來刪除文字檔指定之前面幾行; 而 emove_lastlines() 則刪除文字檔指定之最後幾行. 

/*-----------------------------------------------------------------------------
remove_lines(filename,lines_array)
功能 : 
  此函數用來移除文字檔指定之行.
參數 :                                   
  filename     : 文字檔檔名 (含路徑)   
  lines_array  : 要移除之行數陣列 (0 起算)  
傳回值 :
  成功傳回 1, 失敗傳回原因字串
範例 : 
  var result=remove_lines("test.log", [0]);    
  var result=remove_lines("test.log", [2,4,6]);    
-----------------------------------------------------------------------------*/  
function remove_lines(filename,lines_array) {
  var lines_array=lines_array.sort();  //行號排序,以便取出要刪的最後一行行數
  var text=read_lines(filename);  //讀取檔案成陣列
  var break_point=lines_array[lines_array.length-1] + 1;  //斷點
  var pre=text.slice(0, break_point); //前半部 (要處理刪除作業)
  //剩下的後半部陣列不須處理刪除作業
  var left=text.slice(break_point); //選取斷點至陣列尾
  var tmp=new Array();
  var line_str=lines_array.join();  //把欲刪除行號組成字串
  for (var i = 0; i < pre.length; i++) {  //沒在刪除名單的放入 tmp 陣列
      if (line_str.indexOf(i.toString()) == -1 ) {tmp.push(pre[i]);} //不刪除
      else {continue;}  //有在刪除名單的不存入 tmp : 刪除
      }
  tmp=tmp.concat(left);  //串接刪除後的前半部與後半部串接
  return write_file(filename,tmp.join("\r\n")); 
  }
/*-----------------------------------------------------------------------------
remove_prelines(filename,numbers)
功能 : 
  此函數用來移除文字檔最前面指定之行數.
參數 :                                   
  filename  : 文字檔檔名 (含路徑)   
  numbers   : 移除之行數   
傳回值 :
  成功傳回 1, 失敗傳回原因字串
範例 : 
  var result=remove_prelines("test.log", 2);    
-----------------------------------------------------------------------------*/  
function remove_prelines(filename,numbers) {
  var lines=read_lines(filename);  //
  for (var i = 0; i < numbers; i++) {lines.shift();}
  return write_file(filename,lines.join("\r\n")); 
  }
/*-----------------------------------------------------------------------------
remove_lastlines(filename,numbers)
功能 : 
  此函數用來移除文字檔最後面指定之行數.
參數 :                                   
  filename  : 文字檔檔名 (含路徑)   
  numbers   : 移除之行數   
傳回值 :
  成功傳回 1, 失敗傳回原因字串
範例 : 
  var result=remove_lastlines("test.log", 2);    
-----------------------------------------------------------------------------*/  
function remove_lastlines(filename,numbers) {
  var lines=read_lines(filename);  //讀進檔案為陣列
  lines.reverse();  //陣列倒序
  for (var i = 0; i < numbers; i++) {lines.shift();}  //刪除前面幾列
  lines.reverse();  //陣列倒序回去
  return write_file(filename,lines.join("\r\n")); 
  }


5. 檔案目錄資訊 : 

函式 get_files() 會以陣列傳回指定目錄下之檔案列表; file_exist() 用來檢查指定之檔案是否存在 (存在傳回 1); delete_file() 用來刪除指定之檔案 (成功傳回 1), get_folder() 則傳回網頁檔所在之本機路徑. 

/*-----------------------------------------------------------------------------
get_files(folder)
功能 : 
  此函數用來取得指定目錄下的檔案列表, 以陣列傳回.
參數 :                                   
  folder  : 檔案路徑 (注意, 目錄需用兩個倒斜線分隔) 
傳回值 :
  陣列或失敗原因
範例 : 
  var files=get_files("my_doc");    
  var files=get_files("c:\\test\\my_doc");    
-----------------------------------------------------------------------------*/  
function get_files(folder) {
  try {
      var FSO=new ActiveXObject("Scripting.FileSystemObject");
      var folderObj=FSO.GetFolder(folder); 
      var enumObj=new Enumerator(folderObj.Files); 
      var filesArray=new Array();
      for (;!enumObj.atEnd();enumObj.moveNext()) {      
          filesArray.push(enumObj.item().Name);
          }
      folderObj=null;
      enumObj=null;
      FSO=null;
      return filesArray;   
      }
  catch(e) {return e.description;}
  }
/*-----------------------------------------------------------------------------
file_exist(file_name)
功能 : 
  此函數用來檢查檔案是否存在.
參數 :                                   
  file_name : 檔案名稱與路徑 (注意, 目錄需用兩個倒斜線分隔) 
傳回值 :
  成功傳回 1, 失敗傳回原因
範例 :    
  var result=file_exist("c:\\test\\my_doc.txt");    
-----------------------------------------------------------------------------*/  
function file_exist(file_name) {
  try {
      var FSO=new ActiveXObject("Scripting.FileSystemObject");
      if (FSO.FileExists(file_name)) {return 1;}
      else {return 0;}
      FSO=null;    
      }
  catch(e) {return e.description;}
  }
/*-----------------------------------------------------------------------------
delete_file(file_name)
功能 : 
  此函數用來刪除檔案.
參數 :                                   
  file_name : 檔案名稱與路徑 (注意, 目錄需用兩個倒斜線分隔) 
傳回值 :
  成功傳回 1, 失敗傳回原因
範例 :    
  var result=delete_file("c:\\test\\my_doc.txt");    
-----------------------------------------------------------------------------*/  
function delete_file(file_name) {
  try {
      var FSO=new ActiveXObject("Scripting.FileSystemObject");
      if (FSO.FileExists(file_name)) {FSO.DeleteFile(file_name);}
      FSO=null;
      return 1;
      }
  catch(e) {return e.description;}
  }
/*-----------------------------------------------------------------------------
get_folder()
功能 : 
  此函數會傳回網頁檔所在本機路徑, 例如 D:\\project\\pitch\\
參數 :  
  無
傳回值 : 字串 (雙倒斜線格式 D:\\project\\pitch\\)
-----------------------------------------------------------------------------*/
function get_folder() { //傳回目前網頁所在之目錄字串
  //取得目前網頁所在目錄,例如 /D:\project\pitch\pitch.htm
  var browser=window.navigator.appName;
  var b_version=window.navigator.appVersion;
  var version=b_version.split(";"); 
  var trim_Version=version[1].replace(/[ ]/g,""); 
  //取得目前網頁所在目錄,/D:/project/pitch/pitch.htm
  var sys_path=unescape(window.location.pathname);
  //去除檔名,從右邊開始找第一個右斜線 / 索引
  var pos=sys_path.lastIndexOf("\/"); 
  //須去除第一個右斜線,故從 1 開始直到右側第一個右斜線(含)
  var path=sys_path.substring(1,pos+1); 
  //工作目錄路徑演算結果例如 path=D:/project/pitch/
  //製作 FSO 物件運作所需之系統路徑字串 (由單一倒斜線轉成兩個倒斜線)
  var path_arr=path.split("\/"); //先拆成陣列
  var folder=path_arr.join("\\\\"); //再組合為字串 D:\\project\\pitch\\
  return folder;
  }

先在專案根目錄下新增一個 lib 資料夾, 將此 file.js 函式庫檔案存放於 /lib 下 :




完整的 files.js 參考 GitHub :

https://github.com/tony1966/test/blob/master/jqueryui-app/lib/file.js

下面逐一測試這些函數的用法. 



<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>jQuery UI Single Page Application</title>
  <script src="jquery/jquery.js"></script>
  <script src="jquery/jquery-ui.js"></script>
  <script src="jquery/datatables.js"></script>
  <script src="lib/file.js"></script>
  <link id="theme" href="jquery/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
  <link href="jquery/datatables.css" rel="stylesheet">
  <style>
    body {
      font-family: Arial, Helvetica, sans-serif;
      font-size:10px;
      }
  </style>
</head>
<body>
  <!-- 主題佈景選擇器 -->
  <select id="themes">
    <option value="base">base</option>
    <option value="black-tie">black-tie</option>
    <option value="blitzer">blitzer</option>
    <option value="cupertino">cupertino</option>
    <option value="dark-hive">dark-hive</option>
    <option value="dot-luv">dot-luv</option>
    <option value="eggplant">eggplant</option>
    <option value="excite-bike">excite-bike</option>
    <option value="flick">flick</option>
    <option value="hot-sneaks">hot-sneaks</option>
    <option value="humanity">humanity</option>
    <option value="le-frog">le-frog</option>
    <option value="mint-choc">mint-choc</option>
    <option value="overcast">overcast</option>
    <option value="pepper-grinder">pepper-grinder</option>
    <option value="redmond">redmond</option>
    <option value="smoothness">smoothness</option>
    <option value="south-street">south-street</option>
    <option value="start">start</option>
    <option value="sunny">sunny</option>
    <option value="swanky-purse">swanky-purse</option>
    <option value="trontastic">trontastic</option>
    <option value="ui-darkness">ui-darkness</option>
    <option value="ui-lightness">ui-lightness</option>
    <option value="vader">vader</option>
  </select>
  <script>
    $(function(){
      $("#themes").selectmenu();
      $("#themes").val("hot-sneaks");
      $("#themes").selectmenu("refresh");
      $('#themes').on('selectmenuchange', function() {
        var theme=$(this).val();
        var href="jquery/themes/" + theme + "/jquery-ui.min.css";
        $("#theme").attr("href", href);
        });
      });
  </script>
  <!-- 頁嵌面板 -->
  <div id="tabs">
    <ul>
      <li><a href="#tabs-1">tab1</a></li>
      <li><a href="#tabs-2">tab2</a></li>
      <li><a href="#tabs-3">tab3</a></li>
    </ul>
    <div id="tabs-1">
      <button id="read_file" class="ui-button ui-widget ui-corner-all">讀取檔案</button>
      <div id="out1" class="ui-state-highlight ui-corner-all" style="margin-top: 10px; padding: 5px;"></div>
      <script>
        $(function(){
          //監聽按鈕之 click 事件
          $("#read_file").click(function(e) {
            e.preventDefault();
            var folder=get_folder();     //取得此網頁的本機路徑
            var txt=read_file(folder + "hello-world.txt");      //讀取 .txt 檔
            var htm=read_file(folder + "hello-world.htm");   //讀取 .htm 檔
            $("#out1").html(folder + "<br>" + txt + "<br>" + htm);
            $("#out1").show();
            });
          });
      </script>
    </div>
    <div id="tabs-2">
    </div>
    <div id="tabs-3">
    </div>
  </div>
  <script>
    $(function(){
      $("#tabs" ).tabs();
      $("#out1").hide();
      }); 
  </script>
</body>
</html>

此網頁中的 tab1 頁籤中放置了一個按鈕與預設隱藏的 div 元素 (套用 jQuery UI 的 highlight 樣式類別), 當按下按鈕時會先呼叫 files.js 函式庫中的 get_folder() 函數來取得此網頁在本機中的路徑, 然後呼叫 read_file() 分別讀取專案根目錄下的 hello-world.txt 與 hello-world.htm 這兩個存文字檔案, hello-world.txt 內容為 :

Hello!
World! (text)

而 hello-world.htm 內容為 :

<b>Hello!</b>
<b>World! (html)</b>

將檔案路徑與讀取之檔案內容用跳行元素 br 串接後呼叫 html() 輸出到隱藏的 div 高亮度元件, 最後呼叫 show() 顯示此高亮度元素, 結果如下 :




注意, 由於使用了 Active X 技術, 此範例網頁只能在 IE 執行 (Edge 不支援), 且按下按鈕時會出現如下警告, 必須選 '是' 才會正常執行 :





參考 :

[Jquery]讓div能自由的show、hide


沒有留言 :