|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
java也能做一些底层语言开发做的事情(难度很高,不是java顶尖高手是做不来的),
1.NIO
1.1.申明:在新的I/O体系傍边,我们将次要利用Channel和Buffer来形貌我们底层的操纵。
1.2.模子:
1.3.对Channel举行读写:
/**
*@authorcenyongh@mails.gscas.ac.cn
*/
publicclassCopyFile{
publicstaticvoidmain(String[]args)throwsException{
Stringin=args[0];
Stringout=args[1];
FileInputStreamfis=newFileInputStream(in);
FileOutputStreamfos=newFileOutputStream(out);
FileChannelinc=fis.getChannel();
FileChanneloutc=fos.getChannel();
ByteBufferbb=ByteBuffer.allocate(1024);
while(true){
intret=inc.read(bb);
if(ret==-1){
break;
}
bb.flip();
outc.write(bb);
bb.clear();
}
}
}
注:我们并没有间接对Channel举行读写,而是经由过程Buffer来对Channel举行直接操纵。这里有两个中央要注重,就是我们在拷贝的历程傍边挪用了flip()和clear()办法,这两个办法的感化,将在前面解说。
1.4.手工添补Buffer
/**
*@authorcenyongh@mails.gscas.ac.cn
*/
publicclassWriteFile{
publicstaticvoidmain(String[]args)throwsException{
Stringout=args[0];
Stringin=args[0];
FileInputStreamfin=newFileInputStream(in);
FileOutputStreamfout=newFileOutputStream(out);
FileChannelinc=fin.getChannel();
FileChanneloutc=fout.getChannel();
ByteBufferbb=ByteBuffer.allocate(256);
for(inti=0;i<256;i++)
bb.put((byte)i);
bb.flip();
outc.write(bb);
bb.clear();
inc.read(bb);
bb.flip();
for(inti=0;i<bb.limit();i++){
System.out.println(bb.get());
}
}
}
注:经由过程挪用Buffer上的put()和get()办法,我们能够手工的往Buffer傍边添补数据。
1.5.Buffer的形态量。
Buffer次要利用三个形态量position,limit,capacity来标志底层的形态。个中capacity表征Buffer的最年夜容量,这个值在Buffer被分派时设定,一样平常不会跟着操纵改动。position表征Buffer确当前读写地位,不论是读操纵仍是写操纵,城市招致position的增添。limit表征Buffer的最年夜可读写地位,limit老是小于或即是capacity。
1.5.1.布局图:
1.5.2.flip()和clear()操纵
flip(){
limit=position;
postion=0;
}
clear(){
limit=capacity;
position=0;
}
1.5.3.例子:
/**
*@authorcenyongh@mails.gscas.ac.cn
*/
publicclassCopyFile{
publicstaticvoidmain(String[]args)throwsException{
Stringin=args[0];
Stringout=args[1];
FileInputStreamfis=newFileInputStream(in);
FileOutputStreamfos=newFileOutputStream(out);
FileChannelinc=fis.getChannel();
FileChanneloutc=fos.getChannel();
ByteBufferbb=ByteBuffer.allocate(1024);
inc.read(bb);
show(bb,"Afterread");
bb.flip();
show(bb,"Afterflip");
outc.write(bb);
show(bb,"Afterwrite");
bb.clear();
show(bb,"Afterclear");
}
publicstaticvoidshow(ByteBufferbb,Stringmsg){
System.out.println(msg+"p:"+bb.position()+"l:"+bb.limit()
+"c:"+bb.capacity());
}
}
输入:Afterreadp:1024l:1024c:1024
Afterflipp:0l:1024c:1024
Afterwritep:1024l:1024c:1024
Afterclearp:0l:1024c:1024
注:在举行read()操纵时,程序将只管的添补从position到limit之间的空间。在举行write()操纵时,
程序将读出从position到limit之间的空间。以是,在挪用完read()操纵今后,要举行其他操纵之前,
我们必需要挪用flip()操纵,使得position的地位回指到开首;而当挪用完write()操纵今后,应调
用clear()操纵,这一方面使得position回指到开首,同时使得limit抵达Buffer最年夜的容量处。
1.6.子Buffer
当在Buffer下面挪用slice()操纵时,将独自划出在[position,limit)之间的一段Buffer作为子Buffer,子Buffer与父Buffer利用不异的空间,但保护各自的形态量。
1.6.1.布局图:
1.6.2.例子:
ByteBufferoriginal=ByteBuffer.allocate(8);
original.position(2);
original.limit(6);
ByteBufferslice=original.slice();
1.7.其他范例的Buffer
我们能够把最基础的ByteBuffer包装成其他的CharBuffer,FloatBuffer等。
1.7.1.布局图:
1.7.2.例子:
ByteBufferbuffer=ByteBuffer.allocate(size);
FloatBufferfloatBuffer=buffer.asFloatBuffer();
1.8.在ByteBuffer上的多格局读取
在对ByteBuffer举行读取时,除能够依照流动距离的读取体例之外,我们也能够依照变长的体例读取。
1.8.1.例子:
fch.read(bb);
bb.flip();
byteb0=bb.get();
shorts0=bb.getShort();
byteb1=bb.get();
floatf0=bb.getFloat();
1.9.非堵塞I/O
在完成基于TCP/UDP的谈天服务器时,为了节俭资本我们可使用轮训手艺。而为了让服务器不永久堵塞在accept()办法上,我们能够设置一个守候超时价。而经由过程利用Selector类,我们可让以上办法更简单,更高效的失掉完成。
publicclassServerStubimplementsRunnable{
privateSelectorselector=null;
privateintport=0;
…
publicvoidrun(){
started=true;
try{
selector=Selector.open();
ServerSocketChannelschannel=ServerSocketChannel.open();
schannel.configureBlocking(false);
ServerSocketssocket=schannel.socket();
ssocket.bind(newInetSocketAddress("127.0.0.1",port));
schannel.register(selector,SelectionKey.OP_ACCEPT);
Set<SelectionKey>sks=null;
intkeys=0;
while(started){
keys=selector.select();
if(keys>0){
sks=selector.selectedKeys();
Iterator<SelectionKey>it=sks.iterator();
while(it.hasNext()){
SelectionKeykey=it.next();
it.remove();
if(key.isReadable()){
sender=(SocketChannel)key.channel();
Stringmsg=receive(sender);
}elseif(key.isAcceptable()){
SocketChannelsc=schannel.accept();
sc.configureBlocking(false);
sc.register(selector,SelectionKey.OP_READ);
}else{
emit("SomethingAbnormal");
}
}
}
}
}catch(Exceptione){
e.printStackTrace();
}
}
…
}
注:Selector的利用,使得服务器能以一种事务呼应的体例对客户真个毗连举行监听。经由过程
SelectionKey供应的常量,管道能够注册他说感乐趣的事务,关于ServerSocketChannel他
只能注册OP_ACCEPT事务。当用户挪用selector.select()办法时,线程将会被堵塞,直到某
些事务产生了。然后用户判别产生的事务范例并举行对应的操纵。这里有几点必要注重,第一
是必要利用Selector的Channel必要设置为非堵塞形式(configureBlocking(false)),第二
是用户必要手工的把已处置的SelectionKey,从汇合中移除。
publicclassClientStubimplementsRunnable{
privateSelectorselector=null;
privateSocketChannelchannel=null;
privatebooleanstarted=false;
…
publicvoidrun(){
started=true;
try{
selector=Selector.open();
Selectorsel=Selector.open();
channel=SocketChannel.open();
channel.configureBlocking(false);
channel.register(selector,SelectionKey.OP_READ
|SelectionKey.OP_CONNECT);
channel.connect(addr);
Set<SelectionKey>sks=null;
intkeys=0;
while(started){
keys=selector.select();
if(keys>0){
sks=selector.selectedKeys();
Iterator<SelectionKey>it=sks.iterator();
while(it.hasNext()){
SelectionKeykey=it.next();
it.remove();
if(key.isReadable()){
Stringmsg=receive(channel);
}elseif(key.isConnectable()){
channel.finishConnect();
key.interestOps(SelectionKey.OP_READ);
}else{
emit("SomethingAbnormal");
}
}
}
}
}catch(Exceptione){
e.printStackTrace();
}
}
…
}
注:客户端程序的完成与服务器真个基础类似。独一的一点区分就是,客户端一入手下手注册了两个事务范例OP_READ和OP_CONNECT,而当客户端毗连上服务器今后,他将会收到一个isConnectable的SelectionKey。在这里我们必要先挪用finishConnect()办法,然后因为我们不再必要监听毗连事务,因而我们必要修正Channel在Selector上的监听事务范例,这必要挪用interestOps()操纵来完成,个中办法的参数就是我们所必要的新的事务范例,这一步骤十分主要。
1.10.编码与解码
J2SDK1.4供应了专门用于举行编/解码的类,CharsetEncoder和CharstDecoder。
publicCharBufferdecode(ByteBufferbb){
Charsetc=Charset.forName("gb2312");
CharsetDecodercd=c.newDecoder();
CharBuffercb=cd.decode(bb);
returncb;
}
注:编码(CharsetEncoder)的办法与解码的相似。
2.ImageI/O
J2SDK1.4供应了专门用于图片读写的类。ImageIO。假如我们只是想复杂的读取或输入图片的话,那末我们能够间接利用ImageIO供应的static办法。而假如我们想对图片的读/写举行更多的把持的话,我们可使用ImageReader和ImageWriter,和与图片读写相干的一系列Listener。
publicImagereadImage(Stringfilename){
BufferedImagebi=ImageIO.read(newFile(filename));
returnbi;
}
publicvoidwriteImage(){
BufferedImagebi=newBufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
Graphics2Dg2=bi.createGraphics();
//画图操纵
ImageIO.write(bi,"jpeg",newFile("pic.jpg"));
}
3.Log
J2SDK1.4供应了专门用于誊写日记的类,Logger及其相干的Handler,Filter和Formatter。
3.1.布局图:
在Logger体系傍边,我们必要先猎取一个Logger实例,然后经由过程挪用Logger上的日记办法,我们将发生一个LogRecord实例,该实例将会被传送到在Logger上注册的一切Handler内,然后Handler利用他外部的Filter对象,以判别是不是要处置该LogRecord纪录,假如要处置的话,则把LogRecord传送给Formatter,让他对输入格局举行格局化。
publicclassTest{
publicstaticvoidmain(String[]args){
Loggerlog=Logger.getLogger("Test");
StreamHandlersh=newStreamHandler(System.out,newSimpleFormatter());
log.addHandler(sh);
log.info("HelloWorld");
}
}
输入:2005-3-121:06:25nick.log.Testmain
信息:HelloWorld
2005-3-121:06:25nick.log.Testmain
信息:HelloWorld
申明:因为Logger机制会递回的挪用父类的Logger,因而,这里输入了两份日记纪录。
3.2.自界说Handler,Filter,Formatter
publicclassTestFormatterextendsFormatter{
publicStringformat(LogRecordrecord){
return"INFOMESSAGE:"+record.getMessage();
}
}
publicclassTestFilterimplementsFilter{
publicbooleanisLoggable(LogRecordrecord){
if(record.getLevel()==Level.INFO)
returntrue;
else
returnfalse;
}
}
publicclassTestHandlerextendsHandler{
publicvoidpublish(LogRecordr){
if(!isLoggable(r))
return;
System.out.println(getFormatter().format(r));
}
publicvoidclose()throwsSecurityException{}
publicvoidflush(){}
}
publicclassTest{
publicstaticvoidmain(String[]args){
Loggerlog=Logger.getLogger("Test");
log.setLevel(Level.ALL);
log.setUseParentHandlers(false);
TestHandlerth=newTestHandler();
th.setFilter(newTestFilter());
th.setFormatter(newTestFormatter());
log.addHandler(th);
log.info("info");
log.fine("fine");
}
}
输入:INFOMESSAGE:info
申明:在主程序内里,我们挪用了setUseParentHandlers(false)办法,如许做是为了克制以后
的Logger挪用其父类Logger,默许情形下该值为true。
3.3.默许Handler及其设置
Log体系供应了五个默许Handler的完成:FileHandler,ConsoleHandler,MemoryHandler,SocketHandler,StreamHandler。经由过程设置文件,我们能够设定其默许属性。而经由过程在System.setProperty()办法内里设定“java.util.loggin.config.file”的值,能够指定设置文件的地位,默许情形下体系利用/jre/lib/logging.properties作为设置文件。
FileHandler
ConsoleHandler
MemoryHandler
SocketHandler
StreamHandler
level
y
y
y
Y
Y
filter
y
y
y
Y
Y
formatter
y
y
y
Y
encoding
y
y
y
Y
limit
y
count
y
pattern
y
append
y
size
y
push
y
target
y
host
Y
port
Y
logging.properties的内容:
nick.log.level=WARNING
publicclassTest{
publicstaticvoidmain(String[]args){
System.setProperty("java.util.logging.config.file",
"./logging.properties");
Loggerlog=Logger.getLogger("nick.log");
System.out.println(log.getLevel());
log.setUseParentHandlers(false);
StreamHandlersh=newStreamHandler(System.out,newSimpleFormatter());
log.addHandler(sh);
log.warning("warning");
log.info("info");
log.fine("fine");
}
}
输入:WARNING
2005-3-121:05:44nick.log.Testmain
告诫:warning
4.正则表达式
J2SDK1.4引进了对正则表达式的撑持。这次要包含Pattern和Matcher类。
publicclassTest{
publicstaticvoidmain(String[]args){
Patternp=Pattern.compile("+");
StringinputString="well,heytherefeller";
Matchermatcher=p.matcher(inputString);
while(matcher.find()){
intstart=matcher.start();
intend=matcher.end();
Stringmatched=inputString.substring(start,end);
System.out.println(matched);
}
System.out.println("=====UsingGroup:=====");
matcher.reset();
while(matcher.find()){
Stringmatched=matcher.group();
System.out.println(matched);
}
}
}
输入:well,
hey
there
=====UsingGroup:=====
well,
hey
there
申明:Pattern对必要举行辨认的形式举行编译,这能够进步以后的辨认速率。在利用Pattern
时有一点要出格注重,就是正则表达式单中,大批的利用以“”开首的标记,以是为了在Pattern
中暗示“”我们必要写成“”。而傍边的加号并非暗示毗连,而是暗示“1此或屡次”
上述程序演示了怎样利用一个形式往辨认一个字符串,并提取每个婚配的串。
4.1.捕捉组(CapturingGroup)
在Pattern傍边的正则表达傍边,经由过程利用括号,我们能够在本来的表达式傍边界说子表达式,大概称为CapturingGroup。经由过程Matcher,我们还能够间接提取某一个CapturingGroup的内容。
publicclassTest{
publicstaticvoidmain(String[]args){
Patternp=Pattern.compile("++(+)++");
StringinputString="heytherefeller";
Matchermatcher=p.matcher(inputString);
while(matcher.find()){
intstart=matcher.start(1);
intend=matcher.end(1);
Stringmatched=inputString.substring(start,end);
System.out.println(matched);
}
System.out.println("=====UsingGroup:=====");
matcher.reset();
while(matcher.find()){
Stringmatched=matcher.group(1);
System.out.println(matched);
}
}
}
输入:there
=====UsingGroup:=====
there
申明:CapturingGroup的编号是从1入手下手的。组号为0的组暗示全部串。
4.2.交换
Matcher供应用于交换的办法。一种是复杂举行查找交换,利用replaceAll()办法。第二种加倍天真的体例,在利用的时分能够分离CapturingGroup。
publicclassTest{
publicstaticvoidmain(String[]args){
Patternp=Pattern.compile("+");
StringinputString="heytherefeller";
Matchermatcher=p.matcher(inputString);
Stringns=matcher.replaceAll("Hello");
System.out.println(ns);
}
}
输入:HelloHellofeller
publicclassTest{
publicstaticvoidmain(String[]args){
Patternpattern=Pattern.compile("(((w|)*))");
StringinputString="Theseshouldbe(squarebrackets).(hello)";
StringBuffersb=newStringBuffer();
Matchermatcher=pattern.matcher(inputString);
while(matcher.find()){
matcher.appendReplacement(sb,"[$1]");
}
matcher.appendTail(sb);
StringnewString=sb.toString();
System.out.println(newString);
在1995年5月23日以“Java”的名称正式发布了。 |
|