Directory類系
綜述:Directory類系可以被理解成是一個(gè)文件夾,它提供些對(duì)文件夾內(nèi)容及本身的一些操作。比如:
1.建立/讀取/刪除/重命名文件;
2.復(fù)制文件夾;
3.查尋是否存在某文件;
4.設(shè)置/獲取某文件最后訪問時(shí)間;
5.查尋文件夾大小;
6.查看文件列表
1.Directory類系層次圖

2. 部分代碼說明
Directory類
Directory是所有文件夾類的父類。它規(guī)定了所有子類必須提供的操作,但它本身只實(shí)現(xiàn)了部分,其中比較重要的就是文件夾間的拷貝操作copy()方法。
1
public static void copy(Directory src, Directory dest, boolean closeDirSrc)
2
throws IOException
{ // 文件夾之間的的復(fù)制
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++)
{ // 對(duì)每個(gè)文件進(jìn)行復(fù)制操作
11
IndexOutput os = null; // 寫通道
12
IndexInput is = null; // 讀通道
13
try
{
14
// create file in dest directory
15
os = dest.createOutput(files[i]); // 創(chuàng)建對(duì)file[i]的寫通道
16
// read current file
17
is = src.openInput(files[i]); // 讀通道
18
// and copy to dest directory
19
long len = is.length(); // 文件總長(zhǎng)度
20
long readCount = 0; // 已讀取長(zhǎng)度
21
while (readCount < len)
{ // 循環(huán)讀取文件數(shù)據(jù)
22
int toRead = readCount + BufferedIndexOutput.BUFFER_SIZE > len ? (int) (len - readCount)
23
: BufferedIndexOutput.BUFFER_SIZE; // 實(shí)際一次讀取長(zhǎng)度
24
is.readBytes(buf, 0, toRead); // 讀取
25
os.writeBytes(buf, toRead); // 寫入
26
readCount += toRead; // 記錄已寫入數(shù)量
27
}
28
} finally
{ // 關(guān)閉操作
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中最重要的實(shí)例生成方法就是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()) // 試圖創(chuàng)建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(); // 創(chuàng)建一個(gè)新實(shí)例
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實(shí)例的方法,只能內(nèi)部調(diào)用。
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(""))
{ // 系統(tǒng)設(shè)置了默認(rèn)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(); // 實(shí)例化系統(tǒng)默認(rèn)的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)
{ // 根據(jù)lockFactory的類型各自調(diào)用setLockDir()
49
((NativeFSLockFactory) lockFactory).setLockDir(path);
50
} else if (lockFactory instanceof SimpleFSLockFactory)
{
51
((SimpleFSLockFactory) lockFactory).setLockDir(path);
52
}
53
} else
{ // 使用lucene默認(rèn)的lockFactory: SimpleFSLockFactory
54
// Our default lock is SimpleFSLockFactory;
55
// default lockDir is our index directory:
56
lockFactory = new SimpleFSLockFactory(path);
57
doClearLockID = true; // 設(shè)置為true, 不懂!!!!!!
58
}
59
}
60
}
61
62
setLockFactory(lockFactory); // 設(shè)置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()方法。他們的區(qū)別是,在讀取文件時(shí),FSDirectory在底層用BufferedIndexInput(把文件部分讀入內(nèi)存),而MMapDirectory則用MMapDirectory/MultiMMapDirectory(把文件一次性全部讀入內(nèi)存)。
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
{ // 根據(jù)文件的大小選擇適當(dāng)?shù)腎ndexInput
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不同,它是基于內(nèi)存的。它在內(nèi)存中劃出一個(gè)區(qū)域,用來存放文件,在性能上肯定要比FSDirectory快的多。當(dāng)然它也有它的局限性,比如,文件過大,內(nèi)存小放不下,呵呵。
RAMDirectory里定義了變量:HashMap fileMap = new HashMap()用來存放文件名及與之對(duì)應(yīng)得文件在內(nèi)存中的指針。還有一個(gè)變量long sizeInBytes:文件夾總字節(jié)數(shù)。
當(dāng)通過Directory來創(chuàng)建RAMDirectory時(shí),RAMDirectory需要把Directory中的數(shù)據(jù)拷貝到RAMDirectory中來。
1
private RAMDirectory(Directory dir, boolean closeDir) throws IOException
{
2
this();
3
Directory.copy(dir, this, closeDir); // 拷貝數(shù)據(jù)
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; // 返回文件名數(shù)組
11
}
在查詢某文件是否存在時(shí),只需要到fileMap中看下對(duì)應(yīng)的文件名是否存在。
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)功能是修改給定文件名的文件的最近修改時(shí)間。方法本身并不是同步方法,因此在方法體內(nèi)部需要考慮同步的問題。
1
public void touchFile(String name) throws IOException
{
2
// 修設(shè)置最近修改時(shí)間為當(dāng)前時(shí)間
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
{ // 這個(gè)循環(huán)的用意是什么?????有人告訴我不????
13
try
{
14
Thread.sleep(0, 1); // 睡 1ns
15
} catch (InterruptedException e)
{
16
}
17
ts2 = System.currentTimeMillis(); // 獲取當(dāng)前時(shí)間
18
} while (ts1 == ts2);
19
20
file.setLastModified(ts2); // 同步修改最近修改時(shí)間
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中刪除此文件,也就是刪掉該文件的相關(guān)記錄:名字和buffer地址
6
file.directory = null; // 設(shè)置file的所屬文件夾為null,即它不再屬于任何文件夾
7
sizeInBytes -= file.sizeInBytes; // updates to RAMFile.sizeInBytes synchronized on directory
8
} else
9
throw new FileNotFoundException(name);
10
}
createOutput()創(chuàng)建一個(gè)新文件并返回其寫通道。若同名文件已存在,則刪除之。

public IndexOutput createOutput(String name) throws IOException
{ // 新建給定名字的文件并返回它的寫通道
ensureOpen(); // 確保fileMap不為null
RAMFile file = new RAMFile(this); // 創(chuàng)建一個(gè)內(nèi)存文件,參數(shù)為當(dāng)前文件夾

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

if (existing != null)
{ // 存在同名文件,則刪除之
sizeInBytes -= existing.sizeInBytes; // 更改文件夾大小
existing.directory = null; // 設(shè)置其directory為null
}
fileMap.put(name, file);
}
return new RAMOutputStream(file); // 返回該文件的寫通道
}