自己一直有想法要做一個(gè)在線編輯,并且保存文件到本地的一個(gè)文本編輯器,而且當(dāng)時(shí)還很有想法,想做一個(gè)像EditPlus或者Sepy AS Editor那樣的東西......不過.....對(duì)我來說太有難度了.要實(shí)現(xiàn)代碼提示和高亮顯示,對(duì)正則表達(dá)式一定要非常熟練和精通,我目前還沒有達(dá)到這個(gè)境界.
不過,有一個(gè)技術(shù)點(diǎn),就是把在線編輯的文本保存到本地,我就一早想到怎么做了.今天在論壇看到此問題 http://bbs.blueidea.com/thread-2831986-1-1.html 再考慮到自己這輩子也許都寫不出那個(gè)EditPlus來,終于忍不住做了一個(gè)純文本的發(fā)上來給大家看下. http://www.asv5.cn/hbro/documents/savefile/savefile.html 相信應(yīng)該有不少人一看到就知道怎么實(shí)現(xiàn)了吧,不過我感覺當(dāng)中有少部分人可能以前想不到用此辦法來實(shí)現(xiàn)保存到本地,或者因?yàn)槟莻(gè)框而放棄此做法.
在一般情況下,網(wǎng)頁上的Flash是不能對(duì)客戶端的文件進(jìn)行操作的,包括讀取和寫入都不允許,即使借助于JS,也一樣會(huì)因?yàn)闉g覽器的安全設(shè)置而被禁止. Flash 8的誕生貌似可以讓想實(shí)現(xiàn)本地讀寫的朋友們絕處逢生,因?yàn)榭梢詮腇ileReference類里打開本地文件瀏覽對(duì)話框,第一感覺就是Flash可以對(duì)本地文件進(jìn)行操作了!! 可惜的是,這個(gè)框純?yōu)樯蟼鞫O(shè),不過相當(dāng)于一個(gè)網(wǎng)頁的文件域而已.甚至連文件路徑都不能為FlashPlayer所獲取.更不用談直接操作了.盡管可以用JS來獲得文件路徑,Flash也無法獲得文件里面的數(shù)據(jù). 盡管如此,Flash 8也可以做出一個(gè)本地圖片瀏覽器,其途徑是通過瀏覽文件,上傳到服務(wù)器后,再重新傳輸?shù)奖镜剡M(jìn)行瀏覽.這個(gè)在Flash 8的安裝目錄下有官方的范例. 這個(gè)本地圖片瀏覽器的過程是可逆的,就是說,本來在Flash里的圖片,可以提交到服務(wù)器端,生成圖片文件,再通過FileReference類下載到本地.
我這次所制作的文本編輯器的運(yùn)行過程同樣是官方圖片瀏覽器的逆過程.既然Flash里的文本無法直接保存到本地(SharedObject不算),我們也可以通過提交數(shù)據(jù)到服務(wù)器端,生成文件,再下載. 所以,整個(gè)過程就是: 輸入文本->提交->服務(wù)器端保存文件->下載服務(wù)器端文件到本地 這么看起來,似乎已經(jīng)繞過了安全防線而實(shí)現(xiàn)所需的操作,不過,Flash還是把關(guān)得很嚴(yán)滴,不可以設(shè)置默認(rèn)的下載位置,而且下載前必須顯示系統(tǒng)對(duì)話框.
因?yàn)檎搲馁N是在AS3版塊提問的,所以文件也是AS3的,我也將會(huì)用AS3寫這個(gè)教程.不過,像這種應(yīng)用,用AS1寫也綽綽有余啦,加上本人比較懶,這次AS就寫時(shí)間軸上算了.
講完大致思路以后,就可以給出做法.
1 新建一個(gè)flash文檔(AS3.0),然后打開組件面板,往舞臺(tái)拖入一個(gè)TextArea組件和Button組件,實(shí)例名分別為input_txt和submit_btn.
2 然后就可以寫時(shí)間軸代碼了(就不分塊來寫了,大家看注釋就好).
//這里導(dǎo)入所需的類(其實(shí)如果在時(shí)間軸上寫,有很多是可以省掉的) //既然要用到下載,這當(dāng)然必不可少啦 import flash.net.FileReference; //數(shù)據(jù)通過URLLoader和URLRequest提交 import flash.net.URLLoader; import flash.net.URLRequest; //這個(gè)拿來寫Post方法,用這個(gè)類導(dǎo)入常數(shù) import flash.net.URLRequestMethod; //本來用String來提交數(shù)據(jù)就可以的了,但是感覺用了這個(gè)東西,代碼看上去有水平點(diǎn),呵呵. import flash.net.URLVariables; //都怪那個(gè)組件字體,默認(rèn)是10號(hào)字,非要我用樣式來重新設(shè)置一下,否則中文會(huì)看不清楚 import flash.text.TextFormat; //事件太多了,懶得再一個(gè)個(gè)地去添加 import flash.events.*; //跟下面一句有關(guān)系啦(為防止亂碼而設(shè)的了) import flash.system.System; System.useCodePage=true; //這里給按鈕和文本設(shè)置字體樣式,當(dāng)然也可以用global全局設(shè)置,結(jié)果顯示12號(hào)字 var tf:TextFormat=new TextFormat(); tf.size=12; input_txt.setStyle("textFormat",tf); submit_btn.setStyle("textFormat",tf); //點(diǎn)擊提交(保存)按鈕后,響應(yīng)一個(gè)函數(shù) submit_btn.addEventListener(MouseEvent.CLICK,clickHandler); //點(diǎn)擊按鈕后調(diào)用 function clickHandler(event:MouseEvent):void { //該函數(shù)是提交數(shù)據(jù)的核心函數(shù)(說的好像很高深,其實(shí)比較簡(jiǎn)單,看下去就知道了) submitData(); //這是測(cè)試的時(shí)候突然發(fā)現(xiàn),如果網(wǎng)速慢的話,不停點(diǎn)按鈕容易出錯(cuò) submit_btn.enabled=false; } function submitData():void { //創(chuàng)建URLLoader實(shí)例 var urlL:URLLoader=new URLLoader(); //創(chuàng)建URLRequest實(shí)例,意味著提交的數(shù)據(jù)傳輸?shù)絤akeFile.asp(之后我會(huì)再放一個(gè)PHP版本的),如果用PHP的話,讀者把這個(gè)文件名改改就好了. //這里解釋下makeFile.asp的作用(因?yàn)檫沒有發(fā)后臺(tái)程序,所以先講下功能,就是通過服務(wù)器的FSO對(duì)象,把提交的數(shù)據(jù)保存到一個(gè)文本文檔中,文件名為當(dāng)前時(shí)間加上一個(gè)隨機(jī)數(shù),這樣的文件名可以防止多人同時(shí)提交時(shí),由于文件名相同而導(dǎo)致沖突,如果覺得這樣還是容易重復(fù),可以在文件名里加上IP地址.這個(gè)文件名會(huì)傳回來給SWF,然后由FileReference獲得這個(gè)文件名并下載到本地 var urlR:URLRequest=new URLRequest("makeFile.asp"); //考慮到用戶可能會(huì)輸入亂七八糟或者數(shù)量較多的字符,用get方法傳遞不太合適,所以用post urlR.method=URLRequestMethod.POST; //之前說了,使用URLVariables只是為了看上去代碼有水平點(diǎn),可以用String來傳遞數(shù)據(jù). var urlV:URLVariables=new URLVariables(); //提交一個(gè)變量saveData到后臺(tái),值就是用戶輸入的文本 urlV.saveData=input_txt.text; //讓URLRequest要傳遞的數(shù)據(jù)和URLVariables關(guān)聯(lián)上 urlR.data=urlV; //提交數(shù)據(jù),發(fā)送請(qǐng)求 urlL.load(urlR); //監(jiān)聽完成事件,進(jìn)行后續(xù)操作 urlL.addEventListener(Event.COMPLETE,completeHandler); } //下面是FileReference var fileR:FileReference=new FileReference(); //這堆事件是幫助文件說一定要定義的,如果使用download方法的話,那就聽下Adobe的話,都定義下吧. fileR.addEventListener(IOErrorEvent.IO_ERROR,errHandler); fileR.addEventListener(Event.CANCEL,operateHandler); fileR.addEventListener(Event.OPEN,operateHandler); fileR.addEventListener(ProgressEvent.PROGRESS,operateHandler); fileR.addEventListener(Event.COMPLETE,operateHandler); fileR.addEventListener(Event.Select,operateHandler); fileR.addEventListener(SecurityErrorEvent.SECURITY_ERROR,operateHandler); fileR.addEventListener(HTTPStatusEvent.HTTP_STATUS,operateHandler); //這個(gè)變量用于存儲(chǔ)遠(yuǎn)程保存的文本文件的地址 var fileURL:String; //數(shù)據(jù)提交完成以后響應(yīng) function completeHandler(event:Event):void { //文件路徑由服務(wù)器端傳過來,至于如果傳的,等下看后臺(tái)文件. fileURL=event.target.data //獲得文件路徑以后,下載到本地,默認(rèn)的文件名是myText.txt,當(dāng)然,這個(gè)你可以改,或者就用遠(yuǎn)端文件的名稱 fileR.download(new URLRequest(fileURL),"myText.txt"); } //fileReference發(fā)生錯(cuò)誤(IOError)時(shí)調(diào)度 function errHandler(event:*):void { trace("error"); } //這個(gè)函數(shù)用于處理那一堆被迫定義的事件 function operateHandler(event:*):void { switch(event.type){ case "complete": //這里再一次做URLLoader,目的何在?其實(shí)就是把下載完的文件從服務(wù)器端刪除,以釋放服務(wù)器的空間,但是我們不能在前面的ASP里刪除,必須要等到現(xiàn)在下載完成了才可以. var urlL:URLLoader=new URLLoader(); //deleteFile.asp的作用:刪除之前保存在服務(wù)器上的文本文檔 var urlR:URLRequest=new URLRequest("deleteFile.asp?fileURL="+fileURL); urlL.load(urlR); //這個(gè)純粹形式 urlL.addEventListener(Event.COMPLETE,deleteHandler); case "cancel": //因?yàn)樘峤坏臅r(shí)候屏蔽了提交按鈕,所以用戶點(diǎn)取消或者傳輸完成(其實(shí)有錯(cuò)誤也應(yīng)該寫在這里),都重新恢復(fù)提交按鈕的可用性 submit_btn.enabled=true; } } function deleteHandler(event:Event):void{ //就是比較形式地把這個(gè)函數(shù)寫一下 }
然后,發(fā)布一下SWF和HTML,再創(chuàng)建兩個(gè)ASP文件,放在跟HTML同一個(gè)目錄下
makeFile.asp
<% '本文件作用:接收用戶提交的文本,并將其保存為服務(wù)器上的一個(gè)文本文檔,之后把文件名參數(shù)傳回給Flash '創(chuàng)建FileSystemObject對(duì)象,用于管理文件 dim fso set fso=Server.createObject("Scripting.FileSystemObject") '初始化隨機(jī)函數(shù)器,這是VBScript的一個(gè)特點(diǎn)所導(dǎo)致的,VBScript運(yùn)行第一次,其隨機(jī)變量就會(huì)存儲(chǔ)起來,下一次運(yùn)行就會(huì)重新調(diào)用上一次的隨機(jī)結(jié)果,這一句randomize,初始化隨機(jī)函數(shù)器就禁止調(diào)用之前隨機(jī)的結(jié)果 randomize '定義一個(gè)隨機(jī)變量 dim randomNumber '隨機(jī)數(shù)字等于年+月+日+小時(shí)+分+秒+隨機(jī)變量(為什么不直接用now呢?因?yàn)閚ow含有文件名不允許的字符如":",所以,如果不想寫那么長(zhǎng)的話,可以用函數(shù)Replace或者Split去掉這些符號(hào). randomNumber=year(now)&month(now)&day(now)&hour(now)&minute(now)&second(now)&rnd*10 '定義文件名 dim fileName '文件名就是隨機(jī)數(shù),擴(kuò)展名為txt fileName=randomNumber&".txt" '這里我定義一個(gè)文件夾名,所對(duì)應(yīng)的文件夾用于存放這些臨時(shí)的文本文檔(不放外面,以免影響或者沖突). dim fdrName fdrName="txtFile" '假如文件夾不存在的話(fso.folderExists是判斷文件夾存在的函數(shù),文件夾存在返回true,否則返回false if not fso.folderExists(Server.mapPath(fdrName)) then '就創(chuàng)建這個(gè)文件夾 fso.createFolder Server.mapPath(fdrName) end if '在這個(gè)文件夾里創(chuàng)建一個(gè)文本文檔,并通過fil變量得到該文檔的引用,第二個(gè)參數(shù)true表示若無其事文件存在將會(huì)覆蓋 set fil=fso.createTextFile(Server.mapPath("txtFile/"&fileName),true) 'fil.write意思為往文件寫入用戶提交過來的文本. fil.write Request("saveData") '這里輸出文件夾名稱和文件名稱給Flash,以讓Flash執(zhí)行下一步操作:download,本文件完成任務(wù),結(jié)束. response.write fdrName&"/"&fileName %>
deletefile.asp
<% '該文件的作用:不是必需的,只是為了節(jié)省服務(wù)器空間而采取的一種措施 'Flash下載完文件以后,把遠(yuǎn)程的文件名傳到這一個(gè)ASP里,以讓該ASP刪除剛保存在服務(wù)器的文件 'fso對(duì)象的創(chuàng)建 dim fso set fso=Server.createObject("Scripting.FileSystemObject") '定義文件名,并將提交過來的文件路徑賦予該變量 dim fileName fileName=Request("fileURL") '在服務(wù)器上尋找該文件,如果存在的話 if fso.fileExists(Server.mapPath(fileName)) then '就將其刪除 fso.deleteFile Server.mapPath(fileName) end if %>
PHP版本的代碼(注釋加不加也差不多了,原理跟ASP的沒啥兩樣)
makeFile.php
<? //php的時(shí)間用time(),不含有文件名不允許的字符號(hào),所以不需要像ASP那樣來處理,另外,php也不需要初始化隨機(jī)數(shù)生成器,直接調(diào)用rand函數(shù)即可,rand(0,10000)表示隨機(jī)0~10000的數(shù). $randomNumber=time().rand(0,10000); //生成隨機(jī)文件名 $fileName=$randomNumber.".txt"; //定義存放文本文件的文件夾 $fdrName="txtFile"; if(!file_exists($fdrName)){ $success=mkdir($fdrName); } //這里打開隨機(jī)文件名,"x"表示以寫入的方式打開,并用$fp變量獲得對(duì)此文件流的引用 $fp=fopen(($fdrName."/".$fileName),"x"); //此處用fwrite方法將提交的數(shù)據(jù)寫入前面打開的文件流 $success=fwrite($fp,$_POST["saveData"]); //輸出保存在遠(yuǎn)端的文件路徑給回Flash端 echo $fdrName."/".$fileName; ?>
deleteFile.php
<? //文件下載完成后,把文件名重新傳回服務(wù)器端的deleteFile.php里處理 $fileName=$_GET["fileURL"]; //假如這個(gè)文件存在的話 if(file_exists($fileName)){ //刪除這個(gè)文件,以釋放服務(wù)器的空間 unlink($fileName); } ?>
經(jīng)典論壇討論: http://bbs.blueidea.com/thread-2832355-1-1.html
本文鏈接:http://www.95time.cn/tech/multimedia/2008/5424.asp
出處:藍(lán)色理想
責(zé)任編輯:bluehearts
◎進(jìn)入論壇RIA設(shè)計(jì)與應(yīng)用版塊參加討論
|