应届生找工作要点总结(2)Java IO

对Java IO的认识

对于I/O操作来说, 其根本的作用在于传输数据。输入和输出指的仅是数据的流向,实际传输是通过某些具体的媒介来完成的,其中最主要的是文件系统和网络连接;早期的java.io包把I/O操作抽象成数据的流动,进而有了流的概念;

在Java NIO中,则把I/O操作抽象成端到端的一个数据连接,这就有了通道(channel)的概念;Java中最基本的流是在字节这个层次上进行操作的;在read方法的调用是阻塞的,这可能会成为应用中的瓶颈(可以通过available方法获取在不阻塞的情况下可以获取到的字节数);流无法重新使用,BufferedInputStream通过mark和reset操作可以实现流中部分内容的重复读取;另外一种重用输入流的方式是把它转换成数据来使用;输出流是通过write方法把数据存放在缓冲区(缓冲区满了会自动执行写入),使用flush方法强制进行实际的写入操作;

其他常用流:FileInput(Output)Stream、ByteArrayInput(Output)Stream、字符流(new BufferedReader(new InputStreamReader(inputStream)));

NIO:new io,主要用到的是块,所以nio效率比io高。java api中有两套nio:针对标准输入输出的nio;网络编程nio。io以流的方式处理数据;nio以块的方式处理数据。面向流的io一次处理一个字节,一个输入流产生一个字节,一个输出流消费一个字节。面向块的io,每个操作都在一步中产生或消费一个数据块。

io面向流、阻塞、无选择器;nio面向缓冲、非阻塞、有选择器。

Java NIO的通道:channel表示为一个已经建立好的到支持I/O操作的实体(如文件和网络)的连接,在此连接上进行数据的读写操作,使用的是缓冲区来实现读写;

channel是对原io中流的模拟,任何来源和目的数据都必须通过一个channel对象。一个buffer是一个容器对象,发给channel的所有对象必须先放到buffer中,同样的,从channel中读取任何数据都要读到buffer。

在nio中,数据是放入buffer对象的。在io中,数据是直接写入或读到stream对象。应用程序不能直接对channel进行读写操作,而必须通过buffer来进行。

使用buffer读写数据,一般经过以下4步:写入数据到buffer;调用flip(切换到读模式)方法;从buffer中读取数据;调用clear(清空缓冲区)方法和compact(清除已读的缓冲区)方法。

buffer是父类,他的子类有bytebuffer, shortbuffer, intbuffer, longbuffer, floatbuffer, doublebuffer, charbuffer。buffer是一个对象,它包含要写入或读取的数据;channel是一个对象,可以通过它读取或写入数据。可以把channel看作io流,但它和io流相比还有些不同:channel是双向的,既可读又可写,io流是单向的;channel可以进行异步读写;对channel的读写必须通过buffer对象。

buffer的三个属性:capacity:buffer有一个固定大小,也就是capacity,你只能往里面写capacity个byte, long, char等类型。position:当你写数据时,position表示当前位置,即下一个开始写的位置。初始时position为0,当写入一个数据时,position会向前移动到下一个可插入数据的buffer中,position最大为capacity-1;当读数据时,也就是从某个特定的位置开始读,应当将position从写模式切换到读模式,position被置为0。limit:在写模式下,limit表示最多能写多少数据,此时limit=capacity;在读模式中,limit表示最多能读多少数据。所以切换到读模式时,limit被设置为写模式下的position。

filechannel:从文件中读取数据的。datagramchannel:读写udp的网络协议数据。socketchannel:读写tcp网络协议数据。serversocketchannel:可以监听tcp连接。

从文件读取数据分三步:从fileinputstream中获取channel;创建buffer;从channel中读取数据到buffer。通过nio进行文件复制代码:

FileInputStream fileInputSream = new FileInputStream("...");

FileChannel inChannel = fileInputStream.getChannel(); // 通过inputstream获取channel

ByteBuffer byteBuffer = ByteBuffer.allocate(1024); // 创建buffer

FileOutputStream fileOutputStream = new FileOutputStream("...");

FileChannel outChannel = fileOutputStream.getChannel();

while (true) {

int eof = inChannel.read(byteBuffer);

if (eof == -1) { // 没读到

break;

} else {

byteBuffer.filp(); // 改为写模式

outChannel.write(byteBuffer);

byteBuffer.clear();

}

}

inChannel.close();

outChannel.close();

fileInputStream.close();

fileOutputStream.close();

网络编程io(异步io)异步io是一种没有阻塞的读写数据的方法。selector是一个对象,可以注册到很多channel监听各个channel上发生的事情,并且能够根据事件情况决定channel读写,这样通过一个线程管理多个channel,就可以处理大量网络连接。

有了selector,可以用一个线程处理所有的channel。线程之间的切换对操作系统来说,代价是很高的,并且每个线程也会占用一定的系统资源,所以对系统来说,线程越少越好(但若cpu有多个内核,不使用多任务是在浪费cpu的能力)。

Selector selector = Selector.open();

channel.configureBlocking(false);

SelectionKey key = channel.register(selector, SelectionKey.OP_READ);

注册到server上的channel必须设置为异步模式,否则异步io无法工作,这就意味着我们不可以把一个filechannel注册到selector上。因为filechannel没有异步模式,但socketchannel有异步模式。

register的第二个参数,他是一个"interest set",意思是注册的selector对channel中哪些事件感兴趣。事件类型有4种:read,write,connect,accept。通道触发一个事件指向该事件已经ready,所以某个channel成功连接到另一个服务器称为connect ready。一个serversocketchannel准备好接收新链接称为connect ready。一个数据可读的通道可以说是read ready。等待写数据的通道write ready。

write:SelectionKey.OP_WRITE

read:SelectionKey.OP_READ

accept:SelectionKey.OP_ACCEPT

connect:SelectionKey.OP_CONNECT

若对多个事件感兴趣,可以写为:int interest = SelectionKey.OP_READ | SelectionKey.OP_ACCEPT;

SelectionKey表示通道在seletor上的注册,通过SelectionKey可以得到selector和注册的channel.selector感兴趣的事。

一旦向selector注册了一个或多个通道,就可调用重载的select方法返回你所感兴趣的事件(连接、接收、读写)给已经准备就绪的通道。比如你对Read ready感兴趣,select方法读事件已经就绪的通道,select就返回int值,表示有多少通道已经就绪。

int select():阻塞到至少一个通道在你注册的事件上就绪,int select(long timeout):与select()一样,只是最长只会阻塞timeout ms;int selectNow(),不阻塞,不管什么通道就绪立即返回,若自从前一次选择操作后,没有通道变为可选的,则直接返回0。

Socket和ServerSocket类中提供的建立连接和数据传输相关的方法都是阻塞式的;对服务端通常使用线程池的方式来调用ServerSocket.accept方法来监听连接请求;Java NIO提供了非阻塞式和多路复用的套接字连接;

socketchannel:可以通过以下两种方式创建socketchannel:打开一个socketchannel,并连接到互联网上一台服务器;一个新链接到达serverSocketchannel时,会创建一个socketchannel。

SocketChannel socketchannel = SocketChannel.open();

socketchannel.connect(new InetSocketAddress("www.baidu.com", 80));

socketchannel.close();

int eof = socketchannel.read(bytebuffer); // 读了多少字节进buffer,-1表示读到流末尾

ServerSocketChannel serversocketchannel = ServerSocketchannel.open();

serversocketchannel.socket().bind(new InetSocketAddress(900));

读有很多字节数额的文本文件,用bufferedreader。

BufferedReader br = new BufferedReader(new FileReader("/home/zjz/Desktop/myfile.txt"));

String contentLine = br.readLine();

while (contentLine != null) {

System.out.println(contentLine);

contentLine = br.readLine();

}

BufferedReader br2 = new BufferedReader(new FileReader("/home/zjz/Desktop/myfile2.txt"));

int num = 0;

char ch;

while ((num = br2.read()) != -1) {

ch = (char) num;

System.out.print(ch);

}

字符串写入文件代码:

FileWriter fw = new FileWriter("demo.txt");

fw.write("abjjd");

fw.flush();

fw.close();

猜你喜欢

转载自blog.csdn.net/SEUSUNJM/article/details/86534576