FSDirectory继承了abstract类Directory
在该类中既有该类的一些初始化操作,又有对FSDirectory对象本身的一些操作,这是为什么把其构造函数设置为私有的一部分原因
static final Hashtable DIRECTORIES = new Hashtable();
每新建一个FSDirectory都会将其加入到该Hashtable中来。名称是FSDirectory对应的File 值是该FSDirectory。
注意:final对象并非是不可更改的
static final String LOCK_DIR =
System.getProperty("org.apache.lucene.lockdir",
System.getProperty("java.io.tmpdir"));
首先看用户是否注册了"org.apache.lucene.lockdir"属性,如果没有则用JAVA虚拟机固有的"java.io.tmpdir"属性
这个属性是一个路径,代表lucene的锁文件锁放的位置。
static final boolean DISABLE_LOCKS =
Boolean.getBoolean("disableLuceneLocks") || Constants.JAVA_1_1;
如果用户注册了"disableLuceneLocks"属性且为false,或者JAVA的版本是1.1则无法使用锁。
static FSDirectory getDirectory(String path, boolean create)
static FSDirectory getDirectory(File file, boolean create)
从得到一个指定路径或者文件的FSDirectory如果在则取出,如果不存在则用其私有的构造函数构造一个
该类还有3个非static的类变量
private File directory = null; 索引目录
private int refCount; 锁目录
private File lockDir; 索引目录数目
实际上,初始化一个FSDirectory只需要初始化这3个变量即可
如果create的值为true 则:如果索引目录是已经存在的目录,则会遍历该目录然后删除每一个文件,如果锁目录是已存在的也会用list返回所有的文件然后调用file.delete() 删除。 如果目录不存在则创建一个新的。
注意:list()方法 会先用文件名进行排序然后返回(a.txt会比b.txt先返回) 且delete方法删除文件夹时,只能删除空文件夹。如果失败则跳出程序,不会删除在该文件夹之后返回的文件。(如果有aa.txt , ab/b.txt , b.txt , 则删除时候由于a文件夹非空删除失败,则b.txt由于前面删除失败跳出程序,也不会被删除,但是aa.txt被正常删除)
private FSDirectory(File path, boolean create) throws IOException
私有的构造函数
private synchronized void create() throws IOException
创建新的directory /lockDir目录,当目录已存在时即清空该目录,不存在即创建新的目录。
final String[] list() throws IOException
以字符串文件名的形式返回索引目录的所有文件
final boolean fileExists(String name) throws IOException
在索引目录是否存在指定文件名的文件
final long fileModified(String name) throws IOException
static final long fileModified(File directory, String name)
返回该文件的最后修改时间,directory参数为相对路径,第一个函数的相对路径为索引目录
void touchFile(String name) throws IOException
将该文件的最后修改时间设置为当前时间
final long fileLength(String name) throws IOException
返回该文件的长度
final void deleteFile(String name) throws IOException
删除该文件
final synchronized void renameFile(String from, String to) throws IOException
重命名该文件
该方法会首先检测新的文件名命名的文件是否已经存在如果存在即删除该文件,然后再将文件重新命名为新的文件名。
doug cutting在该方法的注释上写到:
1.删除操作和重命名的操作不是原子的。
2.重命名操作在有些虚拟机上面不能正确的工作,如果重命名失败则会采用手动copy的方法。使用输入输出流将旧的文件的内容写入到新的文件中去,然后删除旧的文件。
注意:该方法必须是同步的。
final OutputStream createFile(String name) throws IOException
用指定的文件名创建一个新的可写的空文件 实际上返回的是FSOutputStream,注意这里的OutputStream并不是java的基础类。而是doug cutting自己写的一个文件随即访问类。同理FSInputStream和InputStream也是Lucene自己的类。
final InputStream openFile(String name) throws IOException
从一个存在的文件打开一个输入流
getLockPrefix()
在FSDirectory中还有
private static MessageDigest DIGESTER;这个静态变量是提供加密功能的
DIGESTER=MessageDigest.getInstance("MD5"),-----MD5加密算法
或者可以DIGESTER=MessageDigest.getInstance("SHA"),-----SHA加密算法
用于对锁目录的 文件名的加密
用法如下:
digest = DIGESTER.digest(dirName.getBytes()); dirName是需要被加密的字符串,这里是索引文件的目录名,
在FSContext中,其应用在 getLockPrefix() 该方法是为某个索引目录创建其对应的锁目录文件名。
首先返回经过加密后的byte[] 数组digest,然后将digest按照每4个bit转化为一个16进制的字符,存进一个StringBuffer中
其转化类似与Base64编码方式,不过要简单得多。
方法
Lockl makeLock(String name)
是从Directory中扩展而来的,该方法返回一个Lock对象,该对象将会在介绍完Lucene的输入输出流之后介绍。
该方法比较简单,首先是调用了getLockPrefix() 方法,返回文件锁的部分对象名,然后在该名称后面加上锁的特征名
譬如说读写锁 事务锁
其名称类似于下:
lucene-12c90c2c381bc7acbc4846b4ce97593b-write.lock
lucene-12c90c2c381bc7acbc4846b4ce97593b-commit.lock
这两种锁机制将会在后面介绍
最后通过一个匿名的内部类返回一个经过重载的Lock对象,该内部类中的方法有锁的创建,得到,释放,以及检测,另外还有一个toString()方法返回锁的名称。
在FSDirectory类中有OutputStream和InputStream的实现类,这两个虚类只是定义了一些操作,并没有定义输入或者输出的设备。
Lucene在输入输出的设计上,将会由子类定义输入输出的设备。
FSOutputStream
在FSOutputStream中有一个 RandomAccess File=new RandomAccessFile(path, "rw");
在对该输出流的操作将用调用该file的相应方法实现
最重要的
public final void flushBuffer(byte[] b, int size) throws IOException {
file.write(b, 0, size);
}
flushBuffer的调用将会将byte中的0--size范围的数据写入到文件path中去。
FSInputStream
最重要的
protected final void readInternal(byte[] b, int offset, int len)
throws IOException {
synchronized (file) {
long position = getFilePointer(); //得到该当前文件指针
if (position != file.position) {
file.seek(position);
file.position = position;
}
int total = 0;
do {
//从文件中读取指定长度的字节到字节数组
// 在其基类InputStream中的refill()方法 将会调用 readInternal(buffer, 0, bufferLength);首先从文件中读取字节到缓冲数组。
// 在InputStream中每次读取操作都会调用readInternal方法,或者通过refill()方法间接调用该方法。
int i = file.read(b, offset+total, len-total); //将文件中的数据读到缓冲区
if (i == -1)
throw new IOException("read past EOF");
file.position += i;
total += i;
} while (total < len);
}
}