Hola a todos, soy
方圆
Tabla de contenido
1. Información general
1.1 Traducción traducción? ¿Qué es NIO?
NIO: Creo que la traducción es Non-Blocking
más sencilla. Comparado con BIO, también hay una comparación. Es mejor llamarlo IO sin bloqueo.
- Tiene las siguientes diferencias con BIO
- Canal Sí
双向
, puede leer y escribir. En comparación con Stream, no distingue entre el flujo de entrada y el flujo de salida, y el canal puede completar la lectura y escritura sin bloqueo, así como bloquear la lectura y escritura
1.2 Introducción a Buffer
- La lectura y escritura de canales son inseparables de Buffer. Buffer es en realidad un área en la memoria para leer y escribir.
1.2.1 Modo de escritura
- Tres de los punteros que debemos entender
position
son la posición actual del puntero, que selimit
usa en el modo de lectura. Se usa para marcar el rango máximo de lectura, quecapacity
es el umbral máximo del rango de escritura.
Cuando escribimos datos y escribimos cuatro cuadrículas, ejecutamos el flip()
método, y se puede cambiar al 读模式
puntero de límite, cambiar directamente a la posición límite de los datos que acabamos de escribir, y el puntero de posición vuelve a la posición inicial, para que podamos leer los datos.
1.2.2 Dos cambios del modo de lectura al modo de escritura
- Cuando hayamos leído todos los datos, cambiamos al modo de escritura y
llamamos alclear()
método. Devolverá el puntero de posición a la posición inicial y se limitará al extremo más lejano, de modo que los datos se puedan reiniciar. Aunque claro significa claro, de hecho Simplemente mueva la posición del puntero y no borra los datos, pero sobrescribirá la posición original
- Leer solo parte de los datos, creo que parte de la reserva no se leerá, y ahora tengo que comenzar a escribir el modo de operación, para que pueda realizar el
compact()
método
Este método将没有读到的数据保存到初始位置
, queposition指针的位置将会移动到这些数据的后面位置
, después de leer los datos, nunca comenzó a escribir datos
después Al leer los datos nuevamente, podemos leer los datos que no se leyeron la última vez
1.3 Introducción al canal
El intercambio de datos entre canales debe depender de Buffer
1.3.1 Varios canales importantes
- FileChannel: utilizado para la transferencia de archivos
- ServerSocketChannel y SocketChannel: transmisión para programación de red
2. Combate de copia de archivo
- Una copia byte a byte es realmente lenta.
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
interface FileCopyRunner{
void copyFile(File source,File target);
}
public class FileCopyDemo {
private static void close(Closeable closeable){
if(closeable != null) {
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//不使用任何缓冲的留的拷贝
private static FileCopyRunner noBufferStreamCopy = new FileCopyRunner() {
@Override
public void copyFile(File source, File target) {
InputStream fin = null;
OutputStream fout = null;
try {
fin = new FileInputStream(source);
fout = new FileOutputStream(target);
int result;
while((result = fin.read()) != - 1){
fout.write(result);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
close(fin);
close(fout);
}
}
};
//使用缓冲区的流的拷贝
private static FileCopyRunner bufferStreamCopy = new FileCopyRunner() {
@Override
public void copyFile(File source, File target) {
InputStream fin = null;
OutputStream fout = null;
try {
fin = new FileInputStream(source);
fout = new FileOutputStream(target);
//创建缓冲区
byte[] buffer = new byte[1024];
int result;
while((result = fin.read(buffer)) != -1){
//result这里表示从中读出来的具体字节数
//虽然缓冲区中能缓存1024,但是我们读取的时候不一定就有这么多字节
//所以我们使用result做下面的参数
fout.write(buffer,0,result);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
close(fin);
close(fout);
}
}
};
//使用带有缓冲区的channel复制 nio
private static FileCopyRunner nioBufferCopy = new FileCopyRunner() {
@Override
public void copyFile(File source, File target) {
FileChannel fin = null;
FileChannel fout = null;
try {
fin = new FileInputStream(source).getChannel();
fout = new FileOutputStream(target).getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
while(fin.read(byteBuffer) != -1){
byteBuffer.flip();//转变为读模式
while (byteBuffer.hasRemaining()){
fout.write(byteBuffer);
}
byteBuffer.clear();//转变为写模式
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
close(fin);
close(fout);
}
}
};
//使用没有缓冲区的channel复制文件
private static FileCopyRunner nioTransferCopy = ((source, target) -> {
FileChannel fin = null;
FileChannel fout = null;
try {
fin = new FileInputStream(source).getChannel();
fout = new FileOutputStream(target).getChannel();
long transferred = 0L;
long size = fin.size();
while(transferred != size){
//如果拷贝的大小没有达到源文件的大小就要一直拷贝
transferred += fin.transferTo(0,size,fout);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
close(fin);
close(fout);
}
});
public static void main(String[] args) {
File source = new File("J:\\StudySpace\\Java秒杀系统方案优化-高性能高并发实战\\project.zip");
File target = new File("J:\\StudySpace\\Java秒杀系统方案优化-高性能高并发实战\\p1.zip");
File target2 = new File("J:\\StudySpace\\Java秒杀系统方案优化-高性能高并发实战\\p2.zip");
File target3 = new File("J:\\StudySpace\\Java秒杀系统方案优化-高性能高并发实战\\p3.zip");
File target4 = new File("J:\\StudySpace\\Java秒杀系统方案优化-高性能高并发实战\\p4.zip");
new Thread(() -> noBufferStreamCopy.copyFile(source,target)).start();
new Thread(() -> bufferStreamCopy.copyFile(source,target2)).start();
new Thread(() -> nioBufferCopy.copyFile(source,target3)).start();
new Thread(() -> nioTransferCopy.copyFile(source,target4)).start();
}
}
3. Descripción general del selector
- El canal debe estar registrado en Selector
- Al mismo tiempo que se registra, debe informar al Selector el estado
- Los estados correspondientes del canal son ::
CONNECT
socketChannel ha establecido una conexión con el servidor ;: serverSocketChannel ha establecido una conexiónACCEPT
con el cliente ;:READ
estado legible ;: estadoWRITE
escribible
- Después de finalizado el registro en el selector de canales, volverá a objetos selectKey, que tiene varias maneras importantes:
interestOps
: Ver el estado de los enlaces de canal registrados;readyOps
: para ver cuál es el estado de funcionamiento;channel
: Objetos de canal de retorno;selector
: Selector de objetivo de rentabilidad ;attachment
: Adjuntar otros objetos - Llame al método de selección del Selector para devolver el número de eventos que supervisa, que pueden responder a varios eventos al mismo tiempo. Sin embargo, es una llamada de bloqueo, cuando no hay un evento de monitoreo que pueda usarse para responder a la solicitud, se bloqueará y no regresará hasta que haya un canal disponible que pueda responder a la solicitud.
¡Venga!