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

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

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

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