Directory类系
综述:Directory类系可以被理解成是一个文件夹,它提供些对文件夹内容及本身的一些操作。比如:
1.建立/读取/删除/重命名文件;
2.复制文件夹;
3.查寻是否存在某文件;
4.设置/获取某文件最后访问时间;
5.查寻文件夹大小;
6.查看文件列表
1.Directory类系层次图

2. 部分代码说明
Directory类
Directory是所有文件夹类的父类。它规定了所有子类必须提供的操作,但它本身只实现了部分,其中比较重要的就是文件夹间的拷贝操作copy()方法。
 1
    public static void copy(Directory src, Directory dest, boolean closeDirSrc)
 2
            throws IOException 
{    // 文件夹之间的的复制
 3
        final String[] files = src.list();    // 获取源文件夹文件列表
 4
 5
        if (files == null)
 6
            throw new IOException("cannot read directory " + src
 7
                    + ": list() returned null");
 8
 9
        byte[] buf = new byte[BufferedIndexOutput.BUFFER_SIZE];    // 建立缓冲buf
10
        for (int i = 0; i < files.length; i++) 
{    // 对每个文件进行复制操作
11
            IndexOutput os = null;    // 写通道
12
            IndexInput is = null;    // 读通道
13
            try 
{
14
                // create file in dest directory
15
                os = dest.createOutput(files[i]);    // 创建对file[i]的写通道
16
                // read current file
17
                is = src.openInput(files[i]);    // 读通道
18
                // and copy to dest directory
19
                long len = is.length();    // 文件总长度
20
                long readCount = 0;    // 已读取长度
21
                while (readCount < len) 
{    // 循环读取文件数据
22
                    int toRead = readCount + BufferedIndexOutput.BUFFER_SIZE > len ? (int) (len - readCount)
23
                            : BufferedIndexOutput.BUFFER_SIZE;    // 实际一次读取长度 
24
                    is.readBytes(buf, 0, toRead);    // 读取
25
                    os.writeBytes(buf, toRead);    // 写入
26
                    readCount += toRead;    // 记录已写入数量
27
                }
28
            } finally 
{    // 关闭操作
29
                // graceful cleanup
30
                try 
{
31
                    if (os != null)
32
                        os.close();
33
                } finally 
{
34
                    if (is != null)
35
                        is.close();
36
                }
37
            }
38
        }
39
        if (closeDirSrc)
40
            src.close();
41
    } 
FSDirectory类
FSDirectory是基于硬盘的Directory。
FSDirectory中最重要的实例生成方法就是getFSDirectory(File, LockFactory)了。
 1
    public static FSDirectory getDirectory(File file, LockFactory lockFactory)
 2
            throws IOException 
{
 3
        file = new File(file.getCanonicalPath());    // 获得file
 4
 5
        if (file.exists() && !file.isDirectory())    // file存在但不是文件夹
 6
            throw new IOException(file + " not a directory");
 7
 8
        if (!file.exists())    // file不存在
 9
            if (!file.mkdirs())    // 试图创建file文件夹,失败则抛出异常
10
                throw new IOException("Cannot create directory: " + file);
11
12
        FSDirectory dir;
13
        synchronized (DIRECTORIES) 
{    // 同步访问DIRECTORIES
14
            dir = (FSDirectory) DIRECTORIES.get(file);    // 试图从DIRECTORIES中获取
15
            if (dir == null) 
{    // 获取失败
16
                try 
{
17
                    dir = (FSDirectory) IMPL.newInstance();    // 创建一个新实例
18
                } catch (Exception e) 
{
19
                    throw new RuntimeException(
20
                            "cannot load FSDirectory class: " + e.toString(), e);
21
                }
22
                dir.init(file, lockFactory);    // 初始化dir
23
                DIRECTORIES.put(file, dir);    // 把dir放入DIRECTORIES
24
            } else 
{
25
                // Catch the case where a Directory is pulled from the cache,
26
                // but has a
27
                // different LockFactory instance.
28
                if (lockFactory != null && lockFactory != dir.getLockFactory()) 
{
29
                    throw new IOException(
30
                            "Directory was previously created with a different LockFactory instance; please pass null as the lockFactory instance and use setLockFactory to change it");
31
                }
32
            }
33
        }
34
        synchronized (dir) 
{
35
            dir.refCount++;    // refCount++
36
        }
37
        return dir;
38
    } 
init(File, LockFactory)为初始化FSDirectory实例的方法,只能内部调用。
 1
    private void init(File path, LockFactory lockFactory) throws IOException 
{
 2
 3
        // Set up lockFactory with cascaded defaults: if an instance was passed
 4
        // in,
 5
        // use that; else if locks are disabled, use NoLockFactory; else if the
 6
        // system property org.apache.lucene.store.FSDirectoryLockFactoryClass
 7
        // is set,
 8
        // instantiate that; else, use SimpleFSLockFactory:
 9
10
        directory = path;
11
12
        boolean doClearLockID = false;
13
14
        if (lockFactory == null) 
{
15
16
            if (disableLocks) 
{
17
                // Locks are disabled:
18
                lockFactory = NoLockFactory.getNoLockFactory();
19
            } else 
{
20
                String lockClassName = System
21
                        .getProperty("org.apache.lucene.store.FSDirectoryLockFactoryClass");
22
23
                if (lockClassName != null && !lockClassName.equals("")) 
{    // 系统设置了默认lockFactory
24
                    Class c;
25
26
                    try 
{
27
                        c = Class.forName(lockClassName);
28
                    } catch (ClassNotFoundException e) 
{
29
                        throw new IOException("unable to find LockClass "
30
                                + lockClassName);
31
                    }
32
33
                    try 
{
34
                        lockFactory = (LockFactory) c.newInstance();    // 实例化系统默认的lockFactory
35
                    } catch (IllegalAccessException e) 
{
36
                        throw new IOException(
37
                                "IllegalAccessException when instantiating LockClass "
38
                                        + lockClassName);
39
                    } catch (InstantiationException e) 
{
40
                        throw new IOException(
41
                                "InstantiationException when instantiating LockClass "
42
                                        + lockClassName);
43
                    } catch (ClassCastException e) 
{
44
                        throw new IOException("unable to cast LockClass "
45
                                + lockClassName + " instance to a LockFactory");
46
                    }
47
48
                    if (lockFactory instanceof NativeFSLockFactory) 
{    // 根据lockFactory的类型各自调用setLockDir()
49
                        ((NativeFSLockFactory) lockFactory).setLockDir(path);
50
                    } else if (lockFactory instanceof SimpleFSLockFactory) 
{
51
                        ((SimpleFSLockFactory) lockFactory).setLockDir(path);
52
                    }
53
                } else 
{    // 使用lucene默认的lockFactory: SimpleFSLockFactory
54
                    // Our default lock is SimpleFSLockFactory;
55
                    // default lockDir is our index directory:
56
                    lockFactory = new SimpleFSLockFactory(path);
57
                    doClearLockID = true;    // 设置为true,    不懂!!!!!!
58
                }
59
            }
60
        }
61
62
        setLockFactory(lockFactory);    // 设置lockFactory
63
64
        if (doClearLockID) 
{
65
            // Clear the prefix because write.lock will be
66
            // stored in our directory:
67
            lockFactory.setLockPrefix(null);
68
        }
69
    } 
MMapDirectory类
MMapDirectory是FSDirectory的子类,它重写了FSDirectory的openInput()方法。他们的区别是,在读取文件时,FSDirectory在底层用BufferedIndexInput(把文件部分读入内存),而MMapDirectory则用MMapDirectory/MultiMMapDirectory(把文件一次性全部读入内存)。
 
openInput(String)功能为打开某文件的读取通道。
 
 1
    public IndexInput openInput(String name) throws IOException 
{
 2
        File f = new File(getFile(), name);    
 3
        RandomAccessFile raf = new RandomAccessFile(f, "r");
 4
        try 
{    // 根据文件的大小选择适当的IndexInput
 5
            return (raf.length() <= MAX_BBUF) ? (IndexInput) new MMapIndexInput(
 6
                    raf)
 7
                    : (IndexInput) new MultiMMapIndexInput(raf, MAX_BBUF);
 8
        } finally 
{
 9
            raf.close();
10
        }
11
    } 
 
RAMDirectory类
RAMDirectory与FSDirectory不同,它是基于内存的。它在内存中划出一个区域,用来存放文件,在性能上肯定要比FSDirectory快的多。当然它也有它的局限性,比如,文件过大,内存小放不下,呵呵。
 
RAMDirectory里定义了变量:HashMap fileMap = new HashMap()用来存放文件名及与之对应得文件在内存中的指针。还有一个变量long sizeInBytes:文件夹总字节数。
 
当通过Directory来创建RAMDirectory时,RAMDirectory需要把Directory中的数据拷贝到RAMDirectory中来。
 
1
    private RAMDirectory(Directory dir, boolean closeDir) throws IOException 
{
2
        this();
3
        Directory.copy(dir, this, closeDir);    // 拷贝数据
4
    } 
 
list()用来列出RAMDirectory中的所有文件,也就是fileMap中的所有文件名。
 
 1
    public synchronized final String[] list() 
{ // 列出fileMap中的文件清单
 2
        ensureOpen(); // 确保fileMap不为空
 3
        Set fileNames = fileMap.keySet(); // 返回文件名set
 4
        String[] result = new String[fileNames.size()];
 5
        int i = 0;
 6
        Iterator it = fileNames.iterator();
 7
        while (it.hasNext())
 8
            // 遍历文件名
 9
            result[i++] = (String) it.next();
10
        return result; // 返回文件名数组
11
    } 
 
在查询某文件是否存在时,只需要到fileMap中看下对应的文件名是否存在。
 
1
    public final boolean fileExists(String name) 
{ // 查询是否存在名为name的文件
2
        ensureOpen();
3
        RAMFile file;
4
        synchronized (this) 
{
5
            file = (RAMFile) fileMap.get(name); // 从fileMap中取name文件
6
        }
7
        // file != null 说明文件存在;反之,不存在
8
        return file != null;
9
    } 
 
touchFile(String)功能是修改给定文件名的文件的最近修改时间。方法本身并不是同步方法,因此在方法体内部需要考虑同步的问题。
 
 1
    public void touchFile(String name) throws IOException 
{
 2
        // 修设置最近修改时间为当前时间
 3
        ensureOpen();
 4
        RAMFile file;
 5
        synchronized (this) 
{
 6
            file = (RAMFile) fileMap.get(name);
 7
        }
 8
        if (file == null)
 9
            throw new FileNotFoundException(name);
10
11
        long ts2, ts1 = System.currentTimeMillis();
12
        do 
{ // 这个循环的用意是什么?????有人告诉我不????
13
            try 
{
14
                Thread.sleep(0, 1); // 睡 1ns
15
            } catch (InterruptedException e) 
{
16
            }
17
            ts2 = System.currentTimeMillis(); // 获取当前时间
18
        } while (ts1 == ts2);
19
20
        file.setLastModified(ts2);    // 同步修改最近修改时间
21
    } 
 
deleteFile(String)功能为删除给定文件名的文件,不存在则抛出异常。
 
 1
    public synchronized void deleteFile(String name) throws IOException 
{ // 删除name文件
 2
        ensureOpen();
 3
        RAMFile file = (RAMFile) fileMap.get(name);
 4
        if (file != null) 
{
 5
            fileMap.remove(name); // 从fileMap中删除此文件,也就是删掉该文件的相关记录:名字和buffer地址
 6
            file.directory = null; // 设置file的所属文件夹为null,即它不再属于任何文件夹
 7
            sizeInBytes -= file.sizeInBytes; // updates to RAMFile.sizeInBytes synchronized on directory
 8
        } else
 9
            throw new FileNotFoundException(name);
10
    } 
 
createOutput()创建一个新文件并返回其写通道。若同名文件已存在,则删除之。
 

    public IndexOutput createOutput(String name) throws IOException 
{ // 新建给定名字的文件并返回它的写通道
        ensureOpen(); // 确保fileMap不为null
        RAMFile file = new RAMFile(this); // 创建一个内存文件,参数为当前文件夹

        synchronized (this) 
{ // 获取同步锁
            RAMFile existing = (RAMFile) fileMap.get(name);

            if (existing != null) 
{ // 存在同名文件,则删除之
                sizeInBytes -= existing.sizeInBytes; // 更改文件夹大小
                existing.directory = null; // 设置其directory为null
            }
            fileMap.put(name, file);
        }
        return new RAMOutputStream(file); // 返回该文件的写通道
    }