利用XPCOM技术实现Firefox跨平台文件操作JavaScript类
在我们工具条的设定选项模块和历史记录模块都需要操作本地文件以读取和写入配置及记录。但是firefox作为一个跨平台和有沙箱机制的浏览器,对于本地操作系统的文件操作不可能像普通的文件操作一样。必须实现一个安全的,跨平台的本地资源访问机制来解决这个问题。在firefox里面提供了XPCOM(Cross Platform Component Object Module)技术已解决这个问题。他类似与微软的COM,但是它们的实现不同。微软的COM组件是注册在系统注册表中的,而XPCOM组件是通过Mozilla自己的注册表注册的。这个信息存在于两个文件中:comreg.dat和xpti.dat。在comreg.dat中你会发现很多信息。XPCOM使我们可以在JavaScript中使用XPCOM组件,并且还可以在JavaScript中开发XPCOM组件。这样就向需要快速解决方案但又不想用C或者C++编写本地XPCOM组件的开发人员打开了创建XPCOM组件的大门。
我们的MTB_File类就使用JavaScript脚本来实现了跨平台的本地文件访问XPCOM组件类。他提供了沙箱模式下对firefox当前运行的Profile文件夹下文件和文件夹的读、写、删、改操作,以及文件和文件夹的大小,类型,是否可执行等属性的获取。
根据MTB_File类所需要实现的功能,我们设计得到一下的MTB_File类图:
根据类图的要求,我们使用JavaScript来实现该类图,根据业务流程,我们逐一讲解该类的各个关键函数:
首先我们必须获取当前Profile下的我们工具栏配置文件和历史文件的存放的目录。这个目录在firefox的当前用户的Home文件夹或者My Document文件夹下的Mozilla/firefox文件夹下面。按照默认规定,我们的工具栏为了和其他的firefox插件区分,所有的配置和历史记录文件都存放在当前Profile文件夹下的FulinToolbarData文件夹下面。为了方便我们获取这个文件夹,我们实现了MTB_getLocalFileDir函数:
1: function MTB_getLocalFileDir()
2:
3: {
4:
5: //获取Mozilla提供的原生Directory服务,便于JS桥接
6:
7: var dirService = Cc["@mozilla.org/file/directory_service;1"]
8:
9: .getService(Ci.nsIProperties);
10:
11: var localFile = dirService.get("ProfD", Ci.nsIFile);
12:
13: // 添加FulinToolbarData文件夹对象
14:
15: localFile.append("FulinToolbarData");
16:
17: //如果当前的FulinToolbarData文件夹不存在,那么创建它
18:
19: if( !localFile.exists() )
20:
21: //创建文件夹的权限为0700,类似linux下权限分配方法
22:
23: localFile.create(1, parseInt("0700", 8) );
24:
25: return localFile;
26:
27: };
我们在获取当前Profile的文件夹的FulinToolbarData后,需要获取该文件夹下面的指定文件名的文件对象。我们实现了MTB_File函数,用于获取改对象。这个也是MTB_File类的构造函数,他会自动的调用上面的MTB_getLocalFileDir函数,然后返回我们所需要的文件对象。
1: function MTB_File(filename)
2:
3: {
4:
5: var localfile = MTB_getLocalFileDir();
6:
7: localfile.append(filename);
8:
9: this.nowFile = localfile;
10:
11: };
我们对一个文件进行增删改等操作前,必须先打开该文件,所以我们提供了文件打开函数open,该函数根据传入的打开类型Mode的不同,分别返回只读,写入和写入及创建三种不同类型的文件流对象,以方便我们使用文件流进行文件的操作。关于文件流的创建,我们使用了Mozilla提供file-input-stream和file-output-stream对象来实现跨平台的文件流功能。
1: MTB_File.prototype.open = function(mode)
2:
3: {
4:
5: switch(mode){
6:
7: / ReadOnly只读模式打开文件流
8:
9: case "r":
10:
11: var instream
12:
13: = Cc["@mozilla.org/network/file-input-stream;1"]
14:
15: .createInstance(Ci.nsIFileInputStream);
16:
17: instream.init(this.nowFile, MTB_RDONLY, PERM_IROTH, 0);
18:
19: this.tmpStream = instream;
20:
21: var sctinstream
22:
23: = Cc["@mozilla.org/scriptableinputstream;1"]
24:
25: .createInstance(Ci.nsIScriptableInputStream);
26:
27: sctinstream.init(this.tmpStream);
28:
29: this.nowStream = sctinstream;
30:
31: break;
32:
33: //Write 可写模式打开文件流
34:
35: case "w":
36:
37: var outstream
38:
39: = Cc["@mozilla.org/network/file-output-stream;1"]
40:
41: .createInstance(Ci.nsIFileOutputStream);
42:
43: outstream.init(this.nowFile, MTB_RDWR, PERM_IROTH, 0);
44:
45: this.nowStream = outstream;
46:
47: break;
48:
49: // Write&Create 创建和可写模式打开文件流
50:
51: case "w+":
52:
53: var outstream
54:
55: = Cc["@mozilla.org/network/file-output-stream;1"]
56:
57: .createInstance(Ci.nsIFileOutputStream);
58:
59: if( this.exists() )
60:
61: this.nowFile.remove( false );
62:
63: outstream.init(
64:
65: this.nowFile, MTB_WRONLY|MTB_CREATE_FILE,
66:
67: PERM_IROTH, 0);
68:
69: this.nowStream = outstream;
70:
71: break;
72:
73: }
74:
75: };
在我们打开文件流之后,我们可以使用文件流来操作我们指定的文件。比如我们可以从当前文件流里面读取出指定长度的内容来,下面的read函数就可以实现上面的功能。我们的文件流提供了读取,写入等操作,我们的函数只是在封装这些功能,以方便我们做一些业务逻辑相关的操作,比如指定内容过滤或者当前文件流可用性的判定。
1: MTB_File.prototype.read = function(count)
2:
3: {
4:
5: if( this.nowStream == null )
6:
7: return;
8:
9: //从当前指定的文件流里面读取指定长度的内容
10:
11: return this.nowStream.read(count);
12:
13: };
下面的函数是往我们指定的文件流里面写入我们指定的内容,我们在函数里面加入了对当前文件流是否存在的判断。如果当前文件流存在,那么我们往当前文件流里面写入指定内容,然后Flush整个文件流,防止下次写入上次的输入的内容。
1: MTB_File.prototype.write = function(str)
2:
3: {
4:
5: if( this.nowStream == null )
6:
7: return;
8:
9: this.nowStream.write( str, str.length );
10:
11: this.nowStream.flush();
12:
13: };
在我们对该做的文件操作结束之后,我们必须关闭我们文件流,以便于系统回收资源。关闭文件流的时候,我们首先要调用当前文件流的close方法,然后将当前的文件流设置为null,就可以标识当前文件流为待回收的,当系统在方便的时候回收该文件流资源。
1: MTB_File.prototype.close = function(){
2:
3: if(this.nowStream != null)
4: this.nowStream.close();
5:
6: if(this.tmpStream != null)
7:
8: this.tmpStream.close();
9:
10: this.nowFile = null;
11:
12: this.nowStream = null;
13:
14: this.tmpStream = null;
15:
16: };
我们在访问文件流进行读操作的时候,可能会遇到我们要读入长度为10的内容的时候,可是我们当前访问的文件流只有长度为5的可用内容,这种时候如果我们没有任何保护手段来确保访问不会越界,那么可能会造成访问越界异常。为了防止越界异常的发生,我们在每次从文件流里面读取内容时都会检查当前文件流是不是已经到了最后了。下面就是这个EOF函数的实现,他会获得当前文件流可用长度,看他是否大于1,如果不大于1那么就说明当前文件流就已经到达最后,不可在读取了。
1: MTB_File.prototype.EOF = function()
2: {
3:
4: if( this.nowStream == null )
5:
6: return;
7:
8: if( this.nowStream.available() > 0 )
9:
10: return false;
11:
12: else
13:
14: return;
15:
16: };
另外,通过当前文件流我们还可以获取当前文件的大小,类型以及是否可运行等其他很多属性,我们也提供了相应的函数封装,以便于其他javascript文件调用。最后提供整个js类的下载:
posted on 2008-06-09 09:59 JesseZhao 阅读(5669) 评论(13) 编辑 收藏 举报