FileReference路徑擷取問題

來源:互聯網
上載者:User
 轉入正題。
其實這個問題,我一直都忽略了。我是從Flash MX時代走過來的人,MX2004出來後,AS就沒有再去認真地學下去,直到現在,Player7後的很多新功能我幾乎都沒有用過,像Tween類,filters類等等。
FileReference類其實也有很長一段時間沒引起我的興趣,但是,看了Flash 8內建的Sample以後,發覺這東東蠻有用的,可以選擇本地圖片,然後顯示在Flash裡頭。
不過,它的顯示是通過上傳,然後再下載來實現的,覺得很麻煩,看個本地圖片也要經過網路(不過當初沒有怪它,大概是要示範FileReference類的upload吧),決定把它改裝一下,做個本地的圖片瀏覽器。Flash 8能支援jpg,gif,png三類圖片,能改出來覺得用途還是有滴。
然而,一切都讓我失望了,搞了大半天,都不能把圖片直接讀出來,就是因為FileReference類無法擷取檔案的路徑,只能得到檔案名稱,想用loadMovie或者mcLoader類通過圖片路徑讀取相應圖片,還是沒辦法。可是,感覺只是差一點點啊。
雖然協助檔案沒有提到如何擷取檔案路徑,但是我仍不死心,總感覺是有的,於是,我寫了下面的代碼測試:
import flash.net.FileReference;
var fr:FileReference = new FileReference();
fr.browse();
var listener:Object=new Object();
fr.addListener(listener)
listener.onSelect = function(file:FileReference) {
       for (var i in file) {
              trace(i+":"+file[i]);
       }
};
選好了一個檔案以後,輸出的結果
_listeners:[object Object]
creator:undefined
creationDate:Thu Feb 15 20:58:03 GMT+0800 2007
modificationDate:Thu Feb 15 20:58:04 GMT+0800 2007
size:3753620
type:.mp3
name:2007127171248.mp3
暈了,用for來枚舉都得不到路徑,看來這次是徹底絕望了。限制安全性也不用限制成這樣吧,Macromedia?
而且,這也將意味著,代碼中的file對象不能自己手動構造,必須通過FileReference的browse方法來構造。因為,僅通過輸出的結果,是不可能得到你瀏覽的檔案的,就是因為沒了路徑。
通過各大搜尋引擎去尋找如何擷取檔案路徑的答案,都是只有問的,沒有回答的。
因為問這一問題的人不多,所以,這事情早擱淺了,一直沒管它。
後來,朱高兄想做個可以播放本地音樂的播放器,是因為他看中了Flash 8的FileReference類。但是,當我道出了FileReference類不能獲得檔案路徑的真相以後,他的這一想法就像我當初做圖片瀏覽器的想法那樣,給打消了。

最近又有人問到了此問題,看來,也是時候要研究下了。
http://bbs.blueidea.com/thread-2721771-1-1.html

要解決FileReference中的這一問題,至少目前來說,靠Flash是沒有用的了,既然網頁裡頭的檔案域有完整路徑,我們為何不去應用一下呢?

所以,解決此問題,用到的,主要還是Flash與js的通訊了,之前的教程都是用fscommand來弄,這次嘗試用ExternalInterface來實現,所以,接下來會先介紹ExternalInterface類的用法(這個相信大多數人會了,說簡單些),然後就是檔案域中的一個相當於FileReference中browse的一個方法,以及類似於FileReference中onSelect的一個事件。

示範地址:http://hbro.cincn.com/HBrO/course/fileField/fileField.html

進入執行個體講解之前,先介紹上面所說的幾點內容:
1 ExternalInterface類的使用
這裡均以網頁裡Flash與js的通訊為例。首先,在Flash裡頭,ExternalInterface類是在Flash.net包裡頭,一般為方便以後調用該類時不輸入此路徑,as裡會先添加
import flash.net.FileReference
添加了這一句以後,在使用該類時,就不需要重複輸入flash.net了。

接著,要在Flash裡頭調用js的函數,可以使用call方法
call(methodName:String, [parameter1:Object])
為方便示範,我使用js一個內建的alert方法來進行測試。
建立個Flash文檔,儲存為ExternalInterface.fla,然後輸入下面的代碼:
import flash.net.FileReference;
ExternalInterface.call("alert",1);
發布一下,然後在IIS下測試你剛產生的網頁,就會看到有個1的對話方塊出來了。就是說,Flash調用js的函數這一步已經實現。
然後,就是到js控制Flash了。js可以調用Flash裡頭的函數,這裡,ExternalInterface類也起到重要的作用。
要使Flash裡頭某個函數可以被js調用,需要用ExternalInterface對其進行註冊:
addCallback(methodName:String, instance:Object, method:Function) : Boolean
其中,methodName是給js調用的名稱,instance是as函數所在的執行個體,method則是as裡頭函數的名稱
返回一個布爾值,指示調用是否成功,不過下面的示範把這個傳回值忽略。
在ExternalInterFace.fla裡頭,追加代碼:
ExternalInterface.addCallback("gotoGoogle",this,goto_Google);
function goto_Google(){
  getURL("http://www.google.com","_blank");
}
然後,用Ctrl+Enter產生下Flash影片。
在ExternalInterFace.html裡頭,找到</body>,在此前面添加代碼:
<a href="#" onclick="ExternalInterface.gotoGoogle">gotoGoogle</a>
儲存下html,運行,點上面的gotoGoogle按鈕,將開啟google的首頁。也就是說,as裡頭的goto_Google函數已經通過js被調用起來了。

 

2 網頁檔案域中檔案路徑的擷取
既然要使用檔案域了,那麼,檔案域的路徑如何擷取就必須解決。使用的就是檔案域的value屬性,這跟文本域的擷取方法一樣。但是,這個屬性貌似只好讀取,不好設定,設定的話,通過file.value="xxx",檔案域裡的文字框似乎沒有跟著變化。可能有一個設定值的函數吧,但是還沒找出來。
測試的代碼比較簡單
<input type="file" id="a" /><br />
<input type="button" onclick="alert(a.value)" value='查看'>
a為檔案域的id,通過一個按鈕點擊以後,檔案域的路徑就通過對話方塊顯示出來。

3 替代“瀏覽”按鈕的方法
因為要在Flash裡頭調用,所以,使用者使用的時候,是不點檔案域後面的瀏覽按鈕的。那麼,如何代替這一按鈕,讓我們可以自行開啟本地瀏覽視窗,並且對檔案域的值進行設定呢?
為尋找這個問題的答案,我可以說是幾經艱辛,雖然本帖的問題是昨晚解決的,但是FileReference類,檔案域等問題就困擾了我很久。
在介紹網頁製作的書裡頭,說到表單元素的插入時,很多都對各種表單元素如何設定值,如何設定屬性都講得很詳細。Dreamweaver中,屬性面板的任何一項都介紹得相當清楚。像文本域,初始值,最大字元數等等,都會講得一清二楚。如果書中包含js的內容,那麼,如何用js對文本域進行設定也會有相應的講解。
然而,儘管檔案域也不能躲開作者的筆下,但是,檔案域的介紹總是幾句帶過,講完如何插入就完事了。如何進行設定也很少進行深入講解,同樣,作者也會想方設法在js部分省略掉檔案域的內容。有的通過全面的調查表單一實例,讓讀者感到全面,而不再追究如何使用檔案域,有的則在對某一元素的設定進行講解,而叫讀者舉一反三,於是,由於文本域使用頻率不高,讀者看完書後,也就不會有問題反饋給作者。但實際上,他們對文本域的一些用法還是不那麼瞭解。
但是,造成這一問題也不能完全歸因於作者,畢竟檔案域具有它的特殊性。
表單最初是用於給使用者提交資料給後台用的。在不包含檔案域的表單中,提交的資料基本上都是ASCII的字串,或者說,提交的資料在記事本中開啟不會有亂碼。後台在擷取這些資料的時候,通常使用Request("xxx")就可以成功擷取並進行處理了。但是,檔案域所提交出去的資料則不一樣,它包含了檔案域中相應檔案的每個位元組,可能包含位元據,不能為記事本所識別,用的時候,單靠Request不能成事,還需要用到上傳組件,ASP的話,有的會使用無組件上傳類。雖然處理位元據很多時候用的是Request.BinaryRead,Request.BinaryWrite,但相比起不帶檔案域的表單來說,要複雜些。在網頁程式的書或教程裡頭,提交含檔案域的表單要獨立出來講解,說明檔案域在幕後處理方面具有特殊性。

隨著js用戶端指令碼的發展,以及伺服器負擔日益加重的趨勢,表單的資料若都直接傳輸,伺服器將更容易崩潰。因此,表單的內容很多時候都會先在前台處理一下,以減少不必要的傳輸。在一些簡單應用中,甚至所有表單資料都不提交到後台,一切皆為前台服務。在這情況下,檔案域的應用也不廣泛,如果只考慮前台,檔案域不過比文本域多了個瀏覽功能,可以獲得一些特定的字串,而獲得這些字串的目的,很多時候只是要讀取或寫入檔案。然而,在網頁前台進行檔案的讀寫操作,一般都會給瀏覽器的安全性禁止,於是,檔案域也就失去了它特有的價值,跟文本域沒什麼區別了。
所以,檔案域的使用會非常容易給人忽略,特別是前台指令碼方面。找這個“瀏覽”方法,也就很讓我頭痛。嘗試使用過for in枚舉,但可惜,只能得到屬性和事件,沒有函數。所以,使用各大搜尋引擎,用不同的關鍵字搜尋,都無法找到答案。
經過一小時的尋找和嘗試,我居然在經典論壇前台區600多天前一個討論css的帖裡頭一個不是很起眼的回答中找到了問題的答案。
http://bbs.blueidea.com/thread-1803020-1-1.html
3樓的marvellous提供了一個通過隱藏檔案域,添加其它表單控制項來實現CSS的方法。
<input type=file name=j style="display: none;" onchange="ye.value=value"><input name=ye style="color: green;border: 1px solid green"> <input type=button value="File" onclick=j.click() style="border: 1px solid green">
雖然討論的是CSS,但是由於他通過外部控制了檔案域,所以達到了我要的效果。在此,非常感謝這位版主提供的答案。
在按下一個普通按鈕的時候,調用j.click()方法,j又是檔案域的id,明顯,click就是檔案域的瀏覽函數啦。
有了他的這幾句代碼,下面的一切就很好解決了。

4 檔案域裡相當於FileReference類中onSelect的事件
有了上面的代碼,這個事件也就不難發現了。因為顯示的文字框也不是檔案域本身所帶的文字框,而是自己另外建立的一個文本域,在測試他代碼的過程中,點了自建立的按鈕以後,選了檔案,檔案路徑也可以顯示在自己做的文本域中,文本域的id是ye,那麼,讓ye.value=value的事件onchange,自然就是選了檔案以後所響應的事件啦。

有了它這一模型以後,我們發現,檔案域中我們需要的內容都可以擷取了,只要通過ExternalInterface類,把這些內容傳給as,就可以實現Flash對檔案路徑的擷取了。

具體步驟如下:
1 在Flash裡建立一動態文本或輸入文本,用來顯示路徑,再建立一個瀏覽按鈕。
2 在網頁中建立一個隱藏的檔案域,給js調用。
3 點Flash的瀏覽按鈕後,通過ExternalInterface.call調用js的一個函數,該函數包含了網頁檔案域的click方法。
4 開啟瀏覽本地檔案的對話方塊,選擇了檔案後,響應onchange事件,調用flash裡頭的一個函數,該函數在Flash裡頭包含了設定動態文字框常值內容的語句。

下面跟據這些步驟,建立這個Flash版的檔案域
1 建立一個Flash文檔,儲存為fileField.fla。
然後,在情境裡頭放一個動態文字框或輸入文字框,執行個體名為fileName,再放一個按鈕,執行個體名為browse_btn。

2 選擇“檔案”-“發布設定”,點下發布按鈕以後,把格式選項卡中的html前的勾去掉(現在不用fscommand了,所以不用像以前那樣做跟蹤)。
然後,在fileField.fla所在目錄下,用記事本開啟fileField.html,找到</body>,在前面輸入如下代碼:
<input type="File" id="myFile" onchange="giveValueToFlash(myFile.value)" style="visibility:hidden">
這裡有個giveValueToFlash,就是說,檔案域選了檔案以後,調用此函數,這一函數在後面定義,將會把檔案域的value屬性傳給Flash。

3 回到fileField.fla,在幀裡頭輸入代碼:
import flash.external.ExternalInterface;//載入ExternalInterface類

browse_btn.onRelease = function() {
       ExternalInterface.call("browse");//讓Flash調用js的browse函數,這函數等下定義,用於開啟瀏覽對話方塊
};

轉到fileField.html,在</body>前面輸入代碼:
<script language="javascript">
function browse(){
  myFile.click();//Flash所調用的browse函數就可以因此而開啟瀏覽對話方塊了
}
</script>

4 在function browse(){}後面,追加onchange事件所響應的giveValueToFlash函數:
function giveValueToFlash(val){
  fileField.setValue(val);//fileField為Flash產生的HTML的swf預設id,這句話就調用fileField的setValue方法,但是,這不是Flash內建的,需要用addCallback來註冊。
}

轉回fileField.fla,追加代碼:
ExternalInterface.addCallback("setValue",this,setTextValue);//讓setValue成為Flash的一個方法,setTextValue的意思是:當在網頁或者其它容器裡頭調用Flash的setValue方法時,Flash中的setTextValue將被調用。
//所以下面這個函數就是給外部調用的
function setTextValue(val:String):Void {
       fileName.text = val;//讓動態文本或者輸入文本的值等於檔案域的value屬性
}

 

走到這一步,檔案路徑已經可以為Flash所擷取,但是,可以看到,FileReference類完全沒有參與其中,所以,它裡頭的一切方法,屬性,事件你都沒辦法用上。所以,這一切如果可以封裝成一個類就完美了。可惜的是,它要和js代碼互動,js存在於網頁中,不容易放到AS類裡頭,但是,看了abc12hjc的保持html乾淨的辦法以後,也可以嘗試用getURL("javascript:xxx")的辦法,把一部分的js寫到類裡頭。加上ExternalInterface類也大量減少了網頁的代碼,寫成類還是可以嘗試的。
如果你要用這一個檔案域來上傳檔案的話,就要給回html去提交資料了。但是,html提交資料需要頁面跳轉,那麼,如何?像Flash一樣的無跳轉頁面上傳?mirycat已經提到了,就是用隱藏的iframe上傳。具體的我沒有在示範地址裡實現,不過我會繼續補充的。
本來想繼續把上傳那塊教程寫出來的,沒想到這麼快就一堆不能在FF下啟動並執行回複.
哭,給這個FF玩死了.居然連檔案域的click方法都不可用.還有什麼設定Flash參數的,還是今天才知道怎麼弄才能在FF下有效.我倒,FF跟IE的差別太多了,真是頭痛.
這回總算給我搞了個可以在FF下啟動並執行了,但是問題還是有的,大家儘管踩吧.反正我就發現不少了.
http://hbro.cincn.com/HBrO/course/fileField(FF)/fileField.html

經典論壇詳細討論地址:

http://bbs.blueidea.com/thread-2721826-1-1.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.