- 浏览: 398548 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
zhchyun2008:
这里有个小问题,背景有时候会出现?不知道如何解决
分享一个ToolTip类,趋于完美! -
heiliuer:
歌词可以用,我试了好几个,都行的
百度MP3音乐API接口及应用 -
connectu:
感觉不错,英文版的。
JMX in Action -
海阔天空1991:
楼主,有没有什么途径可以知道歌曲对应的信息?
百度MP3音乐API接口及应用 -
xiegqooo:
简单的关闭 tomcat
import java.io.IO ...
关于Java钩子的使用
这是一篇比较使用的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<n; i++)
{System.out.println(buff.get());}
在使用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拉丁字符表#1Charset
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 {
// SetupInetSocketAddress socketAddress = new InetSocketAddress(host, 80);
Charset charset = Charset.forName("ISO-8859-1");
CharsetDecoder decoder = charset.newDecoder();
CharsetEncoder encoder = charset.newEncoder();
// Allocate buffersByteBuffer buffer = ByteBuffer.allocateDirect(1024);
CharBuffer charBuffer = CharBuffer.allocate(1024);
// Connectchannel = SocketChannel.open();
channel.connect(socketAddress);
// Send requestString request = "GET / ";
channel.write(encoder.encode(CharBuffer.wrap(request)));
// Read response
while ((channel.read(buffer)) != -1) {
buffer.flip();
// Decode bufferdecoder.decode(buffer, charBuffer, false);
// DisplaycharBuffer.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 objectsSet readyKeys = selector.selectedKeys();
Iterator readyItor = readyKeys.iterator();
// Walk through setwhile (readyItor else if (key}}
这里,remove方法的调用需要进行一下小小的解释。这个已经就绪的集合当你操作它的时候也会发生变化。所以,你应该在你操作这个元素的的时候,把它remove出来。这个移动操作并不会引发ConcurrentModificationException的异常的抛出。同时由于有一个超时设置,select方法的调用也不会在毫无事件发生的情况下僵死。同样也有一个调用来从集合中的键值获得相应的通道对象。你需要完成上述的所有操作。为了在例程中从HTTP连接中进行读取操作,你需要发送初始HTTP请求。基本上,一旦你知道这个连接完成了,你就发送一个GET请求来获得这个站点的根目录。当selector报告通道还是可连接的时候,就还没有完成连接。所以你需要经常的通过isConnectionPending方法检查这个连接是否未完成,并在它完成后调用finishConnect。而在连接完成之后,你就可对这个通道进行写入操作,但是必须使用ByteBuffer,而不是我们常见的I/O流了。下面是一段连接代码的示例:
// OUTSIDE WHILE LOOPCharsetcharset = Charset.forName("ISO-8859-1");
CharsetEncoder encoder = charset.newEncoder();
// INSIDE
if (channel.isConnectable())
// Finish connection
if (keyChannel
// Send requestString 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 responsekey
Channel.read(buffer);buffer.flip();
// Decode
bufferdecoder.decode(buffer, charBuffer, false);
// Display
charBuffer.flip();System.out.print(charBuffer);
// Clear for next
passbuffer.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 {
// SetupInet
SocketAddress 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
// Send request
String request = "GET / ";keyChannel.write(encoder.encode(CharBuffer.wrap(request)));
} else if (key 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
objectsSet readyKeys = selector.selectedKeys();
Iterator readyItor = readyKeys.iterator();
// Walk through set
while (readyItor
else {System.err.println("Ooops");}
}}// Never ends}}
在接受请求之后,你可以从套接口取得一个对应的通道,使它转到非阻塞模式,然后也注册到selector。这个结构框架提供了NIO类在制作一个WEB服务器上的基本用法。关于如何创建一个多线程的服务器的更多信息,可以参考在本文最后“资源”一节里JavaWorld的有关文章。
结论在J2SE 1.4Beta版本中引入的I/O新特性提供了令人振奋的新方法来增进你应用程序的性能。通过这些新特性的使用,你的应用程序不但能够变得更快,性能上也会得到攀升,因为你不必再为每一个连接新建一个线程。这对于服务器端来说更是尤其的重要,可以支持大幅度增长的同时连接的数目。注:如果你浏览过JSR51中的性能列表,你会注意到它提到了扫描和格式化输入输出的支持,和C语言中的printf非常相似。这个特性并没有被1.4Beta实现,将在下一个版本中引入。
回溯到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<n; i++)
{System.out.println(buff.get());}
在使用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拉丁字符表#1Charset
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 {
// SetupInetSocketAddress socketAddress = new InetSocketAddress(host, 80);
Charset charset = Charset.forName("ISO-8859-1");
CharsetDecoder decoder = charset.newDecoder();
CharsetEncoder encoder = charset.newEncoder();
// Allocate buffersByteBuffer buffer = ByteBuffer.allocateDirect(1024);
CharBuffer charBuffer = CharBuffer.allocate(1024);
// Connectchannel = SocketChannel.open();
channel.connect(socketAddress);
// Send requestString request = "GET / ";
channel.write(encoder.encode(CharBuffer.wrap(request)));
// Read response
while ((channel.read(buffer)) != -1) {
buffer.flip();
// Decode bufferdecoder.decode(buffer, charBuffer, false);
// DisplaycharBuffer.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 objectsSet readyKeys = selector.selectedKeys();
Iterator readyItor = readyKeys.iterator();
// Walk through setwhile (readyItor else if (key}}
这里,remove方法的调用需要进行一下小小的解释。这个已经就绪的集合当你操作它的时候也会发生变化。所以,你应该在你操作这个元素的的时候,把它remove出来。这个移动操作并不会引发ConcurrentModificationException的异常的抛出。同时由于有一个超时设置,select方法的调用也不会在毫无事件发生的情况下僵死。同样也有一个调用来从集合中的键值获得相应的通道对象。你需要完成上述的所有操作。为了在例程中从HTTP连接中进行读取操作,你需要发送初始HTTP请求。基本上,一旦你知道这个连接完成了,你就发送一个GET请求来获得这个站点的根目录。当selector报告通道还是可连接的时候,就还没有完成连接。所以你需要经常的通过isConnectionPending方法检查这个连接是否未完成,并在它完成后调用finishConnect。而在连接完成之后,你就可对这个通道进行写入操作,但是必须使用ByteBuffer,而不是我们常见的I/O流了。下面是一段连接代码的示例:
// OUTSIDE WHILE LOOPCharsetcharset = Charset.forName("ISO-8859-1");
CharsetEncoder encoder = charset.newEncoder();
// INSIDE
if (channel.isConnectable())
// Finish connection
if (keyChannel
// Send requestString 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 responsekey
Channel.read(buffer);buffer.flip();
// Decode
bufferdecoder.decode(buffer, charBuffer, false);
// Display
charBuffer.flip();System.out.print(charBuffer);
// Clear for next
passbuffer.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 {
// SetupInet
SocketAddress 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
// Send request
String request = "GET / ";keyChannel.write(encoder.encode(CharBuffer.wrap(request)));
} else if (key 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
objectsSet readyKeys = selector.selectedKeys();
Iterator readyItor = readyKeys.iterator();
// Walk through set
while (readyItor
else {System.err.println("Ooops");}
}}// Never ends}}
在接受请求之后,你可以从套接口取得一个对应的通道,使它转到非阻塞模式,然后也注册到selector。这个结构框架提供了NIO类在制作一个WEB服务器上的基本用法。关于如何创建一个多线程的服务器的更多信息,可以参考在本文最后“资源”一节里JavaWorld的有关文章。
结论在J2SE 1.4Beta版本中引入的I/O新特性提供了令人振奋的新方法来增进你应用程序的性能。通过这些新特性的使用,你的应用程序不但能够变得更快,性能上也会得到攀升,因为你不必再为每一个连接新建一个线程。这对于服务器端来说更是尤其的重要,可以支持大幅度增长的同时连接的数目。注:如果你浏览过JSR51中的性能列表,你会注意到它提到了扫描和格式化输入输出的支持,和C语言中的printf非常相似。这个特性并没有被1.4Beta实现,将在下一个版本中引入。
发表评论
-
线程池之ThreadPoolExecutor
2009-11-12 11:39 1399package blockingqueue; impor ... -
CyclicBarrier
2009-11-11 17:35 1584package service; import java ... -
Callable与Future
2009-10-21 16:01 1428关键字: callable future java.util ... -
Semaphore 信号量
2009-10-21 15:49 1627Semaphore 信号量,就是一个允许实现设置好的令牌。也许 ... -
线程通信
2009-10-12 12:26 1431不同线程间进行通信通常有两种简单方法: 方法一 通过访问共享变 ... -
Java 理论与实践: 流行的原子
2009-08-21 18:01 1022在 JDK 5.0 之前,如 ... -
Java NIO 学习笔记 (2)
2009-08-21 17:31 1124前一篇介绍了 学习笔记[01],这篇介绍另一学习笔记,希望能对 ... -
Java NIO API 详解
2009-08-10 18:48 2154[img][/img]原文出处:http://blog.csd ... -
ByteBuffer中关于allocate和directAllocate的区别
2009-07-29 10:41 2463allocate和directA ... -
对java.nio.ByteBuffer的粗浅理解
2009-07-27 13:27 3559今晚用到 ByteBuffer, 我跟 joy 都是初学 ja ...
相关推荐
基于粒度计算的旅游定制公交初设线路优选——以长岛县定制旅游公交为例.pdf
CSDNApp_242.apk
C++如何读取ZIP内容文件
资源说明: 1:csdn平台资源详情页的文档预览若发现'异常',属平台多文档切片混合解析和叠加展示风格,请放心使用。 2:29页图文详解文档(从零开始项目全套环境工具安装搭建调试运行部署,保姆级图文详解),旨在为更多的人甚至零基础的人也能运行、使用和学习。 3:配套毕业论文,万字长文,word文档,支持二次编辑。 4:范例参考答辩ppt,pptx格式,支持二次编辑。 5:工具环境、ppt参考模板、相关电子教程、视频教学资源分享。 6:资源项目源码均已通过严格测试验证,保证能够正常运行,本项目仅用作交流学习参考,请切勿用于商业用途。 7:项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通。 内容概要: 本系统基于B/S网络结构,在IDEA中开发。服务端用Java并借Spring Boot框架搭建后台。前台采用支持HTML5的VUE框架。用MySQL存储数据,可靠性强。 能学到什么: 使用Spring Boot搭建后台。VUE框架构建前端交互界面、前后端数据交互、MySQL管理数据、从零开始环境搭建、调试、运行、打包、部署流程。
水下机器人AUV的路径规划及基于模型预测控制MPC的跟踪框架实现与解析,4-IEEE trans顶刊复现,水下机器人AUV的路径规划和基于模型预测控制MPC的跟踪框架。 参考文献和建模过程请参考图片中的文章,本代码包括路径规划和MPC路径跟踪两个模块,两个模块均采用优化求解器求解,考虑了AUV的水动力学模型,结果是2D空间内的平面路径。 输出的结果请见下图 ,关键词:IEEE trans顶刊复现; 水下机器人AUV; 路径规划; 模型预测控制MPC; 跟踪框架; 优化求解器; 水动力学模型; 2D空间平面路径。,基于IEEE Trans顶刊复现的AUV路径规划与MPC跟踪框架研究
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
资源说明: 1:csdn平台资源详情页的文档预览若发现'异常',属平台多文档切片混合解析和叠加展示风格,请放心使用。 2:29页图文详解文档(从零开始项目全套环境工具安装搭建调试运行部署,保姆级图文详解),旨在为更多的人甚至零基础的人也能运行、使用和学习。 3:配套毕业论文,万字长文,word文档,支持二次编辑。 4:范例参考答辩ppt,pptx格式,支持二次编辑。 5:工具环境、ppt参考模板、相关电子教程、视频教学资源分享。 6:资源项目源码均已通过严格测试验证,保证能够正常运行,本项目仅用作交流学习参考,请切勿用于商业用途。 7:项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通。 内容概要: 本系统基于 B/S 网络结构,在 IDEA 中开发。服务端用 Java 并借 Spring Boot 框架搭建后台。前台采用支持 HTML5 的 VUE 框架。用 MySQL 存储数据,可靠性强。 能学到什么: 使用Spring Boot搭建后台。VUE 框架构建前端交互界面、前后端数据交互、MySQL管理数据、从零开始环境搭建、调试、运行、打包、部署流程。
2023-04-06-项目笔记-第三百八十二阶段-课前小分享_小分享1.坚持提交gitee 小分享2.作业中提交代码 小分享3.写代码注意代码风格 4.3.1变量的使用 4.4变量的作用域与生命周期 4.4.1局部变量的作用域 4.4.2全局变量的作用域 4.4.2.1全局变量的作用域_1 4.4.2.380局变量的作用域_380- 2025-01-18
基于springboot+vue社区老年人帮扶系统_6u870vlh.zip
Simulink光伏储能VSG仿真模型:完美波形运行,实现光储一次调频、削峰填谷及直流母线电压控制功能,simulink仿真模型光伏储能VSG,加电容,正常运行,波形完美一一光储一次调频、储能削峰填谷、 直流母线电压控制。 2018b及以上都可运行哈 ,simulink仿真;光伏储能;VSG;加电容;正常运行;波形完美;光储一次调频;储能削峰填谷;直流母线电压控制;2018b及以上版本。,Simulink光伏储能VSG模型:电容增强与优化调频调压功能解析
2025年高级生命支持(ACLS)理论考核试题库及答案.docx
ARM compiler version5.06
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
资源说明: 1:csdn平台资源详情页的文档预览若发现'异常',属平台多文档切片混合解析和叠加展示风格,请放心使用。 2:29页图文详解文档(从零开始项目全套环境工具安装搭建调试运行部署,保姆级图文详解),旨在为更多的人甚至零基础的人也能运行、使用和学习。 3:配套毕业论文,万字长文,word文档,支持二次编辑。 4:范例参考答辩ppt,pptx格式,支持二次编辑。 5:工具环境、ppt参考模板、相关电子教程、视频教学资源分享。 6:资源项目源码均已通过严格测试验证,保证能够正常运行,本项目仅用作交流学习参考,请切勿用于商业用途。 7:项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通。 内容概要: 本系统基于B/S网络结构,在IDEA中开发。服务端用Java并借Spring Boot框架搭建后台。前台采用支持HTML5的VUE框架。用MySQL存储数据,可靠性强。 能学到什么: 使用Spring Boot搭建后台。VUE框架构建前端交互界面、前后端数据交互、MySQL管理数据、从零开始环境搭建、调试、运行、打包、部署流程。
Greenplum Platform Extension Framework 6.11.0 for RHEL 8 pxf-gp7-6.11.0-2.el8.x86_64.rpm(97.4 MB) Dec 18, 2024 Dec 19, 2024 c9b2994c61efbb990bb02480c29eeede5415b2af42496b0d1f6a49b200889c46 c5f2ff9b8de2b5120d74fca86e36582c
资源说明: 1:csdn平台资源详情页的文档预览若发现'异常',属平台多文档切片混合解析和叠加展示风格,请放心使用。 2:29页图文详解文档(从零开始项目全套环境工具安装搭建调试运行部署,保姆级图文详解),旨在为更多的人甚至零基础的人也能运行、使用和学习。 3:配套毕业论文,万字长文,word文档,支持二次编辑。 4:范例参考答辩ppt,pptx格式,支持二次编辑。 5:工具环境、ppt参考模板、相关电子教程、视频教学资源分享。 6:资源项目源码均已通过严格测试验证,保证能够正常运行,本项目仅用作交流学习参考,请切勿用于商业用途。 7:项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通。 内容概要: 本系统基于B/S网络结构,在IDEA中开发。服务端用Java并借Spring Boot框架搭建后台。前台采用支持HTML5的VUE框架。用MySQL存储数据,可靠性强。 能学到什么: 使用Spring Boot搭建后台。VUE框架构建前端交互界面、前后端数据交互、MySQL管理数据、从零开始环境搭建、调试、运行、打包、部署流程。
Android File Transfer for mac
高海拔输油管道气保护药芯焊丝半自动焊工艺研究与应用.pdf
commons-fileupload-1.5.jar
“全桥LLC谐振变换器变频与移相混合控制策略:电压范围拓宽及模式切换仿真研究”,全桥LLC谐振变器变频-移相混合控制仿真。 [1]参考文献:《全桥LLC谐振变器的混合式控制策略_李菊》 拓宽电压范围。 保证mos管的ZVS零电压开通和二极管的ZCS零电流关断。 [2]模式切: ①当输入<输出电压时,变器处于升压模式,采用变频控制模式,, ②当输入>输出电压时,变器处于降压模式,采用定频模式也就是移相模型。 [3]具体策略如下:当输入电压较低时,采用变频控制,变器满占空比工作,通过改变开关频率来调 节输出电压,称此时变器工作在变频(Variable-Frequency,VF)模式;当输入电压较高时, 采用定频控制,变器工作在所设定的最高频率,通过调节移相角来控制输出电压,称此时变 器工作在移相(Phase-Shift,PS)模式。 ,全桥LLC谐振变换器; 混合控制策略; 电压范围拓宽; mos管ZVS零电压开通; 二极管ZCS零电流关断; 变频控制; 移相控制; 升压模式; 降压模式; 最高频率调节。,一个基于混合控制的LLC谐振变换器仿真:频率变频与移相策略联合研究