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); // 返回该文件的写通道
}