2008年2月22日
#
1 . 用Executors構(gòu)造一個新的線程池
ExecutorService executor = Executors.newCachedThreadPool();
方法 newCachedThreadPool();
創(chuàng)建一個可根據(jù)需要創(chuàng)建新線程的線程池,但是在以前構(gòu)造的線程可用時將重用它們,并在需要時使用提供的 ThreadFactory 創(chuàng)建新線程。
2. 用構(gòu)造的線程池創(chuàng)建ExecutorFilter
ExecutorFilter es= new ExecutorFilter(executor));

在ExecutorFilter內(nèi)部:
只需要將相應(yīng)的事件分發(fā)到到線程池的相應(yīng)線程即可,但是SessionCreated事件只能在主線程中,不能分發(fā)
觸發(fā)方法
1 .
首先構(gòu)造一個IoFilterEvent,這個IoFilterEvent包含1、事件的類型,2、下一個過濾器
然后觸發(fā)該時間的處理方法。

if (eventTypes.contains(IoEventType.SESSION_OPENED))
{
fireEvent(new IoFilterEvent(nextFilter, IoEventType.SESSION_OPENED,
session, null));
}
2 .
從線程池中取出一個線程執(zhí)行事件處理

protected void fireEvent(IoFilterEvent event)
{
getExecutor().execute(event);
}
在構(gòu)造ExecutorFilter 時如果沒有傳入IoEventType則默認(rèn)只對如下幾種幾件感興趣
EXCEPTION_CAUGHT
MESSAGE_RECEIVED
MESSAGE_SENT
SESSION_CLOSED
SESSION_IDLE
SESSION_OPENED
當(dāng)然還需要覆蓋相應(yīng)的事件處理方法 如上所示
參數(shù)db_block_size;
這個參數(shù)只能設(shè)置成底層操作系統(tǒng)物理塊大小的整數(shù)倍,最好是2的n次方倍。
如WINDOWS下4KB,8KB,16KB
且該參數(shù)需要在建庫的時候指定,一旦指定不能更改。
雖然在ORACLE9I以上可以指定表空間的數(shù)據(jù)庫大小,允許同時使用包括非默認(rèn)大小在內(nèi)的數(shù)據(jù)庫塊大小。不過需要設(shè)置指定大小數(shù)據(jù)塊的buffer_cache.
小的塊:
小的塊降低塊競爭,因為每個塊中的行較少.
小的塊對于小的行有益.
小的塊對于隨意的訪問較好.如果一個塊不太可能在讀入內(nèi)存后被修改,那么塊的大小越小使用buffer cache越有效率。當(dāng)內(nèi)存資源很珍貴時尤為重要,因為數(shù)據(jù)庫的buffer cache是被限制大小的。
劣勢:
小塊的管理消費相對大.
因為行的大小你可能只在塊中存儲很小數(shù)目的行,這可能導(dǎo)致額外的I/O。
小塊可能導(dǎo)致更多的索引塊被讀取
大的塊
好處:
更少的管理消費和更多存儲數(shù)據(jù)的空間.
大塊對于有順序的讀取較好. 譬如說全表掃描
大塊對很大的行較好
大塊改進(jìn)了索引讀取的性能.大的塊可以在一個塊中容納更多的索引條目,降低了大的索引級的數(shù)量.越少的index level意味著在遍歷索引分支的時候越少的I/O。
劣勢:
大塊不適合在OLTP中用作索引塊,因為它們增加了在索引葉塊上的塊競爭。
如果你是隨意的訪問小的行并有大的塊,buffer cache就被浪費了。例如,8 KB的block size 和50 byte row size,你浪費了7,950
將進(jìn)酒 杯莫停 -------> 亭名: 悲默亭
全球通史
《詩經(jīng)·采薇》
昔我往矣,楊柳依依 今我來思,雨雪霏霏
摘要: <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance...
閱讀全文
在搜索引擎中,切詞語是一個重要的部分,其中包括專有名詞的提取、詞的分割、詞的格式化等等。
TokenStream 類幾乎是所有這些類的基類
有兩個需要被子類實現(xiàn)的方法Token next() 和 close()
首先來看analysis包,這個包主要是提供一些簡單的詞匯化處理
以Tokenizer結(jié)尾的類是將要處理的字符串進(jìn)行分割成Token流,而根據(jù)分割的依據(jù)的又產(chǎn)生了以下幾個Tokenizer類
首先Tokenizer類是所有以Tokenizer結(jié)尾的類的基類
然后是CharTokenizer,所有的以Tokenizer結(jié)尾的類都是從這個類繼承的
這個類中有一個抽象方法
protected abstract boolean isTokenChar(char c);
另外一個需要被子類覆寫的方法
protected char normalize(char c) {};
是對單個字符進(jìn)行處理的方法譬如說將英文字母全部轉(zhuǎn)化為小寫
還有一個變量
protected Reader input;
這個讀取器是這些類所處理的數(shù)據(jù)的 數(shù)據(jù)源
輸入一個Reader ,產(chǎn)生一個Token流
這個方法是是否進(jìn)行切分的依據(jù),依次讀取char流,然后用這個方法對每個char進(jìn)行檢測,如果返回false則將預(yù)先存儲在
詞匯緩沖區(qū)中的char數(shù)組作為一個Token返回
LetterTokenizer :
protected boolean isTokenChar(char c) {
return Character.isLetter(c);
}
WhitespaceTokenizer:
protected boolean isTokenChar(char c) {
return !Character.isWhitespace(c);
}
LowerCaseTokenizer extends LetterTokenizer:
protected char normalize(char c) {
return Character.toLowerCase(c);
}
在構(gòu)造函數(shù)中調(diào)用super(in);進(jìn)行和 LetterTokenizer同樣的操作,但是在詞匯化之前所有的詞都轉(zhuǎn)化為小寫了
然后是以Filter結(jié)尾的類,這個類簇主要是對已經(jīng)詞匯化的Token流進(jìn)行進(jìn)一步的處理
輸入是Token流 , 輸出仍然是Token流。
TokenFilter extends TokenStream 是所有這些類的父類
protected TokenStream input;
在TokenFilter 中有一個TokenStream 變量,是Filter類簇處理的數(shù)據(jù)源,而Filter類簇又是繼承了TokenStream 類的
有一個public final Token next()方法,這個方法以TokenStream.next()產(chǎn)生的Token流 為處理源,產(chǎn)生的仍然是Token流
只不過中間有一些處理的過程
LowerCaseFilter:將所有的Token流的轉(zhuǎn)化為小寫
t.termText = t.termText.toLowerCase();
StopFilter:過濾掉一些停止詞,這些停止詞由構(gòu)造函數(shù)指定
for (Token token = input.next(); token != null; token = input.next())
if (!stopWords.contains(token.termText))
return token;
比較一下Tokenizer類簇和Filter類簇,可以知道
Tokenizer類簇主要是對輸入的Reader流,實際上是字符流按照一定的規(guī)則進(jìn)行分割,產(chǎn)生出Token流
其輸入是字符串的Reader流形式,輸出是Token流
Filter類簇主要是對輸入的Token流進(jìn)行更進(jìn)一步的處理,如去除停止詞,轉(zhuǎn)化為小寫
主要為一些格式化操作。
由于Filter類簇的輸入輸出相同,所以可以嵌套幾個不同的Filter類,以達(dá)到預(yù)期的處理目的。
前一個Filter類的輸出作為后一個Filter類的輸入
而Tokenizer類簇由于輸入輸出不同,所以不能嵌套
在JAVA JDK1.5以后具有的自動裝箱與拆箱的功能,所謂的自動裝箱
與拆箱也就是把基本的數(shù)據(jù)類型自動的轉(zhuǎn)為封裝類型。
如:自動裝箱,它可以直接把基本類型賦值給封裝類型
Integer num = 10 ;
Double d = 2d ;
自動拆箱,它可以把封裝類型賦值給基本類型
int num = new Integer(10);
double d = new Double(2d);
自動裝箱與拆箱的功能事實上是編譯器來幫您的忙,編譯器在編譯時期依您所編寫的語法,決定是否進(jìn)行裝箱或拆箱動作。在自動裝箱時對于值從-128到127之間的值,它們被裝箱為Integer對象后,會存在內(nèi)存中被重用,所以范例4.6中使用==進(jìn)行比較時,i1 與 i2實際上參考至同一個對象。如果超過了從-128到127之間的值,被裝箱后的Integer對象并不會被重用,即相當(dāng)于每次裝箱時都新建一個Integer對象,所以范例4.7使用==進(jìn)行比較時,i1與i2參考的是不同的對象。所以不要過分依賴自動裝箱與拆箱,您還是必須知道基本數(shù)據(jù)類型與對象的差異。
public void testBoxingUnboxing() {
int i = 10;
Integer inta = i;
inta++;
inta += 1;
int j = inta;
assertTrue(j == inta);結(jié)果是:true//junit里面的方法
assertTrue(j == new Integer(j)); 結(jié)果是:true
assertTrue(10000 == new Integer(10000)); 結(jié)果是:true
}
Integer i = 100.相當(dāng)于編譯器自動為您作以下的語法編譯:
Integer i = new Integer(100).所以自動裝箱與拆箱的功能是所謂的“編譯器蜜糖”(Compiler Sugar),雖然使用這個功能很方便,但在程序運行階段您得了解Java的語義。例如下面的程序是可以通過編譯的:
Integer i = null.int j = i.這樣的語法在編譯時期是合法的,但是在運行時期會有錯誤,因為這種寫法相當(dāng)于:
Integer i = null.int j = i.intValue().null表示i沒有參考至任何的對象實體,它可以合法地指定給對象參考名稱。由于實際上i并沒有參考至任何的對象,所以也就不可能操作intValue()方法,這樣上面的寫法在運行時會出現(xiàn)NullPointerException錯誤。
自動裝箱、拆箱的功能提供了方便性,但隱藏了一些細(xì)節(jié),所以必須小心。再來看范例4.6,您認(rèn)為結(jié)果是什么呢?
Ü. 范例4.6 AutoBoxDemo2.java
public class AutoBoxDemo2 {
public static void main(String[] args) {
Integer i1 = 100;
Integer i2 = 100;
if (i1 == i2)
System.out.println("i1 == i2");
else
System.out.println("i1 != i2").
}
}
從自動裝箱與拆箱的機制來看,可能會覺得結(jié)果是顯示i1 == i2,您是對的。那么范例4.7的這個程序,您覺得結(jié)果是什么?
Ü. 范例4.7 AutoBoxDemo3.java
public class AutoBoxDemo3 {
public static void main(String[] args) {
Integer i1 = 200;
Integer i2 = 200;
if (i1 == i2)
System.out.println("i1 == i2");
else
System.out.println("i1 != i2");
}
}
結(jié)果是顯示i1 != i2,這有些令人驚訝,兩個范例語法完全一樣,只不過改個數(shù)值而已,結(jié)果卻相反。
其實這與==運算符的比較有關(guān),在第3章中介紹過==是用來比較兩個基本數(shù)據(jù)類型的變量值是否相等,事實上==也用于判斷兩個對象引用名稱是否參考至同一個對象。
在自動裝箱時對于值從–128到127之間的值,它們被裝箱為Integer對象后,會存在內(nèi)存中被重用,所以范例4.6中使用==進(jìn)行比較時,i1 與 i2實際上參考至同一個對象。如果超過了從–128到127之間的值,被裝箱后的Integer對象并不會被重用,即相當(dāng)于每次裝箱時都新建一個Integer對象,所以范例4.7使用==進(jìn)行比較時,i1與i2參考的是不同的對象。
所以不要過分依賴自動裝箱與拆箱,您還是必須知道基本數(shù)據(jù)類型與對象的差異。范例4.7最好還是依正規(guī)的方式來寫,而不是依賴編譯器蜜糖(Compiler Sugar)。例如范例4.7必須改寫為范例4.8才是正確的。
Ü. 范例4.8 AutoBoxDemo4.java
public class AutoBoxDemo4 {
public static void main(String[] args) {
Integer i1 = 200;
Integer i2 = 200;
if (i1.equals(i2))
System.out.println("i1 == i2");
else
System.out.println("i1 != i2");
}
}
結(jié)果這次是顯示i1 == i2。使用這樣的寫法,相信也會比較放心一些,對于這些方便但隱藏細(xì)節(jié)的功能到底要不要用呢?基本上只有一個原則:如果您不確定就不要用。
在IndexWriter中有3個重要的性能參數(shù)
mergeFactor 默認(rèn)為10
minMergeDocs 默認(rèn)為10
maxMergeDocs 默認(rèn)為Integer.maxValue
maxMergeDocs 一個段中所能包含的最大的doc數(shù),達(dá)到這個數(shù)目即不再將段進(jìn)行合并 一般不改變這個值
minMergeDocs 是指在RAMDirectory中保存的Doc的個數(shù),達(dá)到minMergeDocs 個即要合并到硬盤上去(在硬盤上新建一個段)
mergeFactor 合并因子,是控制硬盤上的段的合并的,每次在硬盤上新建一個段之后即執(zhí)行
targetMergeDocs*=mergeFactor(一開始targetMergeDocs=minMergeDocs) 如果硬盤上的doc數(shù)目大于等于 targetMergeDocs則將硬盤上最后建立的mergeFactor個段進(jìn)行合并成一個段
拿默認(rèn)的參數(shù)舉例:
如果硬盤上面已經(jīng)有9個段 每個段分別存儲了10個Document,共(90個DOC),這時候如果程序再向硬盤合并一個新的段(含10個DOC),合并完之后targetMergeDocs=10*10 程序檢查已經(jīng)合并的最后(按照創(chuàng)建的時間先后順序)mergeFactor個段的document的總和100是否大于等于targetMergeDocs(這里是100,剛好滿足要求)于是程序又將硬盤上面的后10個段合并為一個新的段。
另外一個例子:
doc數(shù)目 段數(shù)目
1000---------------9個
100-----------------9個
10 ----------------9個
這時如果再象硬盤中新建一個新的包含了10個doc的段
doc數(shù)目 段數(shù)目
(1) 1000----------------9個
(2) 100-----------------9個
(3) 10 ----------------9個
(4) 10 ----------------1個
這時候(3)(4)首先合并成一個新的段(3-4)包含100個doc
然后(2)(3-4)和并成一個新段(2-3-4)包含1000個doc
然后(1)(2-3-4)合并成一個新的段 包含10000個doc
最后合并成一個段

private final void maybeMergeSegments() throws IOException
{
long targetMergeDocs = minMergeDocs;

while (targetMergeDocs <= maxMergeDocs)
{
// find segments smaller than current target size
int minSegment = segmentInfos.size();
int mergeDocs = 0;

while (--minSegment >= 0)
{
SegmentInfo si = segmentInfos.info(minSegment);
if (si.docCount >= targetMergeDocs)
break;
mergeDocs += si.docCount;
}

if (mergeDocs >= targetMergeDocs) // found a merge to do
mergeSegments(minSegment+1);
else
break;

targetMergeDocs *= mergeFactor; // increase target size
System.out.println("- -- - -targetMergeDocs:"+targetMergeDocs);

try
{Thread.sleep(5000);} catch(Exception e)
{};
}
}
HIBERNATE一多對關(guān)聯(lián)中 要求在持久化類中定義集合類屬性時,必須把屬性聲明為接口,因為HIBERNATE在調(diào)用持久化類的SET/GET方法時傳遞的是HIBERNATE自己定義的集合類。
在定義集合時,一般先初始化為集合實現(xiàn)類的一個實例 : private Set orders=new HashSet(),這樣可以避免訪問空集合出現(xiàn)NullPointerException.
segments文件的格式: (段的信息)
int: =-1 查看文件是否是Lucene合法的文件格式
long: 版本號,每更新一次該文件將會將版本號加1
int: 用來命名新段
int: 段的數(shù)目
String + int 段的信息 String是段的名稱 int是段中所含的doc數(shù)目
String + int 同上
.fnm的文件格式: (Field的信息)
int: Field的個數(shù),最少為1,最少有一個Field("",false),在初始化的時候?qū)懭?暫時不知道原因); 名稱為空字符串,未索引, 未 向 量化。readVInt()讀取
String: byte String是 Field的名稱 byte指示該Field 是否被索引,是否向量化 (值有:11,10,01)第一個1代表被索引,第二個代表被向量化
String: byte Field 同上
.fdx的文件格式:主要是提供對.fdt中存儲的document的隨即讀取
long : 第一個document在.fdt文件中的位置
long: 第二個document在.fdt文件中的位置
.fdt的文件格式: .fdt文件存儲了一系列document的信息
VInt: 該document中的isStored屬性為true的域的個數(shù)
(VInt:) 如果該field的isStored屬性為true則得到該field的fieldNumber,暫時不知道這個fieldNumber是怎么產(chǎn)生的,有什么用,初步估計是按照field創(chuàng)建的順序產(chǎn)生的,每次再上一個field的fieldNumber基礎(chǔ)上加1。
byte: 如果該field的isTokenized屬性為true寫入1否則寫入false。
String: 該field的stringValue()值。
一個document結(jié)束,下面的數(shù)據(jù)將會開始一個新的document,每個新的document的開始點的文件位置都會在.fdx中有記載,便于隨即訪問
final class SegmentInfos extends Vector
可以看出該類實際上是一個Vector 以及封裝了對該Vevtor的一些操作
實際上封裝的是對segments文件的一些讀寫操作
先來看下segments文件的格式
segments文件的格式:
int: =-1 文件是否是Lucene合法的文件格式正常情況下為 -1
long: 版本號,每更新一次該文件將會將版本號加1
int: 用來命名新段
int: 段的數(shù)目
String + int 段的信息 String是段的名稱 int是段中所含的doc數(shù)目
String + int 同上
所以用Lucene的API,我們可以簡單的打印出其segments的所有信息
try {
//DataInputStream fis = new DataInputStream(new FileInputStream("C:\\sf\\snow\\segments"));
FSDirectory dir=FSDirectory.getDirectory("C:/sf/snow", false);
InputStream input = dir.openFile("segments");
System.out.println("Format:"+input.readInt()); //得到文件標(biāo)志,是否為正常的segments文件
System.out.println("version:"+input.readLong()); //得到版本號
System.out.println("name:"+input.readInt()); //得到用來重命名新段的int,暫時不知道有什么用
int n=input.readInt(); //段的數(shù)目
System.out.println("SegmentNum:"+n);
for(int i=0;i<n;i++) { //用循環(huán)打印出所有段的信息 名稱和長度
System.out.println("segment "+i+" - name:"+input.readString()+" num:"+input.readInt());
}
} catch (Exception e) {
}
當(dāng)然,該類提供了更為復(fù)雜的訪問和更新segments文件的方法
final void read(Directory directory) 將所有的段信息保存在本vector中
final void write(Directory directory) 跟新該segment文件的內(nèi)容,主要是為了添加段,
主要是更新 版本號 段的數(shù)目,跟新完這些后即可往segment文件后添加新段的信息。
segment(段)的信息
該類比較簡單,貼出其全部代碼
import org.apache.lucene.store.Directory;
final class SegmentInfo {
public String name; //在索引目錄中唯一的名稱
public int docCount; // 該段中doc的數(shù)目
public Directory dir; // 該段所存在的Dirrectory
public SegmentInfo(String name, int docCount, Directory dir) {
this.name = name;
this.docCount = docCount;
this.dir = dir;
}
}
該類是從RAMFile中讀數(shù)據(jù)用的
最重要的一個方法:
該方法存在著從RAMFile的多個byte[1024]中讀取數(shù)據(jù)的情況,所以應(yīng)該在循環(huán)中進(jìn)行處理
public void readInternal(byte[] dest, int destOffset, int len) {
int remainder = len;
int start = pointer;
while (remainder != 0) {
int bufferNumber = start/BUFFER_SIZE; // buffer的序號
int bufferOffset = start%BUFFER_SIZE; // buffer偏移量
int bytesInBuffer = BUFFER_SIZE - bufferOffset;// 在當(dāng)前buffer中剩下的字節(jié)數(shù)
//如果緩沖區(qū)中剩余的字節(jié)大于len,則讀出len長度的字節(jié),如果不夠則讀出剩余的字節(jié)數(shù)
// bytesToCopy表示實際讀出的字節(jié)數(shù)
int bytesToCopy = bytesInBuffer >= remainder ? remainder : bytesInBuffer;
byte[] buffer = (byte[])file.buffers.elementAt(bufferNumber);
System.arraycopy(buffer, bufferOffset, dest, destOffset, bytesToCopy);
destOffset += bytesToCopy; //增加已經(jīng)復(fù)制的byte數(shù)據(jù)長度 到 dest中的偏移量
start += bytesToCopy; //RAMFile文件指針,用來確定bufferNumber 和bytesInBuffer 相當(dāng)于內(nèi)存中的分頁
remainder -= bytesToCopy; //剩余的還未復(fù)制的字節(jié)數(shù)
}
pointer += len;//文件指針位置
}
這是OutputStream的一個子類,其輸出設(shè)備是內(nèi)存,準(zhǔn)確來說是RAMFile,即將數(shù)據(jù)寫入到RAMFile的Vector中去。
該類有一個最重要的方法,現(xiàn)在把它整個貼出來
public void flushBuffer(byte[] src, int len) {
int bufferNumber = pointer/BUFFER_SIZE; //buffer序列,即當(dāng)前所寫B(tài)uffer在RAMFile中的Vector中的序列號
int bufferOffset = pointer%BUFFER_SIZE; //偏移量,即當(dāng)前所寫字節(jié)在當(dāng)前Buffer中的偏移量。
int bytesInBuffer = BUFFER_SIZE - bufferOffset; //當(dāng)前Buffer的剩余可寫字節(jié)數(shù)
//bytesToCopy是實際寫入的字節(jié)數(shù),如果當(dāng)前Bufer的剩余字節(jié)數(shù)大于需要寫的字節(jié)的總數(shù)則寫入所有字節(jié)
//否則,將當(dāng)前Buffer寫滿即可,剩余的字節(jié)將寫入下一個Buffer
int bytesToCopy = bytesInBuffer >= len ? len : bytesInBuffer;
if (bufferNumber == file.buffers.size())
file.buffers.addElement(new byte[BUFFER_SIZE]); //在RAMFile中添加新的byte[1024]元素
byte[] buffer = (byte[])file.buffers.elementAt(bufferNumber);
System.arraycopy(src, 0, buffer, bufferOffset, bytesToCopy);
if (bytesToCopy < len) { // not all in one buffer,
int srcOffset = bytesToCopy;
bytesToCopy = len - bytesToCopy; // remaining bytes 剩余的未寫入的字節(jié)數(shù)
bufferNumber++; //將buffer數(shù)增加1
if (bufferNumber == file.buffers.size())
file.buffers.addElement(new byte[BUFFER_SIZE]);
buffer = (byte[])file.buffers.elementAt(bufferNumber); //剩余字節(jié)寫入下一個Buffer
System.arraycopy(src, srcOffset, buffer, 0, bytesToCopy);
}
pointer += len;
if (pointer > file.length)
file.length = pointer; //移位文件指針 在原有的基礎(chǔ)上加上實際寫入的字節(jié)總數(shù)
file.lastModified = System.currentTimeMillis(); //修改文件的最后修改時間為當(dāng)前時間
}
從指定的字節(jié)數(shù)組復(fù)制指定長度的字節(jié)到RAMFile中去。由于RAMFile中Vector的元素是byte[1024]所以可能存在做一次該操作
要操作兩個Vector元素的情況。即先將當(dāng)前byte[1024]數(shù)組填滿,再新建一個元素裝載剩余的字節(jié)。
另外還有一個writeTo(OutputStream out)方法,將RAMFile中的數(shù)據(jù)輸出到另一個輸出流
這個類比較簡單
import java.util.Vector;
class RAMFile {
Vector buffers = new Vector();
long length;
long lastModified = System.currentTimeMillis();
}
可以理解為一個存儲在內(nèi)存中的文件,buffers是存儲數(shù)據(jù)的容器,length是容器中數(shù)據(jù)的總的字節(jié)數(shù)
lastModified 是最后修改時間。
在實際使用過程中容器buffers存放的對象是一個byte[1024]數(shù)組。
OutputStream
這是一個Abstract類,是Lucene自己的一個文件輸出流的基類
BUFFER_SIZE = 1024 緩沖區(qū) 大小為 1024bit
bufferStart = 0 文件位置指針
bufferPosition = 0 內(nèi)存緩沖區(qū)指針
public final void writeByte(byte b) throws IOException {
if (bufferPosition >= BUFFER_SIZE)
flush();
buffer[bufferPosition++] = b;
}
幾乎所有的寫入函數(shù)都要調(diào)用這個函數(shù),如果緩沖區(qū)的當(dāng)前容量已經(jīng)等于他的最大容量,則將緩沖區(qū)中的數(shù)據(jù)寫入文件。
public final void writeBytes(byte[] b, int length) throws IOException
批量寫byte進(jìn)入內(nèi)存緩沖
public final void writeInt(int i) throws IOException
寫入整形數(shù)據(jù)
public final void writeLong(long i) throws IOException
寫入長整型數(shù)據(jù),即結(jié)合移位運算調(diào)用兩次writeInt(int i)
另外,最值得注意的是在該類中有兩個最特殊的函數(shù)
writeVInt(int i) / writeVLong(long i),
先說
writeVInt(int i ) {
while ((i & ~0x7F) != 0) {
writeByte((byte)((i & 0x7f) | 0x80));
i >>>= 7;
}
writeByte((byte)i);
}
~0x7F==~(0111 1111)==(1000 0000)==0x80
((i & ~0x7F) != 0) 這一句判斷i是否大于0x80,如果不是則說明該int只有一個字節(jié)的有效數(shù)據(jù),其他字節(jié)都是0,直接轉(zhuǎn)化為Byte寫入。
如果大于0x80則
(i & 0x7f) | 0x80
i&0x7f 只對后7位進(jìn)行處理,|0x80將第8位置1,與前面的7個bit構(gòu)成一個字節(jié),置1的原因是說明該字節(jié)并不是一個完整的整形數(shù),需要與其他的字節(jié)合起來才能構(gòu)成一個整形數(shù)字。
這個算法相當(dāng)于將一個32bit的整形數(shù)字按照每7位編碼成一個字節(jié)進(jìn)行存儲,將按照整形數(shù)的大小存儲1-5個字節(jié)。
writeVLong(long i)方法大致與其相同。
final void writeChars(String s, int start, int length)
將字符串轉(zhuǎn)化成UTF-8編碼的格式進(jìn)行存儲。
附:
UNICODE值 UTF-8編碼
U-00000000 - U-0000007F: 0xxxxxxx
U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
可見對于在 0x00-0x7F范圍內(nèi)的UNICODE值(最大有效數(shù)位:7位),將會編碼成單字節(jié)的,會大大節(jié)約存儲空間。
對于在 0x80-0x7FF范圍內(nèi)的UNICODE(最大有效數(shù)位:11位),會編碼成雙字節(jié)的。先存儲原字節(jié)低5位的數(shù)位,且將最高位和次高位都置1,再次高位置0(writeByte((byte)(0xC0 | (code >> 6)));)。然后存儲后6位的字節(jié),將前兩位置10(writeByte((byte)(0x80 | (code & 0x3F)));)
對于其他的UNICODE值則
writeByte((byte)(0xE0 | (code >>> 12))); 4位
writeByte((byte)(0x80 | ((code >> 6) & 0x3F))); 5位
writeByte((byte)(0x80 | (code & 0x3F))); 3- 5位
final void writeString(String s) throws IOException
該函數(shù)首先用s.length()判斷該String總共有多少個字符
然后首先調(diào)用writeVInt寫入這個字符長度
再調(diào)用writeChars(s,s.length())寫入字符
在inputStream中的readString()方法則與其相反,首先用readVInt()方法讀取字符長度len 然后讀取len長度的字符
protected final void flush() throws IOException
該方法調(diào)用另外一個方法flushBuffer將緩沖區(qū)中的數(shù)據(jù)輸出,然后清空緩沖區(qū);
abstract void flushBuffer(byte[] b, int len) throws IOException
可見flushBuffer方法是abstract的,即需要其子類對該方法進(jìn)行覆寫,以定位該輸出流的輸出方式。
final long getFilePointer() throws IOException
得到文件指針的位置,即得到輸出流已經(jīng)輸出的字節(jié)數(shù)。
public void seek(long pos) throws IOException
輸出緩沖區(qū)的內(nèi)容,然后將文件指針定位到long所指示的文件位置。
abstract long length() throws IOException
返回文件中已有的字節(jié)數(shù)。需要子類實現(xiàn)。
FSDirectory繼承了abstract類Directory
在該類中既有該類的一些初始化操作,又有對FSDirectory對象本身的一些操作,這是為什么把其構(gòu)造函數(shù)設(shè)置為私有的一部分原因
static final Hashtable DIRECTORIES = new Hashtable();
每新建一個FSDirectory都會將其加入到該Hashtable中來。名稱是FSDirectory對應(yīng)的File 值是該FSDirectory。
注意:final對象并非是不可更改的
static final String LOCK_DIR =
System.getProperty("org.apache.lucene.lockdir",
System.getProperty("java.io.tmpdir"));
首先看用戶是否注冊了"org.apache.lucene.lockdir"屬性,如果沒有則用JAVA虛擬機固有的"java.io.tmpdir"屬性
這個屬性是一個路徑,代表lucene的鎖文件鎖放的位置。
static final boolean DISABLE_LOCKS =
Boolean.getBoolean("disableLuceneLocks") || Constants.JAVA_1_1;
如果用戶注冊了"disableLuceneLocks"屬性且為false,或者JAVA的版本是1.1則無法使用鎖。
static FSDirectory getDirectory(String path, boolean create)
static FSDirectory getDirectory(File file, boolean create)
從得到一個指定路徑或者文件的FSDirectory如果在則取出,如果不存在則用其私有的構(gòu)造函數(shù)構(gòu)造一個
該類還有3個非static的類變量
private File directory = null; 索引目錄
private int refCount; 鎖目錄
private File lockDir; 索引目錄數(shù)目
實際上,初始化一個FSDirectory只需要初始化這3個變量即可
如果create的值為true 則:如果索引目錄是已經(jīng)存在的目錄,則會遍歷該目錄然后刪除每一個文件,如果鎖目錄是已存在的也會用list返回所有的文件然后調(diào)用file.delete() 刪除。 如果目錄不存在則創(chuàng)建一個新的。
注意:list()方法 會先用文件名進(jìn)行排序然后返回(a.txt會比b.txt先返回) 且delete方法刪除文件夾時,只能刪除空文件夾。如果失敗則跳出程序,不會刪除在該文件夾之后返回的文件。(如果有aa.txt , ab/b.txt , b.txt , 則刪除時候由于a文件夾非空刪除失敗,則b.txt由于前面刪除失敗跳出程序,也不會被刪除,但是aa.txt被正常刪除)
private FSDirectory(File path, boolean create) throws IOException
私有的構(gòu)造函數(shù)
private synchronized void create() throws IOException
創(chuàng)建新的directory /lockDir目錄,當(dāng)目錄已存在時即清空該目錄,不存在即創(chuàng)建新的目錄。
final String[] list() throws IOException
以字符串文件名的形式返回索引目錄的所有文件
final boolean fileExists(String name) throws IOException
在索引目錄是否存在指定文件名的文件
final long fileModified(String name) throws IOException
static final long fileModified(File directory, String name)
返回該文件的最后修改時間,directory參數(shù)為相對路徑,第一個函數(shù)的相對路徑為索引目錄
void touchFile(String name) throws IOException
將該文件的最后修改時間設(shè)置為當(dāng)前時間
final long fileLength(String name) throws IOException
返回該文件的長度
final void deleteFile(String name) throws IOException
刪除該文件
final synchronized void renameFile(String from, String to) throws IOException
重命名該文件
該方法會首先檢測新的文件名命名的文件是否已經(jīng)存在如果存在即刪除該文件,然后再將文件重新命名為新的文件名。
doug cutting在該方法的注釋上寫到:
1.刪除操作和重命名的操作不是原子的。
2.重命名操作在有些虛擬機上面不能正確的工作,如果重命名失敗則會采用手動copy的方法。使用輸入輸出流將舊的文件的內(nèi)容寫入到新的文件中去,然后刪除舊的文件。
注意:該方法必須是同步的。
final OutputStream createFile(String name) throws IOException
用指定的文件名創(chuàng)建一個新的可寫的空文件 實際上返回的是FSOutputStream,注意這里的OutputStream并不是java的基礎(chǔ)類。而是doug cutting自己寫的一個文件隨即訪問類。同理FSInputStream和InputStream也是Lucene自己的類。
final InputStream openFile(String name) throws IOException
從一個存在的文件打開一個輸入流
getLockPrefix()
在FSDirectory中還有
private static MessageDigest DIGESTER;這個靜態(tài)變量是提供加密功能的
DIGESTER=MessageDigest.getInstance("MD5"),-----MD5加密算法
或者可以DIGESTER=MessageDigest.getInstance("SHA"),-----SHA加密算法
用于對鎖目錄的 文件名的加密
用法如下:
digest = DIGESTER.digest(dirName.getBytes()); dirName是需要被加密的字符串,這里是索引文件的目錄名,
在FSContext中,其應(yīng)用在 getLockPrefix() 該方法是為某個索引目錄創(chuàng)建其對應(yīng)的鎖目錄文件名。
首先返回經(jīng)過加密后的byte[] 數(shù)組digest,然后將digest按照每4個bit轉(zhuǎn)化為一個16進(jìn)制的字符,存進(jìn)一個StringBuffer中
其轉(zhuǎn)化類似與Base64編碼方式,不過要簡單得多。
方法
Lockl makeLock(String name)
是從Directory中擴展而來的,該方法返回一個Lock對象,該對象將會在介紹完Lucene的輸入輸出流之后介紹。
該方法比較簡單,首先是調(diào)用了getLockPrefix() 方法,返回文件鎖的部分對象名,然后在該名稱后面加上鎖的特征名
譬如說讀寫鎖 事務(wù)鎖
其名稱類似于下:
lucene-12c90c2c381bc7acbc4846b4ce97593b-write.lock
lucene-12c90c2c381bc7acbc4846b4ce97593b-commit.lock
這兩種鎖機制將會在后面介紹
最后通過一個匿名的內(nèi)部類返回一個經(jīng)過重載的Lock對象,該內(nèi)部類中的方法有鎖的創(chuàng)建,得到,釋放,以及檢測,另外還有一個toString()方法返回鎖的名稱。
在FSDirectory類中有OutputStream和InputStream的實現(xiàn)類,這兩個虛類只是定義了一些操作,并沒有定義輸入或者輸出的設(shè)備。
Lucene在輸入輸出的設(shè)計上,將會由子類定義輸入輸出的設(shè)備。
FSOutputStream
在FSOutputStream中有一個 RandomAccess File=new RandomAccessFile(path, "rw");
在對該輸出流的操作將用調(diào)用該file的相應(yīng)方法實現(xiàn)
最重要的
public final void flushBuffer(byte[] b, int size) throws IOException {
file.write(b, 0, size);
}
flushBuffer的調(diào)用將會將byte中的0--size范圍的數(shù)據(jù)寫入到文件path中去。
FSInputStream
最重要的
protected final void readInternal(byte[] b, int offset, int len)
throws IOException {
synchronized (file) {
long position = getFilePointer(); //得到該當(dāng)前文件指針
if (position != file.position) {
file.seek(position);
file.position = position;
}
int total = 0;
do {
//從文件中讀取指定長度的字節(jié)到字節(jié)數(shù)組
// 在其基類InputStream中的refill()方法 將會調(diào)用 readInternal(buffer, 0, bufferLength);首先從文件中讀取字節(jié)到緩沖數(shù)組。
// 在InputStream中每次讀取操作都會調(diào)用readInternal方法,或者通過refill()方法間接調(diào)用該方法。
int i = file.read(b, offset+total, len-total); //將文件中的數(shù)據(jù)讀到緩沖區(qū)
if (i == -1)
throw new IOException("read past EOF");
file.position += i;
total += i;
} while (total < len);
}
}
該類提供了日期和字符串之間的相互轉(zhuǎn)化,實際上是 long型和String型的相互轉(zhuǎn)化,轉(zhuǎn)化時用到了一個不常用的
Long.toString(long,int);方法。是按指定的方式對long型進(jìn)行轉(zhuǎn)化
第一個參數(shù)是要轉(zhuǎn)化的long,第二個參數(shù)是轉(zhuǎn)化時候的基數(shù),如果基數(shù)是10就相當(dāng)于方法Long.toString(long);
這里使用的參數(shù)是最大值,即36== 10個數(shù)字+26個英文字母。這樣轉(zhuǎn)化出來的字符串長度比較短,占用比較少的空間,
另外,在轉(zhuǎn)化時,統(tǒng)一了轉(zhuǎn)化后的字符串長度,如果不足9位(日期的long轉(zhuǎn)化后最高為9位,1970之后的日期可正確轉(zhuǎn)換),
統(tǒng)一長度后的字符串可以通過比較字符串來比較日期的大小。
日期轉(zhuǎn)化成的字符串類似于
0fev8eza3
本來應(yīng)該是fev8eza3 采取了不足9位補0的方法。
private static int DATE_LEN = Long.toString(1000L*365*24*60*60*1000,
Character.MAX_RADIX).length();
計算出從1970年開始后1000年的時間轉(zhuǎn)化為字符串后的長度,所有轉(zhuǎn)化后的時間都不應(yīng)超過這個長度,如果不足則在前面補0
可以通過字符串轉(zhuǎn)化為日期的函數(shù)計算出能表示的最大日期為
stringToTime("zzzzzzzzz");
打印出來是 Fri Apr 22 19:04:28 CST 5188
所以該函數(shù)能轉(zhuǎn)化的日期范圍為 1970-1-1~~5188-4-22
日期轉(zhuǎn)化為字符串
public static String timeToString(long time)
字符串轉(zhuǎn)化為日期
public static long stringToTime(String s)
實際上 函數(shù) LongToString(long i,int radix) 相當(dāng)于 先將i轉(zhuǎn)化為radix進(jìn)制的整數(shù),然后再用函數(shù)
LongToString(i)轉(zhuǎn)化為字符串。所以radix的值應(yīng)該在2--36之間如果不是 則按照10進(jìn)制計算。
Document是一些Field的集合,每個Field有一個名字和文本值,當(dāng)中的某些Field可能會隨著Documnet被存儲。這樣,每個Document應(yīng)該至少包含一個可以唯一標(biāo)示它的被存儲的Field
//Field集合
List fields = new Vector();
//增強因子,作用于該Document的所有Field
private float boost = 1.0f;
//向Document中添加Field
public final void add(Field field) {
fields.add(field);
}
//刪除指定名稱的第一個Field
public final void removeField(String name)
//刪除所有擁有指定名稱的Field
public final void removeFields(String name)
//得到指定名稱的第一個Field
public final Field getField(String name)
//以數(shù)組的形式返回指定名稱的所有Field
public final Field[] getFields(String name)
//得到所有Field的一個枚舉
public final Enumeration fields()
該類也重載了toString()方法
打印出所有Field的信息
package org.apache.lucene.document;
Field
是Document的一部分,每個Field有兩個部分組成 名字-值 對 名字是String 值 可以是String 和 Reader,如果是KeyWord類型的Field,那么值將不會被進(jìn)一步處理,像URL,Date等等。Field被存儲在Index中,以便于能以Hits的形式返回原有的Document
Field有3 個Boolean形的標(biāo)識
private boolean isStored = false; 被存儲
private boolean isIndexed = true; 被索引
private boolean isTokenized = true 被分割
通過調(diào)整這3個boolean的值,可以確定該Field的類型
Keyword true, true, false 一般存儲 URL DATE 等關(guān)鍵字
UnIndexed true, false, false 一般是隨HITS查詢結(jié)果一起返回的信息
Text true, true, true
UnStored false, true, true
另外,還有一個重載的toString方法 可以打印出該Field的類型
float boost = 1.0f; 增強因子,用于排序的評分,作用于擁有該域(field)的所有文檔(document)
TRANSACTION_NONE:
正式地講,TRANSACTION_NONE不是一個有效的事務(wù)級別。
根據(jù)java.sql Connection API文件,這個級別表示事務(wù)是
不被支持的,因此理論上說你不能使用TRANSACTION_NONE作
為一個自變量賦給Connection.setTransactionIsolation()
方法。事實上,雖然一些數(shù)據(jù)庫實施了這個事務(wù)級別,但是
Oracle9i卻沒有實施。
臟讀取(TRANSACTION_READ_UNCOMMITTE):
(允許的操作 讀-讀 讀-寫 寫-讀 (臟數(shù)據(jù),不可重復(fù)讀,虛讀) )
表示,這個事務(wù)級別
允許讀取臟數(shù)據(jù),什么是臟數(shù)據(jù)?就是指還沒有提交的數(shù)據(jù).
因為這個級別,是允許一個事務(wù)(A)讀取另一個事務(wù)(B)
還沒有提交的數(shù)據(jù).一旦事務(wù)B發(fā)生異常退出.而修改了的數(shù)據(jù)
卻還沒提交,或者新插入的數(shù)據(jù)和刪除了的數(shù)據(jù)都還沒有
提交,導(dǎo)致事務(wù)A拿到了一些臟數(shù)據(jù),或者錯誤數(shù)據(jù);
因此在這個事務(wù)級別里是會發(fā)生臟讀,重復(fù)讀,錯誤讀取;
禁止臟讀(TRANSACTION_READ_COMMITTED):
(允許的操作 讀-讀 讀-寫 (不可重復(fù)讀,虛讀))
在這個級別中,事務(wù)A
只能讀取一些提交的數(shù)據(jù),如事務(wù)B添加了一條記錄,但是
如果事務(wù)B沒有提交,那么事務(wù)A是讀不到的,所以該事務(wù)級別,
把臟讀給屏蔽掉了.---卻允許重復(fù)讀取,和錯誤讀取.
什么是重復(fù)讀取呢?譬如,事務(wù)A讀取了一個數(shù)據(jù),這個數(shù)據(jù)
的值為"helloworld",事務(wù)A準(zhǔn)備利用這個數(shù)據(jù)來更新一下
其他數(shù)據(jù),但這個時候事務(wù)B開始對這個數(shù)據(jù)進(jìn)行修改,并且
提交---"hello 無名氏",由于是已經(jīng)提交了,所以事務(wù)A是可以
看到這個數(shù)據(jù)的,當(dāng)事務(wù)A在沒提交事務(wù)之前,它想看下數(shù)據(jù)
是否正確,這個時候它發(fā)現(xiàn),新讀出的數(shù)據(jù)已經(jīng)和原來的數(shù)據(jù)
不一樣了(這就是重復(fù)讀取);
允許重復(fù)讀取(TRANSACTION_REPEATABLE_READ):
(允許的操作 讀-讀 讀-寫(僅允許插入,不允許刪除和修改)(虛讀))
在這個級別中,
是禁止了臟讀,和取消了不可重復(fù)讀取,但是沒有禁止錯誤讀取;
這個級別的事務(wù)比較嚴(yán)格,當(dāng)一個事務(wù)A在讀取一個值的時候
是不允許另一個事務(wù)對該值進(jìn)行修改的;
為了允許重復(fù)讀取,可以選用該級別,因為TRANSACTION_READ_
COMMITED這個事務(wù)級別,是允許重復(fù)讀取提交的數(shù)據(jù)的,如果
事務(wù)A在讀取一個數(shù)值的時候,值為"Hello World!",但這個時
候事務(wù)B對"Hello World"值進(jìn)行修改了,改為"Hello EveryOne"
然后提交,當(dāng)事務(wù)A再次去讀取這個值的時候,去發(fā)現(xiàn)原來讀到
的值改變了,變成了"Hello EveryOne",為了防止出現(xiàn)這種情況
可以禁止重復(fù)提交,目的是為了重復(fù)讀取不會出錯!那么這個
時候就可以選擇
TRANSACTION_REPEATABLE_READ這個級別,
這個級別就是用來禁止重復(fù)提交的.
(實際上是加了行鎖,鎖定了選中的數(shù)據(jù),不允許修改,但是允許插入新的數(shù)據(jù))
雖然這個時候是禁止了重復(fù)提交,但卻可以添加刪除,
比如事務(wù)A,作了個查詢語句"select * from 無名氏 "; 這個時候是允許事務(wù)B做這樣的操作的:
"insert into 無名氏 values(2,'aaa')"; 這個時候,
事務(wù)A再次做讀取操作的時候,卻發(fā)現(xiàn)數(shù)據(jù)莫名其妙的
多了一條,這就是所謂的---幻影讀取;
禁止幻讀(TRANSACTION_SERIALIZABLE):
事務(wù)的最高級別(串行化 操作)事務(wù)級別最高,所耗費的性能也越多.
禁止幻讀禁止了臟讀,禁止了重復(fù)提交和幻讀.
也就是當(dāng)事務(wù)A在按條件查詢的時候,事務(wù)A一旦沒有提
交,任何事務(wù)都不能對事務(wù)A的資源進(jìn)行操作--- 保證
事務(wù)A的操作真正的原子性!
注意:在Oracle中只支持兩種級別:
TRANSACTION_READ_COMMITTED(默認(rèn)的級別)(只有提交后
才可以讀取)而每一個終端進(jìn)行自己的DML操作 都自動開啟了一個事務(wù)
TRANSACTION_SERIALIZABLE(竄行化操作)
Java運行環(huán)境有一個字符串池,由String類維護(hù)。執(zhí)行語句String str="abc"時,首先查看字符串池中是否存在字符串"abc",如果存在則直接將"abc"賦給str,如果不存在則先在字符串池中新建一個字符串"abc",然后再將其賦給str。執(zhí)行語句String str=new String("abc")時,不管字符串池中是否存在字符串"abc",直接新建一個字符串"abc"(注意:新建的字符串"abc"不是在字符串池中),然后將其付給str。前一語句的效率高,后一語句的效率低,因為新建字符串占用內(nèi)存空間。String str = new String()創(chuàng)建了一個空字符串,與String str=new String("")相同。
public String intern()
- 返回字符串對象的規(guī)范化表示形式。
一個初始為空的字符串池,它由類 String
私有地維護(hù)。
當(dāng)調(diào)用 intern 方法時,如果池已經(jīng)包含一個等于此 String
對象的字符串(用 equals(Object)
方法確定),則返回池中的字符串。否則,將此 String
對象添加到池中,并返回此 String
對象的引用。
它遵循以下規(guī)則:對于任意兩個字符串 s
和 t
,當(dāng)且僅當(dāng) s.equals(t)
為 true
時,s.intern() == t.intern()
才為 true
。
String.intern();
再補充介紹一點:存在于.class文件中的常量池,在運行期間被jvm裝載,并且可以擴充。String的intern()方法就是擴充常量池的一個方法;當(dāng)一個String實例str調(diào)用intern()方法時,java查找常量池中是否有相同unicode的字符串常量,如果有,則返回其引用,如果沒有,則在常量池中增加一個unicode等于str的字符串并返回它的引用。
例3:
String s0=”kvill”;
String s1=new String(“kvill”);
String s2=new String(“kvill”);
System.out.println(s0==s1);
S1.intern();
S2=s2.intern();
System.out.println(s0==s1);
System.out.prntln(s0==s1.intern());
System.out.println(s0==s2);
結(jié)果為:
False
False //雖然執(zhí)行了s1.intern(),但它的返回值沒有賦給s1
True
True
最后再破除一個錯誤的理解:
有人說,“使用String.intern()方法可以將一個String類保存到一個全局的String表中,如果具有相同值的unicode字符串已經(jīng)在這個表中,那么該方法返回表中已有字符串的地址,如果在表中沒有相同值的字符串,則將自己的地址注冊到表中”如果把這個全局的String表理解為常量吃的話,最后一句話“如果在表中沒有相同值的字符串,則將自己的地址注冊到表中”是錯的。
例4:
String s1=new String(“kvill”);
String s2=s1.intern();
System.out.println(s1==s1.intern());
System.out.println(s1+” ”+s2);
System.out.println(s2==s1.intern());
結(jié)果是:
False
Kvill kvill
True
我們沒有聲明一個”kvill”常量,所以常量池中一開始沒有”kvill”的,當(dāng)我們調(diào)用s1.intern()后就在常量池中新添加了一個”kvill”常量,原來的不在常量池中的”kvill”仍然存在,也就不是“把自己的地址注冊到常量池中”了。
例5:
String str1=”java”;
String str2=”blog”;
String s=str1+str2;
System.out.println(s==”javablog”);
結(jié)果是false。Jvm確實對型如String str1=”java”;的String對象放在常量池里,但是它是在編譯時那么做的,而String s=str1+str2;是在運行時刻才能知道,也就是說str1+str2是在堆里創(chuàng)建的,所以結(jié)果為false了。
比較兩個已經(jīng)存在于字符串池中字符串對象可以用"=="進(jìn)行,擁有比equals操作符更快的速度
摘要:
1package com;
2
3import java.io.BufferedReader;
4import java.io.ByteArrayOutputStream;
5import java.io.Filte...
閱讀全文
//整數(shù)到字節(jié)數(shù)組的轉(zhuǎn)換 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng) h$_g8Lbx g s
public byte[] intToByte(int intValue) {
O R-v0OS&{;u0 byte[] result = new byte[4];
e!sm#DN0 result[0] = (byte) ( (intValue & 0xFF000000) >> 24);軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)3e Ou-l*l
result[1] = (byte) ( (intValue & 0x00FF0000) >> 16);軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)%F3hN!XoC
result[2] = (byte) ( (intValue & 0x0000FF00) >> 8);
d"TS)ro;L`;A:eI0 result[3] = (byte) ( (intValue & 0x000000FF));軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)t1^O{;_,S"e `
return result;軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)q*~[? n M"i
}
//字節(jié)數(shù)組到整數(shù)的轉(zhuǎn)換 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)i f9``3@0LZK&R
public static int byteToInt(byte[] b) { 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)Rb~,Ws"u1m
public static int byteToInt(byte[] byteVal) {
2X/cH bIM0 int result = 0;軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)7e5~3p"J r\ _
for (int i = 0; i < byteVal.length; i++) {
1i {T q a2eT V_.^!Q0 int tmpVal = (byteVal[i] << (8 * (3 - i)));
&?x%pQ4_9T7k0 switch (i) {軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)A P/u[ C,J&FA#f
case 0:軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)B,}\z`]8UU
tmpVal = tmpVal & 0xFF000000;軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)*yS6X$y9n*md~
break;
piL/jY)lkZ?0 case 1:軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)5D#YS%w3f X|g
tmpVal = tmpVal & 0x00FF0000;軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)c?Iu I w
break;軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)~&E3Vmp0_;}@
case 2:
6j3t1F;iX+K4{0 tmpVal = tmpVal & 0x0000FF00;軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)5fD7H.i y R a/q
break;
]5b:h MMa!K0 case 3:
)^~_.\A0 tmpVal = tmpVal & 0x000000FF;
t2}8J f7A E~eH2[0 break;軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)\? d:MN#D#iN
}
MJ:c.rxWE0X"e"^*@0 result = result | tmpVal;軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)9R lE\Q(g&SAJ
}軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)1ixe#~9]lyF},T
return result;軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)d,d"L^/fC?*upX
}
//字符到字節(jié)轉(zhuǎn)換
Q N"P6tq.b@~0 public static byte[] charToByte(char ch){ 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)%]|X,~-vb'?$SU
int temp=(int)ch; 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)'L9cx"B:` Ak
byte[] b=new byte[2]; 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)2C8j1U/i1[ ls
for (int i=b.length-1;i>-1;i--){
'C3^]_V:qz0 b = new Integer(temp&0xff).byteValue(); //將最高位保存在最低位 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng) |S`"I h%YQU\(g
temp = temp >> 8; //向右移8位 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)!s/jv'Z2R
} 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)R+C:w4LY4Xu!M
return b; 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)%n+x/Y ZV`6T\
}
//字節(jié)到字符轉(zhuǎn)換 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)n:gg'^!_@NF p*@B
public static char byteToChar(byte[] b){ 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)(}xOQ:b
int s=0;
ZuYw~ac0 if(b[0]>0) 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)'Tsc(rq
s+=b[0]; 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)5G]%j*fg)wk$Z
else 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)q#i2kb@
s+=256+b[0];
#iCo0kd+|i0 s*=256; 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)X%Zn?-k9h5q
if(b[1]>0) 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)(E0v"C(Bv4Q
s+=b[1];
+{`z$m a R0 else 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)D^j aODKA3T
s+=256+b[1]; 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)\ hv8We}U)b
char ch=(char)s; 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)#JLO"h;NH*AHb0LLt!m
return ch; 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)$g,Mu0?JT#Ef&xi
}
//浮點到字節(jié)轉(zhuǎn)換
de4w8L-MpD8{\0 public static byte[] doubleToByte(double d){ 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng),~9g3FuQ9q;sMCa
byte[] b=new byte[8]; 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng) UY:}1oV:\ {-uZ7Ed
long l=Double.doubleToLongBits(d);
ar8f3|"@b(g'L0 for(int i=0;i<b.length;i++){
%t4roUTU;zgxI0 b=new Long(l).byteValue(); 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)*I%@7R#} bb0P
l=l>>8;
E$^+\"u!h!Y3^0 } 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)%])x)S)u)i,ul
return b;
n`(]3K k`0 }
//字節(jié)到浮點轉(zhuǎn)換
KwV!^Kt2q#p j0 public static double byteToDouble(byte[] b){
:C.}9o GI9r0 long l;
l=b[0]; 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)^4_/j4oL\*l b
l&=0xff; 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)8x-fA;H.\
l|=((long)b[1]<<8); 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)P\Z9tk
l&=0xffff;
u;A&Vs3n.p]*K/B0 l|=((long)b[2]<<16);
)_ ^,F\ n3o0 l&=0xffffff;
` z3~*PIe aMK0 l|=((long)b[3]<<24);
DM!ldb&|U(A*J0 l&=0xffffffffl;
'i)k yh\0 l|=((long)b[4]<<32); 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng) T$D_Wr:M!_,E^a
l&=0xffffffffffl;
l|=((long)b[5]<<40); 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)g3m+GN$_)J1h,F.^(u.H d
l&=0xffffffffffffl;
,gJ&o'u N7\Sp0 l|=((long)b[6]<<48);
:m@s7\WCt+B0 l&=0xffffffffffffffl;
,x)T:eO e2d![0 l|=((long)b[7]<<56);
}^MS.x%_7P0 return Double.longBitsToDouble(l); 軟件測試專業(yè)網(wǎng)站:51Testing軟件測試網(wǎng)Q)at;{k9Tq
}