J2SE1.4的I/O新特性

1、Java NIO:提升I/O性能的利器 本文深入探讨了Java NIO的核心组件及其在提升I/O性能方面的应用。从传统Java I/O的局限性出发,介绍了Java NIO诞生的背景,并详细解析了Buffers、Channels、Selectors等核心概念及其应用场景。同时提供了各组件的操作步骤示例,帮助开发者快速掌握Java NIO的使用方法。通过本文,读者可以全面了解Java NIO如何优化企业级应用的I/O处理能力。 阅读详情
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script> 出处:Java.sun.com 作者:John Zukowski 译者序:这是一篇比较使用的I/O新特性的介绍文章。文中使用了大量的代码实例来演示和解说如何使用J2SE1.4的新I/O特性并提供你应用程序的性能,而且提供了两个完整的例子,其中包括一个循环WEB服务器的雏形,非常值得我们参考。 回溯到2000年的1月,当人们正在争论着公元2000年究竟是一个世纪的开始还是一个实际的结束的时候,一份新的JAVA规范——JSR(Java Specification Request)51也被审核通过了。这份JSR的名字是《New I/O APIs for the Java Platform》(JAVA平台的新I/O API)。许多人认为这份新的规范只会给大家带来非阻塞I/O操作的能力,但是在JSDK1.4Beta(JavaTM 2 Platform, Standard Edition)中引入的新的特性,却还包含其它的一些新而有趣的特征。新的API在提供了可升级的套接口(socket)和文件I/O操作的同时(这是理所当然的),你也可以找到一个正则表达的包来支持模式匹配,以及对字符集转换的编码器和解码器,和优化过的文件系统支持如文件锁定、内存映射等功能。我们在这篇文章中的讨论会全面覆盖上面所说的四个新特性。 注意:JAVA本地接口(JNI)为新的I/O操作所做的修改我们将不会涉及,如果你需要了解有关的内容,请参考本文结尾“资源”部分的有关内容。 Buffers 按照从最简单到最复杂的习惯,我们将从java.nio包中的一系列Buffer类开始说起。Buffer提供了一种在内存容器中保存一系列原始数据的机制。基本上,你可以设想一下,把DataInputStream/DataOutputStream组合在一起封装成一个固定字节大小的数组而只允许读写一种数据类型,例如char,int,或者double。在这个包里,总共有7种这样的Buffer可用: · ByteBuffer · CharBuffer · DoubleBuffer · FloatBuffer · IntBuffer · LongBuffer · ShortBuffer 实际上,ByteBuffer也能够对其它六种类型进行读写,但是这些特别的Buffer更有针对性,更专门化一些。为了示范如何使用一个Buffer,接下来这一小片代码将完成一个从String型变量到一个CharBuffer的转换,并从这个Buffer中逐一的读出单个字符。你可以用warp方法来完成转换,用get方法来取一个字符。



CharBuffer buff = CharBuffer.wrap(args[0]);

for (int i=0, n=buff.length(); i
在使用Buffer的时候,一定要注意它目前的大小(sizing)和位置(positioning)的值是有区别的,千万不要混淆了。方法length是不规范的,尤其是对于CharBuffer而言。当然这并非是出了什么错,而是它返回的是Buffer中的剩余长度的值,所以如果position并非在Buffer的开始处的话,返回值将不是Buffer的长度,而是在Buffer中剩余的字符的长度。换句话说,上面程序中的循环也可以修改成这样:



CharBuffer buff = CharBuffer.wrap(args[0]);

for (int i=0; buff.length() > 0; i  ) {

 System.out.println(buff.get());

}

我们回到正题,继续讨论大小(sizing)和位置(positioning)的关系,在这里,有四个概念必须明确,它们是mark(标记),position(位置),limit(限制),和capacity(容量)。 · mark——用mark方法设置的可设位置,mark方法可以使用reset来重置position,<=position,>=0; · position——在Buffer中目前读写的位置,<=limit; · limit——第一个不应该被读取的元素的位置的index(索引号),<=cpacity; · capcity——Buffer的大小,>=size。 Position(位置)属性值是我们在对一个Buffer读取或者写入的时候需要时刻牢记的信息。例如,如果你想读取你刚刚写入的字符,你不许把position移动到你想读取的位置,否则,你将越过limit的限制,而读到一个不知道是什么的字符。这时候你需要立刻使用flip方法,把limit移动到当前的位置,并把position移动到0位置。你也可以回绕一个buffer来保持当前的limit位置,而把position返回到0位置。举个例子,如果从下面这一小段代码中的flip调用去掉,将返回一个空白,因为在buffer中还什么都没有。 buff.put('a'); buff.flip(); buff.get(); 上面的封装机制是一个非直接缓冲(non-direct buffer)的例子。非直接缓冲也可以通过allocate方法来创建和限定大小,本质上来说,只是把数据封装到一个数组里了。如果愿意消耗稍微多一点的创建资源,你也可以通过allocateDirect方法开辟一块连续的内存来保存数据,这也可以称作直接缓冲。直接缓冲是依赖于系统的本地接口的I/O操作来优化存取操作的。 文件映射 MappedByteBuffer是一个专门用于直接缓冲的ByteBuffer,这个类用字节缓冲来映射一个文件。想要映射一个文件到MappedByteBuffer,你必须先取得这个文件的通道(channel)。通道是某种已建立的连接,例如管道(pipe),套接口(socket),或者文件(file)等能够完成I/O操作的对象。如果是文件通道,你可以通过 FileInputStream(文件输入流),FileOutputStream(文件输出流)或者RandomAccessFile(随机存取文件)的getChannel方法来获得一个通道。一旦你取得这个通道,你就可以通过它的map方法,指明映射模式来把你想映射的那一部分文件映射到缓冲中去。文件通道可以使用FileChannel.MapMode的任一个常数打开:只读(READ_ONLY),私有/写时拷贝(PRIVATE),或者读写(READ_WRITE)。 下面是一个从文件中创建只读的MappedByteBuffer的基本例程:



String filename = ...;

FileInputStream input = new 

 FileInputStream(filename);

FileChannel channel = input.getChannel();

int fileLength = (int)channel.size();

MappedByteBuffer buffer = 

 channel.map(FileChannel.MapMode.READ_ONLY, 0, 

 fileLength);



你可以在java.nio.channels包里找到与通道有关的类。 一旦MappedByteBuffer被建立了,你就可以象存取其它任何ByteBuffer一样来操作它。当然在这个例子里它是只读的,所以加入你试图写入一些东西的时候,它会抛出一个NonWritableChannelException的异常。假如你想把它当作字符来处理的话,你必须制定一个字符集把ByteBuffer转化成CharBuffer。这个字符集是在Charset类中定义的。然后你用CharsetDecoder类对文件的内容进行解码。它相反的操作是由CharsetEncoder类来完成的。



// ISO-8859-1 是ISO拉丁字符表#1

Charset charset = Charset.forName("ISO-8859-1");

CharsetDecoder decoder = charset.newDecoder();

CharBuffer charBuffer = decoder.decode(buffer);



这个类可以在java.nio.charset包中找到。 正则表达式 一旦你完成了从文件到CharBuffer的可输入映射,你就可以对文件内容进行模式匹配。就像我们分别使用grep命令和wc命令来进行正则表达的匹配和单词计数一样。其中使用到了java.util.regex中的Pattern和Matcher两个类。 Pattern类为匹配正则表达提供了所有的构造类型。一般来说,你的模式表达是一个字符串,可以查阅类文档得到模式的完整细节,这里只提供一些简单常用的例子: · 行模式,任意个字符然后以回车换行借宿并且/或者行结束:.* ? 或.*$ · 连续的数字:[0-9]* 或者 d* 一个控制符:{cntrl} · 一个大写或者小写US-ASCII字符,接着一个空格,接着标点:[p{Lower}p{Upper}]sp{Punct} 注:不幸的是,J2SE 1.4 beta3中打断了这一切,因为它对正则表达式所必须的字符缓冲的次序支持的非常不好。从SUN的Bug Parade可以看到这个问题的详细资料(希望你有JDC的帐号,呵呵,没有就快去申请啊,还愣着干什么?)。很遗憾,这意味着你不能用模式匹配同时去读取一个词或者一行。 如果想获得更多的有关正则表达式库的信息,可以参考本文最后所列“资源”中的《Regular Expressions and the Java Programming Language》(正则表达和java编程语言) 套接口通道 下面我们要从文件通道转移到读写一个套接口连接的通道中来。这个通道可以用做阻塞模式,也可以用作非阻塞模式。如果是阻塞模式,取决于你的程序是服务器端还是客户端,只需把你的调用换成connect或者accept。而在非阻塞模式,它们的处理方式是不一样的。 这些新类处理基本套接口的读写操作。在java.net包中的InetSocketAddress类指定连接地址,java.nio.channels包中的SocketChannel类来完成实际的读写操作。 使用InetSocketAddress来进行连接非常类似于普通的Socket类的操作。你所要做的一切仅仅是提供主机和端口号:



String host = ...;

InetSocketAddress socketAddress = new 

 InetSocketAddress(host, 80);



一旦你获得了InetSocketAddress,一切都改变了(怎么听着象童话^&^)。你可以打开一个SocketChannel来连接到InetSocketAddress,用它来取代我们以前从套接口的输入流来读取、向套接口的输出流写入的所有操作:



SocketChannel channel = SocketChannel.open();

channel.connect(socketAddress);



在连接完成之后,你立刻可以使用ByteBuffer对象对这个通道进行读写。例如,你可以把一个字符串使用CharsetEncoder封装到一个CharBuffer来发送一个http请求:



Charset charset = Charset.forName("ISO-8859-1");

CharsetEncoder encoder = charset.newEncoder();

String request = "GET / ";

channel.write(encoder.encode(CharBuffer.wrap(request)));



你可以从这个通道中读取请求的响应。由于这个http请求的响应是一个文本格式的,你需要使用CharsetDecoder来把响应转换到CharBuffer。你可以使用一个CharBuffer来完成这些操作,通过重用来避免在读取的时候产生不必要的多余连接:



ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

CharBuffer charBuffer = CharBuffer.allocate(1024);

while ((channel.read(buffer)) != -1) {

 buffer.flip();

 decoder.decode(buffer, charBuffer, false);

 charBuffer.flip();

 System.out.println(charBuffer);

 buffer.clear();

 charBuffer.clear();

}



下面这个程序通过一个http请求来读取这个web站点的首页。你可以把这个输出保存成一个文件与用浏览器浏览该页的结果相对比。



import java.io.*;

import java.net.*;

import java.nio.*;

import java.nio.channels.*;

import java.nio.charset.*;





public class ReadURL {

 public static void main(String args[]) {

   String host = args[0];

   SocketChannel channel = null;



   try {



     // Setup

     InetSocketAddress socketAddress = 

       new InetSocketAddress(host, 80);

     Charset charset = 

       Charset.forName("ISO-8859-1");

     CharsetDecoder decoder = 

       charset.newDecoder();

     CharsetEncoder encoder = 

       charset.newEncoder();



     // Allocate buffers

     ByteBuffer buffer = 

       ByteBuffer.allocateDirect(1024);

     CharBuffer charBuffer = 

       CharBuffer.allocate(1024);



     // Connect

     channel = SocketChannel.open();

     channel.connect(socketAddress);



     // Send request

     String request = "GET / ";

     channel.write(encoder.encode(CharBuffer.wrap(request)));



     // Read response

     while ((channel.read(buffer)) != -1) {

       buffer.flip();

       // Decode buffer

       decoder.decode(buffer, charBuffer, false);

       // Display

       charBuffer.flip();

       System.out.println(charBuffer);

       buffer.clear();

       charBuffer.clear();

     }

   } catch (UnknownHostException e) {

     System.err.println(e);

   } catch (IOException e) {

     System.err.println(e);

   } finally {

     if (channel != null) {

       try {

         channel.close();

       } catch (IOException ignored) {

       }

     }

   }

 }

}



非阻塞读取 现在,我们将要进入一个比较有趣的部分,也是人们在新的I/O包中最感兴趣的部分。怎么配置你的通道使它以非阻塞模式工作呢?基本的步骤是在打开通道后调用configureBlocking方法,输入false值。一旦你调用了connect方法,这个方法将马上返回。





String host = ...;

InetSocketAddress socketAddress = 

 new InetSocketAddress(host, 80);

channel = SocketChannel.open();

channel.configureBlocking(false);

channel.connect(socketAddress);



获得一个非阻塞的通道后,你需要考虑的是如何用这个通道做实际的工作。SocketChannel是一个SelectableChannel。这些可选择通道(selectable channels)通过一个Selector来工作。基本上,你把你的通道注册到一个Selector,然后告诉这个Selector你对那些事件有兴趣,它会在你有兴趣的事发生的时候提醒你的。 要取得一个Selector的实例,只需调用这个类的静态方法open就可以了: Selector selector = Selector.open(); 通道的register方法可以完成到Selector类的注册。而你关心的事件名称则由SelectionKey类的各个字段来描述。对于SocketChannel类来说,有效的操作事件是OP_CONNECT,OP_READ 和 OP_WRITE。所以当你对连接和读取有兴趣的时候,可以如下进行注册: channel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ); 这时候,你就必须等待selector来通知你感兴趣的事件在你注册的通道上发生了。Selector的select方法将将阻塞到事件的发生。为了获取这个信息,你可以在它自己的线程里使用一个while (selector.select() > 0)循环,当I/O操作执行的时候再跳出来做自己的事。当有事件发生的时候select方法会返回,返回值是事件发生的通道的序数,而并非事件本身。 在你感兴趣的事发生之后,你不许计算出发生了什么事来对它进行响应。在我们这个例子中,我们已经向Select表示我们只对OP_CONNECT和OP_READ两项有兴趣,所以必然是二者之一。接着你所要做的是通过selectedKeys方法来取得一个已经就绪的对象集。在这个集合中的元素是一个SelectionKey,你可以检查它的isConnectable 和isReadable两个属性来得到它的状态。 下面是这个循环的基本框架:



while (selector.select(500) > 0) {

 // Get set of ready objects

 Set readyKeys = selector.selectedKeys();

 Iterator readyItor = readyKeys.iterator();



 // Walk through set

 while (readyItor.hasNext()) {



   // Get key from set

   SelectionKey key = 

     (SelectionKey)readyItor.next();



   // Remove current entry

   readyItor.remove();



   // Get channel

   SocketChannel keyChannel = 

     (SocketChannel)key.channel();



   if (key.isConnectable()) {



   } else if (key.isReadable()) {



   }

 }

}



这里,remove方法的调用需要进行一下小小的解释。这个已经就绪的集合当你操作它的时候也会发生变化。所以,你应该在你操作这个元素的的时候,把它remove出来。这个移动操作并不会引发ConcurrentModificationException的异常的抛出。同时由于有一个超时设置,select方法的调用也不会在毫无事件发生的情况下僵死。同样也有一个调用来从集合中的键值获得相应的通道对象。你需要完成上述的所有操作。 为了在例程中从HTTP连接中进行读取操作,你需要发送初始HTTP请求。基本上,一旦你知道这个连接完成了,你就发送一个GET请求来获得这个站点的根目录。当selector报告通道还是可连接的时候,就还没有完成连接。所以你需要经常的通过isConnectionPending方法检查这个连接是否未完成,并在它完成后调用finishConnect。而在连接完成之后,你就可对这个通道进行写入操作,但是必须使用ByteBuffer,而不是我们常见的I/O流了。 下面是一段连接代码的示例:





// OUTSIDE WHILE LOOP

Charset charset = 

    Charset.forName("ISO-8859-1");

CharsetEncoder encoder = charset.newEncoder();



// INSIDE if (channel.isConnectable())

// Finish connection

if (keyChannel.isConnectionPending()) {

 keyChannel.finishConnect();

}



// Send request

String request = "GET / ";

keyChannel.write

    (encoder.encode(CharBuffer.wrap(request)));



从一个套接口通道中读取数据和从一个文件通道中读取是一样的。然后可能会引发一个异常,它更可能的情况是当从一个套接口读取数据的时候缓冲还没有被充满。在你准备好读取需要的数据的时候,这没什么大不了的。



// OUTSIDE WHILE LOOP

CharsetDecoder decoder = charset.newDecoder();

ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

CharBuffer charBuffer = CharBuffer.allocate(1024);



// INSIDE if (channel.isReadable())

// Read what's ready in response

keyChannel.read(buffer);

buffer.flip();



// Decode buffer

decoder.decode(buffer, charBuffer, false);



// Display

charBuffer.flip();

System.out.print(charBuffer);



// Clear for next pass

buffer.clear();

charBuffer.clear();

加入必要的例外处理代码,你就可以使用你的套接口读取数据了。一定要在finally代码段中加入关闭通道的代码,这样即使在发生了例外的时候,也可以保证资源不被锁住。下面是完整的代码:



import java.io.*;

import java.net.*;

import java.nio.*;

import java.nio.channels.*;

import java.nio.charset.*;

import java.util.*;





public class NonBlockingReadURL {

 static Selector selector;



 public static void main(String args[]) {

   String host = args[0];

   SocketChannel channel = null;



   try {



     // Setup

     InetSocketAddress socketAddress = 

       new InetSocketAddress(host, 80);

     Charset charset = 

       Charset.forName("ISO-8859-1");

     CharsetDecoder decoder = 

       charset.newDecoder();

     CharsetEncoder encoder = 

       charset.newEncoder();



     // Allocate buffers

     ByteBuffer buffer = 

       ByteBuffer.allocateDirect(1024);

     CharBuffer charBuffer = 

       CharBuffer.allocate(1024);



     // Connect

     channel = SocketChannel.open();

     channel.configureBlocking(false);

     channel.connect(socketAddress);



     // Open Selector

     selector = Selector.open();



     // Register interest in when connection

     channel.register(selector, 

       SelectionKey.OP_CONNECT | 

         SelectionKey.OP_READ);



     // Wait for something of interest to happen

     while (selector.select(500) > 0) {

       // Get set of ready objects

       Set readyKeys = selector.selectedKeys();

       Iterator readyItor = readyKeys.iterator();



       // Walk through set

       while (readyItor.hasNext()) { 

 





         // Get key from set

         SelectionKey key = 

           (SelectionKey)readyItor.next();



         // Remove current entry

         readyItor.remove();



         // Get channel

         SocketChannel keyChannel = 

           (SocketChannel)key.channel();



         if (key.isConnectable()) {



           // Finish connection

           if (keyChannel.isConnectionPending()) {

             keyChannel.finishConnect();

           }



           // Send request

           String request = 

                "GET / ";

           keyChannel.write(encoder.encode(

             CharBuffer.wrap(request)));



         } else if (key.isReadable()) {



           // Read what's ready in response

           keyChannel.read(buffer);

           buffer.flip();



           // Decode buffer

           decoder.decode(buffer, 

             charBuffer, false);



           // Display

           charBuffer.flip();

           System.out.print(charBuffer);



           // Clear for next pass

           buffer.clear();

           charBuffer.clear();



         } else {

           System.err.println("Ooops");

         }

       }

     }

   } catch (UnknownHostException e) {

     System.err.println(e);

   } catch (IOException e) {

     System.err.println(e);

   } finally {

     if (channel != null) {

       try {

         channel.close();

       } catch (IOException ignored) {

       }

     }

   }

   System.out.println();

 }

}



非阻塞服务器 在最后这部分,我们使用NIO包实现一个Web服务器。通过新的I/O特性,你可以不必为每个连接都提供一个线程就可以实现WEB服务器的功能。当然你可以用线程来处理费时较长的任务,但是你所需要做的一切仅仅是调用select方法等待需要做的事的到来,而不在是让所有的线程都整装待命。 这个服务器的基本设计思想是使用通道来包容已经通过调用bind方法绑定在InetSocketAddress上的ServerSocketChannel。





ServerSocketChannel channel = 

 ServerSocketChannel.open();

channel.configureBlocking(false);

InetSocketAddress isa = 

 new InetSocketAddress(port);

channel.socket().bind(isa);

所有的步骤和客户端读取的准备差不多,除了这次你需要注册的是OP_ACCEPT键值,当selector提醒你事件到来的时候检查isAcceptable,并使用ServerSocketChannel代替SocketChannel外。非常简单! 下面的例程正是向大家展示了它是如何的简单。这是一个基本的单线程的服务器,对每一个响应都发回一段固定的文字信息。使用telnet连接到9999端口可以看到它的响应:)



import java.io.*;

import java.net.*;

import java.nio.*;

import java.nio.channels.*;

import java.util.*;



public class Server {

  private static int port = 9999;

  public static void main(String args[]) 

    throws Exception {

    Selector selector = Selector.open();



    ServerSocketChannel channel = 

      ServerSocketChannel.open();

    channel.configureBlocking(false);

    InetSocketAddress isa = new InetSocketAddress(port);

    channel.socket().bind(isa);



    // Register interest in when connection

    channel.register(selector, SelectionKey.OP_ACCEPT);



    // Wait for something of interest to happen

    while (selector.select() > 0) {

      // Get set of ready objects

      Set readyKeys = selector.selectedKeys();

      Iterator readyItor = readyKeys.iterator();



      // Walk through set

      while (readyItor.hasNext()) {



        // Get key from set

        SelectionKey key = 

          (SelectionKey)readyItor.next();



        // Remove current entry

        readyItor.remove();



        if (key.isAcceptable()) {

          // Get channel

          ServerSocketChannel keyChannel =

            (ServerSocketChannel)key.channel();



          // Get server socket

          ServerSocket serverSocket = keyChannel.socket();



          // Accept request

          Socket socket = serverSocket.accept();



          // Return canned message

          PrintWriter out = new PrintWriter

            (socket.getOutputStream(), true);

          out.println("Hello, NIO");

          out.close();

        } else {

          System.err.println("Ooops");

        }



      }

    }

    // Never ends

  }

}

在接受请求之后,你可以从套接口取得一个对应的通道,使它转到非阻塞模式,然后也注册到selector。这个结构框架提供了NIO类在制作一个WEB服务器上的基本用法。关于如何创建一个多线程的服务器的更多信息,可以参考在本文最后“资源”一节里JavaWorld的有关文章。 结论 在J2SE 1.4Beta版本中引入的I/O新特性提供了令人振奋的新方法来增进你应用程序的性能。通过这些新特性的使用,你的应用程序不但能够变得更快,性能上也会得到攀升,因为你不必再为每一个连接新建一个线程。这对于服务器端来说更是尤其的重要,可以支持大幅度增长的同时连接的数目。 注:如果你浏览过JSR51中的性能列表,你会注意到它提到了扫描和格式化输入输出的支持,和C语言中的printf非常相似。这个特性并没有被1.4Beta实现,将在下一个版本中引入。 资源 JSR 51 New I/O APIs for the Java Platform New I/O API Summary JNI Enhancements Regular Expressions and the Java Programming Language Character Sets Master Merlin's new I/O classes (JavaWorld) Non-Blocking Socket I/O in JDK 1.4 关于作者 John Zukowski目前担任JZ Ventures, Inc的战略JAVA战略顾问。他最近新出版的书籍有《Java Collections》和《Definitive Guide to Swing for Java 2》(第二版)。并将在2002年出版《Learn Java with JBuilder 6》。 联系方式:mailto:jaz@zukowski.net?Subject=New I/O Article 。
J2SE1.4.2_02 for windows 立即下载

相关推荐

upload.jar for J2SE 1.4.2

这是在 sun java jdk 1.4.2 平台上开发的一个类库文件,解决上传文件到 java web server 的问题。 和最早的版本相比,该版本修正了当 request.getgetCharacterEncoding() 为 null 时所导致的 NullException 。

用J2SE 1.4进行Internet安全编制程序

http://www.pcvz.com/Program/Programs/Java/JavaJC/Program_99729.html 任何在计算机网络或者 Internet 中传输的消息都可能被拦截,其中不乏一些比较敏感的内容,如信用卡号或者其它一些私人数据。为了更好的在企业环境和电子商务中使用 Internet,应用软件必须使用加 密、验证和安全的通信协议来保护用户的数据安全。安全超文

杨德龙的专栏 1035

AI 生成 CAN 通信测试用例实战

本文分享了AI辅助汽车电子测试用例编写的实战经验。通过某车企CAN网络测试项目案例,对比传统方式(需27天)与AI辅助方式(仅5天)的效率差异,展示81%的效率提升。文章详细介绍了从DBC文件提取信号信息的方法,包括DBC文件结构解析、信号定义说明,并提供了完整的Python解析脚本代码,可将信号信息导出为JSON或Excel格式,为后续AI批量生成测试用例奠定基础。

小明的博客 695

J2SDK 1.4中的新功能类

1.        NIO1.1.       说明:在新的I/O系统当中,我们将主要使用Channel和Buffer来描述我们底层的操作。1.2.       模型:1.3.       对Channel进行读写:/** * @author cenyongh@mails.gscas.ac.cn */public class CopyFile {     public static void ma

技术源于生活 2257

公文派2025:免费社区版重大安装更新!

距离上一次更新已经过去了将近一年的时间,今天我们带来了全新的免费2025社区版,该版本也是目前最新的版本,无需授权即可使用所有的功能。

似最初 1964

用 Java 2 标准版本 (J2SE) 1.4 进行 Internet 安全编

<!--google_ad_client = "pub-2947489232296736";/* 728x15, 创建于 08-4-23MSDN */google_ad_slot = "3624277373";google_ad_width = 728;google_ad_height = 15;//--><script type="text/javascript"

zgqtxwd的专栏 525

【报错】sqli-labs靶场搭建出现“Unable to connect to the database: security”

搭建sqli-labs靶场时,“Unable to connect to the database: security”报错解决

九芒星的博客 2996

j2se和j2ee

随着Internet网络的迅速发展,基于互联网的企业应用要求软件平台具有开放性、分布性和平台无关性。于是就相继出现了RPC/COM/CORBA等技术,但这些技术在实际应用中存在着许多不足和局限。它们的特定协议难以通过防火墙,因而不适于Web上的应用开发。为了进一步开发基于Web的应用,出现了Sun公司的Sun ONE(Open Net Environment 开发网络环境)和Microsoft公司

fighter_hua的专栏 2243

外设高级定时器互补输出带死区控制实验

外设高级定时器互补输出带死区控制实验

ff_juju的博客 1654

2025机械考研复试面试问题汇总篇(含13门科目),考研机械复试专业面试常见重点问题总结!考研机械复试专业面试准备看这一篇就够了!

(完整版内容:)1.汇集了本科各科的重点知识及多个机械名校800多个常见问题,共8.7万字185页,涵盖机械所以专业课的重点知识和常见问答。 2.涉及机械大类重点科目,包括:材料力学、控制工程、数控技术、机械制造技术基础、理论力学、液压传动、机械设计、机械原理、工程材料、互换性与技术测量、测试技术、汽车理论、程序设计与C语言等13门必修课。

weixin_56510835的博客 1862

Java New I/O的使用

NIO的使用导读 J2SE1.4以上版本中发布了全新的I/O类库。本文将通过一些实例来简单介绍NIO库提供的一些新特性:非阻塞I/O,字符转换,缓冲以及通道。一. 介绍NIONIO包(java.nio.*)引入了四个关键的抽象数据类型,它们共同解决传统的I/O类中的一些问题。1. Buffer:它是包含数据且用于读写的线形表结构。其中还提供了一个特殊类用于内存映射文件的

dycm的专栏 1754

uniapp(微信小程序):实现PDF在线预览+在线预览pdf文件完整示例源码,支持文件来源:服务器pdf外链URL预览、调用后端API接口获取PDF文件流二进制下载及解析打开、上传本地PDF文件预览

uni-app实现PDF预览功能,uniapp微信小程序预览PDF,uniapp开发微信小程序在线预览pdf等文件,uniApp微信小程序实现PDF在线预览,Uniapp app在线预览pdf文件流,微信小程序实现pdf预览(苹果安卓兼容),uniapp-微信小程序 实现pdf外链在线预览,uniapp小程序如何做在线预览pdf功能,uniapp小程序端 实现pdf文件预览,微信小程序(uniapp)PDF预览完整实现方案示例demo源码,uni-app预览PDF,小程序pdf预览插件插件,Uniapp微信

✅ 精选推荐文章 4706

NIO的使用

NIO的使用导读 J2SE1.4以上版本中发布了全新的I/O类库。本文将通过一些实例来简单介绍NIO库提供的一些新特性:非阻塞I/O,字符转换,缓冲以及通道。一. 介绍NIONIO包(java.nio.*)引入了四个关键的抽象数据类型,它们共同解决传统的I/O类中的一些问题。1. Buffer:它是包含数据且用于读写的线形表结构。其中还提供了一个特殊类用于内存映射文件的I/O操作。2.

从前有座山 1771

手把手教您如何在飞牛NAS上部署OpenClaw(Clawdbot/Moltbot)智能助手,接入钉钉,0成本使用(万字保姆级教程)

想在飞牛NAS上部署一个24小时待命的AI助手?🤖 本文手把手教您如何在飞牛NAS上部署一个完全免费的OpenClaw智能助手 ✅

XiaoqiangClub的博客 7239

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Sun发布J2SE 1.4.2,宣布Tiger发布里程碑

Sun宣布了J2SE 1.5的发布里程碑,Tiger将于今年年底之前发布一个beta版本。另外,J2SE 1.4.2(代号“Mantis”——蟑螂)已经发布,修补了4000多个bug,增加了对Itanium CPU的完全支持,提供了两种新的Swing观感:Windows XP和GTK,并加入了两种新的高效GC算法。看到这条消息,我唯一的感想就是:已经发展了10年的Java居然还有超过4000个

透明思考@优快云 4329

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

高级图像处理图像I/O API

要理解JAI图像I/O工具的使用,需要首先了解图像I/O库。在安装和介绍图像I/O工具包之前,我们先看一看图像I/O库。图像I/O库图像I/O库是J2SE  1.4的标准API,放在javax.imageio包内。虽然这个包提供了两个接口和9个类,整个API实际上就是ImageIO类。通过这个类可以弄清读写所支持的图像格式并对这些图像进行读写,实际上这也就是整个API的全部内容。由于图像I/O库是

2538

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Java I/O API之性能分析 (上)

 IO API的可伸缩性对Web应用有着极其重要的意义。Java 1.4版以前的API中,阻塞I/O令许多人失望。从J2SE 1.4版本开始,Java终于有了可伸缩的I/O API。本文分析并计算了新旧I/O API在可伸缩性方面的差异。   一、概述   IO API的可伸缩性对Web应用有着极其重要的意义。Java 1.4版以前的API中,阻塞I/O令许多人失望。从J2SE 1.4版本开始,J

zaowei21的专栏 1702

J2SE 5.0专题 之 用户接口

J2SE 5.0专题 之 用户接口作者(枯木)1.1.        引子“从Java诞生至今已有9年时间,而从第二代Java平台J2SE算起也有5个年头了。在这样的背景下,将下一个版本的版本号从1.5改为5.0可以更好的反映出新版J2SE的成熟度、稳定性、可伸缩性和安全性。” Sun公司如是解释Java的这次意义深远的变革。众所周知Sun公司从发布Java以来,对Java的每一次变更

《优快云社区电子杂志——Java杂志》官方blog 1万+

JDK1.4新特性之I/O APIs篇

当然阅读本文之前,你最好先了解一下原有的Java I/O APIs。   新在何处   任何新事物的出现,都是对旧事物的一种修正和改进,从而使其更加方便可用,在J2SE v1.4中出现的新I/O(NIO) APIs亦是如此,主要是针对那些旧的I/O APIs不能解决或者解决起来很麻烦的问题。这些新特性主要体现在以下几个方面:    · 更加灵活的可伸缩的I/O接口(scalable ...

我是一只愚 187

J2SE各版本差异说明-发展演进史

<br />(结合《J2SE发展演变史》 Matrix社区 总结)<br />J2SE1.4:<br />    发布时间2002年2月13日<br />1)HotSpot虚拟机:<br />2)锁机制:由于旧版的HotSpot虚拟机的锁机制会导致严重的性能和功能问题,J2SE1.4已经改写了该锁机制<br />3)安全API:JCE/JSSE/JAAS从OptionalAPI移到Core API。<br />4)RandomAccess标记接口:如果一个List实现这个接口,则表示它支持快速的随机访问,可

coder专栏1 614
上一篇: WEBLOGIC6.0的一些使用经验
下一篇: 利用JSP建立Web站点
java169
博客等级 码龄19年 27粉丝 2568原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值