其中常用的就是FSDirectory:表示对文件系统目录的操作。RAMDirectory :内存中的目录操作。
首先我们看看类FSDirectory的源代码
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import org.apache.lucene.index.IndexFileNameFilter;
// Used only for WRITE_LOCK_NAME in deprecated create=true case:
import org.apache.lucene.index.IndexWriter;
public class FSDirectory extends Directory {
//主要是用来缓存FilePath与FSDirectory,主要是保证针对统一目录,只能有一个FSDirectory实例
private static final Map DIRECTORIES = new HashMap();
//主要判断是否给目录上锁
private static boolean disableLocks = false;
//设置是否给目录上锁,一般只能用户只读目录。
//They should only be disabled if the index
// is on a read-only medium like a CD-ROM
public static void setDisableLocks(boolean doDisableLocks) {
FSDirectory.disableLocks = doDisableLocks;
}
//f返回是否给目录上锁
public static boolean getDisableLocks() {
return FSDirectory.disableLocks;
}
public static final String LOCK_DIR = System.getProperty("org.apache.lucene.lockDir",
System.getProperty("java.io.tmpdir"));
private static Class IMPL; //主要是获取FSDirectory的实例
static {
try {
String name =System.getProperty("org.apache.lucene.FSDirectory.class",
FSDirectory.class.getName());
IMPL = Class.forName(name); //首先获取该类的名称,然后在获取该类的Class实例
} catch (ClassNotFoundException e) {
throw new RuntimeException("cannot load FSDirectory class: " + e.toString(), e);
} catch (SecurityException se) {
try {
IMPL = Class.forName(FSDirectory.class.getName()); //直接使用JAVA反射获取该类Class实例
} catch (ClassNotFoundException e) {
throw new RuntimeException("cannot load default FSDirectory class: " + e.toString(), e);
}
}
}
private static MessageDigest DIGESTER; //获取加密
static {
try {
DIGESTER = MessageDigest.getInstance("MD5"); //使用MD5加密
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e.toString(), e);
}
}
private byte[] buffer = null;
/**静态方法,根据基于指定目录,返回该目录中对应的一个FSDirectory实例 */
public static FSDirectory getDirectory(String path) throws IOException {
return getDirectory(new File(path), null);
}
/** 静态方法,根据指定的路径path以及锁工厂LockFactory参数,返回该路径的一个FSDirectiry实例 */
public static FSDirectory getDirectory(String path, LockFactory lockFactory) throws IOException {
return getDirectory(new File(path), lockFactory);
}
/**静态方法,根据指定的File对象,返回该路径的一个FSDirectiry实例 */
public static FSDirectory getDirectory(File file) throws IOException {
return getDirectory(file, null);
}
/**静态方法,根据指定File对象以及锁工厂LockFactory参数,返回该路径的一个FSDirectiry实例
其他方法,都最终转化为该方法来实现 */
public static FSDirectory getDirectory(File file, LockFactory lockFactory) throws IOException
{
file = new File(file.getCanonicalPath()); //定义一个File对象,以传递的参数作为目录
if (file.exists() && !file.isDirectory()) //首先判断文件存在时,是否是目录
throw new IOException(file + " not a directory");
if (!file.exists()) //如果文件不存在。则创建
if (!file.mkdirs()) throw new IOException("Cannot create directory: " + file); //创建所有目录
FSDirectory dir; //定义一个类 FSDirectory
synchronized (DIRECTORIES) {
dir = (FSDirectory)DIRECTORIES.get(file); //首先从Map查找是否存在该实例,
if (dir == null) {
try {
dir = (FSDirectory)IMPL.newInstance(); //调用静态内部类IMPL获取一个与文件系统目录有关的Directory类,并加载该类
} catch (Exception e) {
throw new RuntimeException("cannot load FSDirectory class: " + e.toString(), e);
}
dir.init(file, lockFactory); // 根据指定的file和lockFactory,调用该类Directory的init方法,进行FSDirectory的初始化初始化工作
DIRECTORIES.put(file, dir); //将该实例放置到HashMap中
} else {
//如果该目录dir管理所用的锁工厂实例为空,或者不是同一个锁工厂实例,抛出异常
if (lockFactory != null && lockFactory != dir.getLockFactory()) {
throw new IOException("Directory was previously created with a different LockFactory instance; please pass null as the lockFactory instance and use setLockFactory to change it");
}
}
}
synchronized (dir) {
dir.refCount++; //用于记录该目录dir被引用的计数增加1
}
return dir;
}
/** 废弃的方法 */
public static FSDirectory getDirectory(String path, boolean create) throws IOException {
return getDirectory(new File(path), create);
}
/** 废弃的方法 */
public static FSDirectory getDirectory(File file, boolean create) throws IOException
{
FSDirectory dir = getDirectory(file, null);
if (create) {
dir.create();
}
return dir;
}
private void create() throws IOException {
if (directory.exists()) {
String[] files = directory.list(IndexFileNameFilter.getFilter()); // clear old files
if (files == null)
throw new IOException("cannot read directory " + directory.getAbsolutePath() + ": list() returned null");
for (int i = 0; i < files.length; i++) {
File file = new File(directory, files[i]);
if (!file.delete())
throw new IOException("Cannot delete " + file);
}
}
lockFactory.clearLock(IndexWriter.WRITE_LOCK_NAME);
}
private File directory = null; //File directory是FSDirectory类的一个成员
private int refCount; //用于记录该目录dir被引用的计数增加1
protected FSDirectory() {}; // permit subclassing
private void init(File path, LockFactory lockFactory) throws IOException {
//根据指定的file和lockFactory,调用该类Directory的init方法,进行FSDirectory的初始化初始化工作
directory = path;
boolean doClearLockID = false;
if (lockFactory == null) { //锁工厂实例为null
if (disableLocks) { //如果锁不可以使用
lockFactory = NoLockFactory.getNoLockFactory(); //调用NoLockFactory类,获取NoLockFactory实例,为当前的锁工厂实例。其实NoLockFactory是一个单态(singleton)模式的工厂类,应用中只能有一个锁实例,不需要进行同步
} else { //如果锁可以使用,获取锁工厂类名称的字符串描述
String lockClassName = System.getProperty("org.apache.lucene.store.FSDirectoryLockFactoryClass");
if (lockClassName != null && !lockClassName.equals("")) {//如果获取的锁工厂类名称的字符串描述不为null,而且者不为空
Class c;
try {
c = Class.forName(lockClassName); //创建一个Class对象,加载该锁工厂类
} catch (ClassNotFoundException e) {
throw new IOException("unable to find LockClass " + lockClassName);
}
try {
lockFactory = (LockFactory) c.newInstance(); //获取一个锁工厂的实例
} catch (IllegalAccessException e) {
throw new IOException("IllegalAccessException when instantiating LockClass " + lockClassName);
} catch (InstantiationException e) {
throw new IOException("InstantiationException when instantiating LockClass " + lockClassName);
} catch (ClassCastException e) {
throw new IOException("unable to cast LockClass " + lockClassName + " instance to a LockFactory");
}
// 根据获取的锁工厂实例的类型来设置对文件File path加锁的方式
if (lockFactory instanceof NativeFSLockFactory) {
((NativeFSLockFactory) lockFactory).setLockDir(path);
} else if (lockFactory instanceof SimpleFSLockFactory) {
((SimpleFSLockFactory) lockFactory).setLockDir(path);
}
} else {
// 没有其他的锁工厂类可用,则使用默认的锁工厂类创建一个锁工厂实例
lockFactory = new SimpleFSLockFactory(path);
doClearLockID = true;
}
}
}
// 设置当前FSDirectory相关锁工厂实例
setLockFactory(lockFactory);
if (doClearLockID) {
// Clear the prefix because write.lock will be
// stored in our directory:
lockFactory.setLockPrefix(null);
}
}
/** 返回所有的在当前目录下的Lucene索引文件名,并且保存在数组中*/
public String[] list() {
ensureOpen();
return directory.list(IndexFileNameFilter.getFilter());
}
/**检查指定名称的文件是否存在 */
public boolean fileExists(String name) {
ensureOpen();
File file = new File(directory, name);
return file.exists();
}
/** 返回指定文件最后修改的时间*/
public long fileModified(String name) {
ensureOpen();
File file = new File(directory, name);
return file.lastModified();
}
/** 返回指定目录和文件名的文件最后修改的时间*/
public static long fileModified(File directory, String name) {
File file = new File(directory, name);
return file.lastModified();
}
/**设置指定文件最后修改的时间为当前时间*/
public void touchFile(String name) {
ensureOpen();
File file = new File(directory, name);
file.setLastModified(System.currentTimeMillis());
}
/**返回指定文件的长度*/
public long fileLength(String name) {
ensureOpen();
File file = new File(directory, name);
return file.length();
}
/**删除当前目录中指定文件名的文件*/
public void deleteFile(String name) throws IOException {
ensureOpen();
File file = new File(directory, name);
if (!file.delete())
throw new IOException("Cannot delete " + file);
}
/** 创建一个名称为name的文件,返回一个输出流,以便对该文件进行写入操作 */
public IndexOutput createOutput(String name) throws IOException {
ensureOpen();
File file = new File(directory, name);
if (file.exists() && !file.delete()) //如果文件存在,则将文件删除
throw new IOException("Cannot overwrite: " + file);
return new FSIndexOutput(file); // 返回文件File file的一个输出流
}
// Lucene使用该方法确保所有的针对该文件的写操作都会存储到Index。并且阻止machine/OS发生故障 破坏该index。
public void sync(String name) throws IOException {
ensureOpen();
File fullFile = new File(directory, name);
boolean success = false;
int retryCount = 0;
IOException exc = null;
while(!success && retryCount < 5) {
retryCount++;
RandomAccessFile file = null;
try {
try {
file = new RandomAccessFile(fullFile, "rw");
file.getFD().sync();
success = true;
} finally {
if (file != null)
file.close();
}
} catch (IOException ioe) {
if (exc == null)
exc = ioe;
try {
// Pause 5 msec
Thread.sleep(5);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
}
if (!success)
// Throw original exception
throw exc;
}
//读取名称为name的文件,返回一个输出流,以便定义对读取出来的内容进行操作
public IndexInput openInput(String name) throws IOException {
ensureOpen();
return openInput(name, BufferedIndexInput.BUFFER_SIZE);
}
// 打开指定名称为name的文件,指定大小为缓冲区大小bufferSize,返回一个输入流
public IndexInput openInput(String name, int bufferSize) throws IOException {
ensureOpen();
return new FSIndexInput(new File(directory, name), bufferSize);
}
// 一个字符缓冲区,将字节转换为十六进制
private static final char[] HEX_DIGITS =
{'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
//获取锁的标识ID
public String getLockID() {
ensureOpen();
String dirName; // name to be hashed
try {
dirName = directory.getCanonicalPath();
} catch (IOException e) {
throw new RuntimeException(e.toString(), e);
}
byte digest[];
synchronized (DIGESTER) {
digest = DIGESTER.digest(dirName.getBytes());
}
StringBuffer buf = new StringBuffer();
buf.append("lucene-");
for (int i = 0; i < digest.length; i++) {
int b = digest[i];
buf.append(HEX_DIGITS[(b >> 4) & 0xf]);
buf.append(HEX_DIGITS[b & 0xf]);
}
return buf.toString();
}
/** 关闭当前目录. */
public synchronized void close() {
if (isOpen && --refCount <= 0) {
isOpen = false;
synchronized (DIRECTORIES) {
DIRECTORIES.remove(directory);
}
}
}
//获取当前目录File类
public File getFile() {
ensureOpen();
return directory;
}
/** For debug output. */
public String toString() {
return this.getClass().getName() + "@" + directory;
}
//FSIndexInput是一个静态内部类,用于管理文件系统中的索引文件输入流
protected static class FSIndexInput extends BufferedIndexInput {
protected static class Descriptor extends RandomAccessFile {
// 用于记录文件打开状态的boolean型变量isOpen
protected volatile boolean isOpen;
long position;
final long length; // 文件长度
//构造函数for类Descriptor
public Descriptor(File file, String mode) throws IOException {
super(file, mode);
isOpen=true;
length=length();
}
//关闭
public void close() throws IOException {
if (isOpen) {
isOpen=false;
super.close();
}
}
protected void finalize() throws Throwable {
try {
close();
} finally {
super.finalize();
}
}
}
protected final Descriptor file;
boolean isClone;
public FSIndexInput(File path) throws IOException {
this(path, BufferedIndexInput.BUFFER_SIZE);
}
public FSIndexInput(File path, int bufferSize) throws IOException {
super(bufferSize);
file = new Descriptor(path, "r");
}
/** 比较底层的读取操作,主要是对字节操作 */
protected 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 {
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);
}
}
//仅当不是拷贝的时间关闭
public void close() throws IOException {
// only close the file if this is not a clone
if (!isClone) file.close();
}
protected void seekInternal(long position) {
}
//返回文件的长度
public long length() {
return file.length;
}
//创建一个拷贝
public Object clone() {
FSIndexInput clone = (FSIndexInput)super.clone();
clone.isClone = true;
return clone;
}
/** Method used for testing. Returns true if the underlying
* file descriptor is valid.
*/
boolean isFDValid() throws IOException {
return file.getFD().valid();
}
}
// FSIndexOutput是一个静态内部类,用于管理文件系统中的索引文件输出流,与FSIndexInput实现类似
protected static class FSIndexOutput extends BufferedIndexOutput {
RandomAccessFile file = null; //定一个随机读写文件
private volatile boolean isOpen;
//构造函数,根据文件定一个一个可以读写
public FSIndexOutput(File path) throws IOException {
file = new RandomAccessFile(path, "rw");
isOpen = true;
}
//输入内容
public void flushBuffer(byte[] b, int offset, int size) throws IOException {
file.write(b, offset, size);
}
//关闭该对象。仅当该对象被打开,从来没有被关闭过
public void close() throws IOException {
if (isOpen) {
boolean success = false;
try {
super.close();
success = true;
} finally {
isOpen = false;
if (!success) {
try {
file.close();
} catch (Throwable t) {
// Suppress so we don't mask original exception
}
} else
file.close();
}
}
}
// 随机访问的方法实现
public void seek(long pos) throws IOException {
super.seek(pos);
file.seek(pos);
}
public long length() throws IOException {
return file.length();
}
public void setLength(long length) throws IOException {
file.setLength(length);
}
}
}
由具体构造函数实现方法以及dir.init()方法,可以看出来,针对每一个目录只能有一个FSDirectory实例,
由此我们可以看看FSDirectory的主要功能:
1、针对同一个目录进行维护
2、对于锁工厂的获取以及管理
3、对文件系统目录下索引文件的输入流和输出流的管理
4、FSDirectory类中实现了很多静态内部类,这使得只能在FSDirectory类内部访问这些静态类,对外部透明。
因此该类主要Directory抽象类的操作本地文件的实现。具体操作我们在以后索引的处理详细讲解