我正在使用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程序员,请随时指出我在这里犯的任何明显错误。
答案 0 :(得分:3)
您应该几乎总是使用window
,而不是使用$wnd
。有关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
中的内容是非空的可能是明智的,甚至可能在FileUpload
的{{1}}关闭时将其清空。
答案 1 :(得分:0)
据我所知,您在编写扩展程序时只能使用new File(name)
:https://developer.mozilla.org/en/Extensions/Using_the_DOM_File_API_in_chrome_code