LetsCoding.cn

天地之间有杆秤,拿秤砣砸老百姓。

Lucene源码分析笔记之[org.apache.lucene.store](三)

Directory类系

综述:Directory类系可以被理解成是一个文件夹,它提供些对文件夹内容及本身的一些操作。比如:

1.建立/读取/删除/重命名文件;
2.复制文件夹;
3.查寻是否存在某文件;
4.设置/获取某文件最后访问时间;
5.查寻文件夹大小;
6.查看文件列表

1Directory类系层次图

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

MMapDirectoryFSDirectory的子类,它重写了FSDirectoryopenInput()方法。他们的区别是,在读取文件时,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

RAMDirectoryFSDirectory不同,它是基于内存的。它在内存中划出一个区域,用来存放文件,在性能上肯定要比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(01); // 睡 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); // 返回该文件的写通道
    }

 

posted on 2008-11-17 19:30 Rolandz 阅读(1289) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航:
 

导航

统计

留言簿(1)

随笔分类(12)

随笔档案(19)

积分与排名

最新评论

阅读排行榜

评论排行榜