欢迎光临
我们一直在努力

J2SDK 1.4中的新功能类-JSP教程,Java技巧及代码

建站超值云服务器,限时71元/月

1.        nio

1.1.       说明:在新的i/o系统当中,我们将主要使用channel和buffer来描述我们底层的操作。

1.2.       模型:

1.3.       对channel进行读写:

/**

 * @author cenyongh@mails.gscas.ac.cn

 */

public class copyfile {

     public static void main(string[] args) throws exception {

         string in = args[0];

         string out = args[1];

         fileinputstream fis = new fileinputstream(in);

         fileoutputstream fos = new fileoutputstream(out);

         filechannel inc = fis.getchannel();

         filechannel outc = fos.getchannel();

         bytebuffer bb = bytebuffer.allocate(1024);

         while (true) {

              int ret = inc.read(bb);

              if (ret == -1) {

                   break;

              }

              bb.flip();

              outc.write(bb);

              bb.clear();

         }

     }

}

注:我们并没有直接对channel进行读写,而是通过buffer来对channel进行间接操作。这里有两个地方要注意,就是我们在拷贝的过程当中调用了flip()和clear()方法,这两个方法的作用,将在后面讲解。

 

 

 

1.4.       手工填充buffer

/**

 * @author cenyongh@mails.gscas.ac.cn

 */

public class writefile {

     public static void main(string[] args) throws exception {

         string out = args[0];

         string in = args[0];

         fileinputstream fin = new fileinputstream(in);

         fileoutputstream fout = new fileoutputstream(out);

         filechannel inc = fin.getchannel();

         filechannel outc = fout.getchannel();

         bytebuffer bb = bytebuffer.allocate(256);

         for (int i = 0; i < 256; i++)

              bb.put((byte) i);

         bb.flip();

         outc.write(bb);

 

 

 

         bb.clear();

         inc.read(bb);

         bb.flip();

         for (int i = 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.      例子:

/**

 * @author cenyongh@mails.gscas.ac.cn

 */

 

 

 

public class copyfile {

 

 

 

     public static void main(string[] args) throws exception {

         string in = args[0];

         string out = args[1];

         fileinputstream fis = new fileinputstream(in);

         fileoutputstream fos = new fileoutputstream(out);

         filechannel inc = fis.getchannel();

         filechannel outc = fos.getchannel();

         bytebuffer bb = bytebuffer.allocate(1024);

 

 

 

         inc.read(bb);

         show(bb, "after read");

         bb.flip();

         show(bb, "after flip");

         outc.write(bb);

         show(bb, "after write");

         bb.clear();

         show(bb, "after clear");

     }

     public static void show(bytebuffer bb, string msg) {

         system.out.println(msg + " p:" + bb.position() + " l:" + bb.limit()

                   + " c:" + bb.capacity());

     }

}

输出:   after read p:1024 l:1024 c:1024

after flip p:0 l:1024 c:1024

after write p:1024 l:1024 c:1024

after clear p:0 l:1024 c: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.      例子:

bytebuffer original = bytebuffer.allocate( 8 );

original.position( 2 );

original.limit( 6 );

bytebuffer slice = original.slice();

 

 

 

1.7.       其他类型的buffer

我们可以把最基本的bytebuffer包装成其他的charbuffer,floatbuffer等。

1.7.1.      结构图:

1.7.2.      例子:

bytebuffer buffer = bytebuffer.allocate( size );

floatbuffer floatbuffer = buffer.asfloatbuffer();

 

 

 

1.8.       在bytebuffer上的多格式读取

在对bytebuffer进行读取时,除了可以按照固定间隔的读取方式以外,我们也可以按照变长的方式读取。

1.8.1.      例子:

fch.read( bb );

bb.flip();

byte b0 = bb.get();

short s0 = bb.getshort();

byte b1 = bb.get();

float f0 = bb.getfloat();

1.9.       非阻塞i/o

在实现基于tcp/udp的聊天服务器时,为了节省资源我们可以使用轮训技术。而为了让服务器不永远阻塞在accept()方法上,我们可以设置一个等待超时值。而通过使用selector类,我们可以让以上方法更容易,更高效的得到实现。

public class serverstub implements runnable{

   private selector selector = null;

   private int port = 0; 

   public void run() {

        started = true;

        try {

            selector = selector.open();

            serversocketchannel schannel = serversocketchannel.open();

            schannel.configureblocking(false);

            serversocket ssocket = schannel.socket();

            ssocket.bind(new inetsocketaddress("127.0.0.1", port));

            schannel.register(selector, selectionkey.op_accept);

            set<selectionkey> sks = null;

            int keys = 0;

            while (started) {

                 keys = selector.select();

                 if (keys > 0) {

                      sks = selector.selectedkeys();

                      iterator<selectionkey> it = sks.iterator();

                      while (it.hasnext()) {

                          selectionkey key = it.next();

                          it.remove();

                          if (key.isreadable()) {

                               sender = (socketchannel) key.channel();

                               string msg = receive(sender);                 

                          } else if (key.isacceptable()) {

                               socketchannel sc = schannel.accept();

                               sc.configureblocking(false);

                               sc.register(selector, selectionkey.op_read);

                          } else {

                               emit("something abnormal");

                          }

                      }

                 }

            }

        } catch (exception e) {

            e.printstacktrace();

        }

   }

   …

}

注:selector的使用,使得服务器能以一种事件响应的方式对客户端的连接进行监听。通过

selectionkey提供的常量,管道可以注册他说感兴趣的事件,对于serversocketchannel他

只能注册op_accept事件。当用户调用selector.select()方法时,线程将会被阻塞,直到某

些事件发生了。然后用户判断发生的事件类型并进行对应的操作。这里有几点需要注意,第一

是需要使用selector的channel需要设置为非阻塞模式(configureblocking(false)),第二

是用户需要手工的把已处理的selectionkey,从集合中移除。

 

 

 

public class clientstub implements runnable {

   private selector selector = null;

   private socketchannel channel = null;

   private boolean started = false;

   public void run() {

        started = true;

        try {

            selector = selector.open();

            selector sel = selector.open();

            channel = socketchannel.open();

            channel.configureblocking(false);

            channel.register(selector, selectionkey.op_read

                      | selectionkey.op_connect);

            channel.connect(addr);

            set<selectionkey> sks = null;

            int keys = 0;

            while (started) {

                 keys = selector.select();

                 if (keys > 0) {

                      sks = selector.selectedkeys();

                      iterator<selectionkey> it = sks.iterator();

                      while (it.hasnext()) {

                          selectionkey key = it.next();

                          it.remove();

                          if (key.isreadable()) {

                               string msg = receive(channel);                

                          } else if (key.isconnectable()) {

                               channel.finishconnect();

                               key.interestops(selectionkey.op_read);

                          } else {

                               emit("something abnormal");

                          }

                      }

                 }

            }

        } catch (exception e) {

            e.printstacktrace();

        }

   }

   …

}

注:客户端程序的实现与服务器端的基本相似。唯一的一点区别就是,客户端一开始注册了两个事件类型op_read和op_connect,而当客户端连接上服务器以后,他将会收到一个isconnectable的selectionkey。在这里我们需要先调用finishconnect()方法,然后由于我们不再需要监听连接事件,因此我们需要修改channel在selector上的监听事件类型,这需要调用interestops()操作来完成,其中方法的参数就是我们所需要的新的事件类型,这一步骤非常重要。

 

 

 

1.10.    编码与解码

j2sdk 1.4提供了专门用于进行编/解码的类,charsetencoder和charstdecoder。

public charbuffer decode(bytebuffer bb){

charset c = charset.forname("gb2312");

charsetdecoder cd = c.newdecoder();

charbuffer cb = cd.decode(bb);

return cb;

}

注:编码(charsetencoder)的方法与解码的类似。

 

 

 

2.        image i/o

j2sdk 1.4提供了专门用于图片读写的类。imageio。如果我们只是想简单的读取或输出图片的话,那么我们可以直接使用imageio提供的static方法。而如果我们想对图片的读/写进行更多的控制的话,我们可以使用imagereader和imagewriter,以及与图片读写相关的一系列listener。

public image readimage(string filename){

     bufferedimage bi = imageio.read(new file(filename));

     return bi;

}

 

 

 

public void writeimage(){

     bufferedimage bi = new bufferedimage(width,height,bufferedimage.type_int_argb);

     graphics2d g2 = bi.creategraphics();

     //   绘图操作

     imageio.write(bi, "jpeg",new file("pic.jpg"));

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

3.        log

j2sdk 1.4提供了专门用于书写日志的类,logger及其相关的handler,filter和formatter。

3.1.       结构图:

在logger系统当中,我们需要先获取一个logger实例,然后通过调用logger上的日志方法,我们将产生一个logrecord实例,该实例将会被传送到在logger上注册的所有handler内,然后handler使用他内部的filter对象,以判断是否要处理该logrecord记录,如果要处理的话,则把logrecord传递给formatter,让他对输出格式进行格式化。

public class test{

     public static void main(string[] args){

         logger log = logger.getlogger("test");

         streamhandler sh = new streamhandler(system.out, new simpleformatter());

         log.addhandler(sh);

         log.info("hello world");

     }

}

输出:   2005-3-12 1:06:25 nick.log.test main

信息: hello world

2005-3-12 1:06:25 nick.log.test main

信息: hello world

          说明:由于logger机制会递归的调用父类的logger,因此,这里输出了两份日志记录。

 

 

 

3.2.       自定义handler,filter,formatter

public class testformatter extends formatter {

     public string format(logrecord record) {

         return "info message:" + record.getmessage();

     }

}

 

 

 

public class testfilter implements filter {

     public boolean isloggable(logrecord record) {

         if (record.getlevel() == level.info)

              return true;

         else

              return false;

     }

}

 

 

 

public class testhandler extends handler {

     public void publish(logrecord r) {

         if (!isloggable(r))

              return;

         system.out.println(getformatter().format(r));

     }

     public void close() throws securityexception {}

     public void flush() {}

}

 

 

 

public class test {

     public static void main(string[] args) {

         logger log = logger.getlogger("test");

         log.setlevel(level.all);        

         log.setuseparenthandlers(false);

         testhandler th = new testhandler();

         th.setfilter(new testfilter());

         th.setformatter(new testformatter());

         log.addhandler(th);

         log.info("info");

         log.fine("fine");

     }

}

 

 

 

输出:info message: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

    

public class test {

     public static void main(string[] args) {

         system.setproperty("java.util.logging.config.file",

                   "./logging.properties");

         logger log = logger.getlogger("nick.log");

         system.out.println(log.getlevel());      

         log.setuseparenthandlers(false);

         streamhandler sh = new streamhandler(system.out, new simpleformatter());

         log.addhandler(sh);

         log.warning("warning");

         log.info("info");

         log.fine("fine");

     }

}

输出:   warning

2005-3-12 1:05:44 nick.log.test main

警告: warning

 

 

 

4.        正则表达式

j2sdk 1.4引入了对正则表达式的支持。这主要包括pattern和matcher类。

public class test {

     public static void main(string[] args) {

         pattern p = pattern.compile("\ +\ ");

         string inputstring = "well, hey there feller";

         matcher matcher = p.matcher(inputstring);

         while (matcher.find()) {

              int start = matcher.start();

              int end = matcher.end();

              string matched = inputstring.substring(start, end);

              system.out.println(matched);

         }

         system.out.println("===== using group: =====");

         matcher.reset();

         while (matcher.find()) {

              string matched = matcher.group();

              system.out.println(matched);

         }

     }

}

输出:   well,

hey

there

===== using group: =====

well,

hey

there

         说明:pattern对需要进行识别的模式进行编译,这可以提高之后的识别速度。在使用pattern

时有一点要特别注意,就是正则表达式单中,大量的使用以“\”开头的符号,所以为了在pattern

中表示“ ”我们需要写成“\ ”。而当中的加号并不是表示连接,而是表示“1此或多次”

上述程序演示了如何使用一个模式去识别一个字符串,并提取每一个匹配的串。

 

 

 

4.1.       捕获组(capturing group)

在pattern当中的正则表达当中,通过使用括号,我们可以在原来的表达式当中定义子表达式,或者称为capturing group。通过matcher,我们还可以直接提取某一个capturing group的内容。

public class test {

     public static void main(string[] args) {

         pattern p = pattern.compile("\ +\ +(\ +)\ +\ +");

         string inputstring = "hey there feller";

         matcher matcher = p.matcher(inputstring);

         while (matcher.find()) {

              int start = matcher.start(1);

              int end = matcher.end(1);

              string matched = inputstring.substring(start, end);

              system.out.println(matched);

         }

         system.out.println("===== using group: =====");

         matcher.reset();

         while (matcher.find()) {

              string matched = matcher.group(1);

              system.out.println(matched);

         }

     }

}

输出:   there

===== using group: =====

there

说明:capturing group的编号是从1开始的。组号为0的组表示整个串。

 

 

 

4.2.       替换

matcher提供用于替换的方法。一种是简单进行查找替换,使用replaceall()方法。第二种更加灵活的方式,在使用的时候可以结合capturing group。

public class test {

   public static void main(string[] args) {

        pattern p = pattern.compile("\ +\ ");

        string inputstring = "hey there feller";

        matcher matcher = p.matcher(inputstring);

        string ns = matcher.replaceall("hello ");

        system.out.println(ns);

   }

}

输出:hello hello feller

 

 

 

public class test {

   public static void main(string[] args) {

        pattern pattern = pattern.compile("\\(((\\w|\ )*)\\)");

        string inputstring = "these should be (square brackets).(hello)";

        stringbuffer sb = new stringbuffer();

        matcher matcher = pattern.matcher(inputstring);

        while (matcher.find()) {

            matcher.appendreplacement(sb, "[$1]");

        }

        matcher.appendtail(sb);

        string newstring = sb.tostring();

        system.out.println(newstring);

   }

}

输出:these should be [square brackets].[hello]

说明:这种方式的替换,由于加入了capturing group。所以比之前的方法更加灵活。在appendreplacement()方法中,我们使用第二个参数的内容,替换匹配的部分。而$x则是用于引用对应的capturing group的值。

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » J2SDK 1.4中的新功能类-JSP教程,Java技巧及代码
分享到: 更多 (0)