英语中需要注意的句型语法

  1. 反意疑问句:
    She doesn’t like coffee, does she. — No, she doesn’t(是的,她不喜欢) –Yes, she does(不,她喜欢)
  2. 祈使句:
    Open the door, please.
    Pass me the salt, will you?
    Let’s take a break, shall we?
    祈使句加上疑问,除了let’s 用shall we, 其他用will you。

NIO — 通道间互传数据

transferFrom:

public void transferFrom(){
		RandomAccessFile fromFile;
		try {
			fromFile = new RandomAccessFile("E:\\study\\new.txt", "rw");
			FileChannel fromChannel = fromFile.getChannel();
			
			RandomAccessFile toFile = new RandomAccessFile("E:\\study\\output2.txt", "rw");
			FileChannel toChannel = toFile.getChannel();
			
			toChannel.transferFrom(fromChannel, 0, fromChannel.size());
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

 
position表示从position处开始向目标文件写入数据,count表示最多传输的字节数。如果源通道的剩余空间小于 count 个字节,则所传输的字节数要小于请求的字节数。

transferTo:

public void transferTo(){
		RandomAccessFile fromFile;
		try {
			fromFile = new RandomAccessFile("E:\\study\\new.txt", "rw");
			FileChannel fromChannel = fromFile.getChannel();
			
			RandomAccessFile toFile = new RandomAccessFile("E:\\study\\output3.txt", "rw");
			FileChannel toChannel = toFile.getChannel();
			
			fromChannel.transferTo(0, fromChannel.size(), toChannel);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

NIO — Scatter & Gather

分散(scatter):从Channel中读取是指在读操作时将读取的数据写入多个buffer中
4
scatter / gather经常用于需要将传输的数据分开处理的场合,例如传输一个由消息头和消息体组成的消息,你可能会将消息体和消息头分散到不同的buffer中,这样你可以方便的处理消息头和消息体。

ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body   = ByteBuffer.allocate(1024);
 
ByteBuffer[] bufferArray = { header, body };
 
channel.read(bufferArray);

会依次写入header和body两个buffer,写完第一个buffer,才会写第二个buffer(意味着它不适用于动态消息)

聚集(gather):写操作时将多个buffer的数据写入同一个Channel
5

ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body   = ByteBuffer.allocate(1024);
write()方法会按照buffer在数组中的顺序,将数据写入到channel,注意只有position和limit之间的数据才会被写入。因此,如果一个buffer的容量为128byte,但是仅仅包含58byte的数据,那么这58byte的数据将被写入到channel中。因此与Scattering Reads相反,Gathering Writes能较好的处理动态消息。
 
//write data into buffers
 
ByteBuffer[] bufferArray = { header, body };
 
channel.write(bufferArray);

NIO — Buffer

Buffer(缓冲区)是一块用来读写的内存,包装成了Buffer对象,提供了api方便访问。
Buffer读写的通常步骤:

写入数据到Buffer
调用flip()方法
从Buffer中读取数据
调用clear()方法或者compact()方法

当向buffer写入数据时,buffer会记录下写了多少数据。一旦要读取数据,需要通过flip()方法将Buffer从写模式切换到读模式。在读模式下,可以读取之前写入到buffer的所有数据。

清空缓存区clear(),compact()区别:
clear()
方法会清空整个缓冲区。
position将被设回0,limit被设置成capacity的值。
如果Buffer中有一些未读的数据,调用clear()方法,数据将“被遗忘”,意味着不再有任何标记会告诉你哪些数据被读过,哪些还没有。
compact()
方法只会清除已经读过的数据。任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面。
position设到最后一个未读元素正后面。limit属性依然像clear()方法一样,设置成capacity。
如果Buffer中仍有未读的数据,且后续还需要这些数据,但是此时想要先先写些数据,那么使用compact()方法。

Buffer的capacity,position和limit:
3
Capacity: 就是只Buffer里面的容量、内存块,里面可以装的byte、long,char的数目,一旦满了需要清空才可以重新写入,如就是ByteBuffer.allocate(1024)这个1024就是他的容量。
Position:
写数据到Buffer中时,position表示当前的位置。初始的position值为0.当一个byte、long等数据写到Buffer后, position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1.
读取数据时,也是从某个特定位置读。当将Buffer从写模式切换到读模式,position会被重置为0. 当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。
Limit:
写模式下就是capacity,表示一共能写多少
读模式下就是position,表示已经读了多少了

Buffer的实例化和空间分配:

ByteBuffer buffer = ByteBuffer.allocate(1024);

写入Buffer:
(1)从channel写入Buffer:
int r = inFc.read(buffer);

(2)Buffer的put()
	buf.put(127);

flip()
flip方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。

读取Buffer:
(1)从Buffer读取数据到Channel。

outFc.write(buffer);

(2)Buffer的get()
byte aByte = buf.get();

rewind()
Buffer.rewind()将position设回0,可以重读Buffer中的所有数据。limit保持不变,仍然表示能从Buffer中读取多少个元素(byte、char等)。

make();reset()
类似于数据库的回滚功能,Buffer.mark()方法,可以标记Buffer中的一个特定position。之后可以通过调用Buffer.reset()方法恢复到这个position。

equals();compareTo()
equals()条件:

有相同的类型(byte、char、int等)。
Buffer中剩余的byte、char等的个数相等。
Buffer中所有剩余的byte、char等值都相同。
所以equals不比较所有元素,只是比较剩余元素

compareTo(认为一个Buffer“小于”另一个Buffer:)条件:

第一个不相等的元素小于另一个Buffer中对应的元素 。
所有元素都相等,但第一个Buffer比另一个先耗尽(第一个Buffer的元素个数比另一个少)。

NIO – Channel

特性:
1. 可从通道读取到buffer,也可以从buffer写到通道。
2. 异步读写

类型与协议:
FileChannel — File
DatagramChannel — UDP读写网络中的数据
SocketChannel — TCP读写网络中的数据
ServerSocketChannel — 监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel

public class NIOFileCopy {
	public void copyFile(){
		try {
			FileInputStream is = new FileInputStream("E:\\study\\yuan.txt");
			FileOutputStream os = new FileOutputStream("E:\\study\\output.txt");
			
			FileChannel inFc = is.getChannel();
			FileChannel outFc = os.getChannel();
			
			ByteBuffer buffer = ByteBuffer.allocate(1024);
			
			while(true){
				buffer.clear();
				int r = inFc.read(buffer);
				if(r == -1){
					break;
				}
				buffer.flip();
				outFc.write(buffer);
				
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		NIOFileCopy nioFileCopy = new NIOFileCopy();
		nioFileCopy.copyFile();
	}
}

NIO基本概念

Java NIO 由以下几个核心部分组成:

Channels
Buffers
Selectors
其他没那么常用的组件:Pipe和FileLock

Channel 和 Buffer
所有的 IO 在NIO 中都从一个Channel 开始。Channel 有点象流。 数据可以从Channel读到Buffer中,也可以从Buffer 写到Channel中
1

Channel类型:

FileChannel
DatagramChannel
SocketChannel
ServerSocketChannel

Buffer类型:

ByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
MappedByteBuffer
Selector:
Selector允许单线程处理多个 Channel,如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便
一个单线程中使用一个Selector处理3个Channel的图示
2
要使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子有如新连接进来,数据接收等

多线程 start()和run()的区别

1.start()方法来启动线程,真正实现了多线程运行。这时无需等待run方法体代码执行完毕,可以直接继续执行下面的代码;通过调用Thread类的start()方法来启动一个线程, 这时此线程是处于就绪状态, 并没有运行。 然后通过此Thread类调用方法run()来完成其运行操作的, 这里方法run()称为线程体,它包含了要执行的这个线程的内容, Run方法运行结束, 此线程终止。然后CPU再调度其它线程。
2.run()方法当作普通方法的方式调用。程序还是要顺序执行,要等待run方法体执行完毕后,才可继续执行下面的代码; 程序中只有主线程——这一个线程, 其程序执行路径还是只有一条, 这样就没有达到写线程的目的。

循环start多个线程,真实线程执行不一定按照顺序,start表示就绪,真实的run是由cpu来控制。