簡體   English   中英

HTML5和Javascript:使用File API打開和讀取本地文件

[英]HTML5 and Javascript : Opening and Reading a Local File with File API

我正在使用Google Web Toolkit進行項目,並希望用戶選擇要在瀏覽器內的文本窗口中打開的文本文件。 這是幾乎可以工作的代碼:

 private DialogBox createUploadBox() {
     final DialogBox uploadBox = new DialogBox();
     VerticalPanel vpanel = new VerticalPanel();
     String title = "Select a .gms file to open:";
     final FileUpload upload = new FileUpload();
     uploadBox.setText(title);
     uploadBox.setWidget(vpanel);
     HorizontalPanel buttons = new HorizontalPanel();
     HorizontalPanel errorPane = new HorizontalPanel();
     Button openButton = new Button( "Open", new ClickHandler() {
        @Override
        public void onClick(ClickEvent event) {
            String filename = upload.getFilename();
            int len = filename.length();
            if (len < 5) {
                Window.alert("Please enter a valid filename.\n\tFormat: <filename>.gms");
            } else if (!filename.substring(len-4).toLowerCase().equals(".gms")) {
                Window.alert(filename.substring(len-4) + " is not valid.\n\tOnly files of type .gms are allowed.");
            } else {
                Window.alert(getFileText(filename));
            }
        }
        private native String getFileText(String filename) /*-{
            // Check for the various File API support.
            if (window.File && window.FileReader && window.FileList && window.Blob) {
                // Great success! All the File APIs are supported.
                var reader = new FileReader();
                var file = File(filename);
                str = reader.readAsText(file);
                return str;
            } else {
                alert('The File APIs are not fully supported in this browser.');
                return;
            }
        }-*/;
     });
     Button cancelButton = new Button( "Cancel", 
             new ClickHandler() {
        @Override
        public void onClick(ClickEvent event) {
            uploadBox.hide();               
        }
     });
     buttons.add(openButton);
     buttons.add(cancelButton);
     vpanel.add(upload);
     vpanel.add(buttons);
     vpanel.add(errorPane);
     uploadBox.setAnimationEnabled(true);
     uploadBox.setGlassEnabled(true);
     uploadBox.center();
     return uploadBox;
 }

每當我嘗試在我的程序中實際使用此函數時,我得到:

(NS_ERROR_DOM_SECURITY_ERR):安全性錯誤

我確信它是由以下方式提供的:

var file = new File(filename, null);

免責聲明:我不是一個Javascript程序員,請隨時指出我在這里犯的任何明顯錯誤。

你應該幾乎總是使用$wnd而不是使用window 有關JSNI的更多詳細信息,請參閱https://developers.google.com/web-toolkit/doc/latest/DevGuideCodingBasicsJSNI#writing

在使用Firebug或Chrome的Inspector之類的東西時添加debugger語句也是值得的。 這個語句會停止調試器中的JS代碼,好像你在那里放了一個斷點,允許你在Javascript中調試,一次踩一行來查看到底出了什么問題。

最后,您確定瀏覽器允許您正在閱讀的文件嗎? http://dev.w3.org/2006/webapi/FileAPI/#dfn-SecurityError ,可能發生該錯誤,因為瀏覽器未被允許訪問該文件。 您可以傳入用戶正在與之交互的<input type='file' /> ,而不是傳入String,並從中獲取他們選擇的文件。


更新(抱歉延遲,顯然我所做的早期更新被扔掉了,我帶了一點重寫它):

幾個壞假設正在原始代碼中。 我的大部分閱讀來自http://www.html5rocks.com/en/tutorials/file/dndfiles/ ,還有一些實驗。

  • 首先,你可以從<input type='file' />字段獲得一個真實的路徑,再加上
  • 您可以通過路徑從用戶文件系統中讀取任意文件,最后
  • FileReader API是同步的。

出於安全原因,大多數瀏覽器在讀取文件名時都沒有提供真實的路徑 - 在幾個瀏覽器中檢查從upload.getFilename()獲得的字符串,看看它給出了什么 - 不足以加載文件。 第二個問題也是一個安全問題 - 只需使用字符串來指定要讀取的文件就可以從文件系統中讀取,這樣做很少。

出於前兩個原因,您需要詢問input它正在處理的文件。 支持FileReader API的瀏覽器允許通過讀取input元素的files屬性來訪問它。 有兩種簡單的方法 - 在jsni中使用NativeElement.getEventTarget(),或者只使用FileUpload.getElement()。 請記住,默認情況下,此files屬性包含多個項目,因此在類似於您的情況下,只需讀取第0個元素即可。

private native void loadContents(NativeEvent evt) /*-{
    if ($wnd.File && $wnd.FileReader && $wnd.FileList && $wnd.Blob) {
        // Great success! All the File APIs are supported.
        var reader = new FileReader();
        reader.readAsText(evt.target.files[0]);
//...

要么

private native void loadContents(Element elt) /*-{
    if ($wnd.File && $wnd.FileReader && $wnd.FileList && $wnd.Blob) {
        // Great success! All the File APIs are supported.
        var reader = new FileReader();
        reader.readAsText(elt.files[0]);
//...

對於最后一篇文章, FileReader api是異步的 - 你不會立即得到文件的全部內容,但需要等到調用onloadend回調(再次,來自http://www.html5rocks.com/en / tutorials / file / dndfiles / )。 這些文件可能足夠大,您不希望應用程序在讀取時阻止,因此顯然規范將此視為默認值。

這就是為什么我最終創建一個新的void loadContents方法,而不是將代碼保存在onClick方法中 - 當字段的ChangeEvent關閉時調用此方法,開始讀取文件,盡管這可以用其他方式編寫。

// fields to hold current state
private String fileName;
private String contents;
public void setContents(String contents) {
  this.contents = contents;
}

// helper method to read contents asynchronously 
private native void loadContents(NativeEvent evt) /*-{;
    if ($wnd.File && $wnd.FileReader && $wnd.FileList && $wnd.Blob) {
        var that = this;
        // Great success! All the File APIs are supported.
        var reader = new FileReader();
        reader.readAsText(evt.target.files[0]);
        reader.onloadend = function(event) {
            that.@com.sencha.gxt.examples.test.client.Test::setContents(Ljava/lang/String;)(event.target.result);
        };
    } else {
        $wnd.alert('The File APIs are not fully supported in this browser.');
    }
}-*/;

// original createUploadBox
private DialogBox createUploadBox() {
  final DialogBox uploadBox = new DialogBox();
  VerticalPanel vpanel = new VerticalPanel();
  String title = "Select a .gms file to open:";
  final FileUpload upload = new FileUpload();
  upload.addChangeHandler(new ChangeHandler() {
    @Override
    public void onChange(ChangeEvent event) {
      loadContents(event.getNativeEvent());
      fileName = upload.getFilename();
    }
  });
  // continue setup

然后,“確定”按鈕從字段中讀取。 ClickHandler檢查內容是非空的可能是明智的,甚至可能在FileUploadChangeEvent關閉時將其ClickHandler

據我所知,在編寫擴展時只能使用new File(name)https//developer.mozilla.org/en/Extensions/Using_the_DOM_File_API_in_chrome_code

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM