Java IO系统,你真的懂了吗?

poll()例程(包含 bind,listen,accept,setsockopt 的用法) Using poll() instead of select() The poll() API is part of the Single Unix Specification and the UNIX® 95/98 standard. The poll() API performs the same API as the existing select() API. The only 阅读详情

学习java IO系统,重点是学会IO模型,了解了各种IO模型之后就可以更好的理解java IO

Java IO 是一套Java用来读写数据(输入和输出)的API。大部分程序都要处理一些输入,并由输入产生一些输出。Java为此提供了java.io包

Java中IO系统可以分为BIO,NIO,AIO三种io模型

  1. 关于BIO,我们需要知道什么是同步阻塞IO模型,BIO操作的对象:流,以及如何使用BIO进行网络编程,使用BIO进行网络编程的问题

  2. 关于NIO,我们需要知道什么是同步非阻塞IO模型,什么是多路复用Io模型,以及NIO中的Buffer,Channel,Selector的概念,以及如何使用Nio进行网络编程

  3. 关于AIO,我们需要知道什么是异步非阻塞IO模型,AIO可以使用几种方式实现异步操作,以及如何使用Aio进行网络编程

一、BIO

BIO是同步阻塞IO,JDK1.4之前只有这一个IO模型,BIO操作的对象是流,一个线程只能处理一个流的IO请求,如果想要同时处理多个流就需要使用多线程

流包括字符流和字节流,流从概念上来说是一个连续的数据流。当程序需要读数据的时候就需要使用输入流读取数据,当需要往外写数据的时候就需要输出流

1、阻塞IO模型

 

 

在Linux中,当应用进程调用recvfrom方法调用数据的时候,如果内核没有把数据准备好不会立刻返回,而是会经历等待数据准备就绪,数据从内核复制到用户空间之后再返回,这期间应用进程一直阻塞直到返回,所以被称为阻塞IO模型

2、流

BIO中操作的流主要有两大类,字节流和字符流,两类根据流的方向都可以分为输入流和输出流

按照类型和输入输出方向可分为:

(1)输入字节流:InputStream

(2)输出字节流:OutputStream

(3)输入字符流:Reader

(4)输出字符流:Writer

字节流主要用来处理字节或二进制对象,字符流用来处理字符文本或字符串

使用InputStreamReader可以将输入字节流转化为输入字符流

Reader reader  =  new InputStreamReader(inputStream); 

使用OutputStreamWriter可以将输出字节流转化为输出字符流

Writer writer = new OutputStreamWriter(outputStream) 

我们可以在程序中通过InputStream和Reader从数据源中读取数据,然后也可以在程序中将数据通过OutputStream和Writer输出到目标媒介中

 

 

在使用字节流的时候,InputStream和OutputStream都是抽象类,我们实例化的都是他们的子类,每一个子类都有自己的作用范围

 

 

在使用字符流的时候也是,Reader和Writer都是抽象类,我们实例化的都是他们的子类,每一个子类都有自己的作用范围

 

 

以读写文件为例

(1)从数据源中读取数据

输入字节流:InputStream

public static void main(String[] args) throws Exception{     
File file = new File("D:/a.txt");     
InputStream inputStream = new FileInputStream(file);     
byte[] bytes = new byte[(int) file.length()];     
inputStream.read(bytes);     
System.out.println(new String(bytes));     
inputStream.close(); 
} 

输入字符流:Reader

public static void main(String[] args) throws Exception{     
File file = new File("D:/a.txt");     
Reader reader = new FileReader(file);     
char[] bytes = new char[(int) file.length()];     
reader.read(bytes);     
System.out.println(new String(bytes));     
reader.close(); 
} 

(2)输出到目标媒介

输出字节流:OutputStream

public static void main(String[] args) throws Exception{     
String var = "hai this is a test";     
File file = new File("D:/b.txt");     
OutputStream outputStream = new FileOutputStream(file);     
outputStream.write(var.getBytes());     
outputStream.close(); 
} 

输出字符流:Writer

public static void main(String[] args) throws Exception{     
String var = "hai this is a test";     
File file = new File("D:/b.txt");     
Writer writer = new FileWriter(file);     
writer.write(var);     
writer.close(); 
} 

(3)BufferedInputStream

在使用InputStream的时候,都是一个字节一个字节的读或写,而BufferedInputStream为输入字节流提供了缓冲区,读数据的时候会一次读取一块数据放到缓冲区里,当缓冲区里的数据被读完之后,输入流会再次填充数据缓冲区,直到输入流被读完,有了缓冲区就能够提高很多io速度

使用方式将输入流包装到BufferedInputStream中

/**  * inputStream 输入流  * 1024 内部缓冲区大小为1024byte  */ BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream,1024); 

(4)BufferedOutputStream

BufferedOutputStream可以为输出字节流提供缓冲区,作用与BufferedInputStream类似

使用方式将输出流包装到BufferedOutputStream中

/**  * outputStream 输出流  * 1024 内部缓冲区大小为1024byte  */ BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream,1024); 

字节流提供了带缓冲区的,那字符流肯定也提供了BufferedReader和BufferedWriter

(5)BufferedReader

为输入字符流提供缓冲区,使用方式如下

BufferedReader bufferedReader = new BufferedReader(reader,1024); 

(6)BufferedWriter

为输出字符流提供缓冲区,使用方式如下

BufferedWriter bufferedWriter = new BufferedWriter(writer,1024); 

3、BIO模型 网络编程

当使用BIO模型进行Socket编程的时候,服务端通常使用while循环中调用accept方法,在没有客户端请求时,accept方法会一直阻塞,直到接收到请求并返回处理的相应,这个过程都是线性的,只有处理完当前的请求之后才会接受处理后面的请求,这样通常会导致通信线程被长时间阻塞

BIO模型处理多个连接:

 

 

在这种模式中我们通常用一个线程去接受请求,然后用一个线程池去处理请求,用这种方式并发管理多个Socket客户端连接,像这样:

 

 

使用BIO模型进行网络编程的问题在于缺乏弹性伸缩能力,客户端并发访问数量和服务器线程数量是1:1的关系,而且平时由于阻塞会有大量的线程处于等待状态,等待输入或者输出数据就绪,造成资源浪费,在面对大量并发的情况下,如果不使用线程池直接new线程的话,就会大致线程膨胀,系统性能下降,有可能导致堆栈的内存溢出,而且频繁的创建销毁线程,更浪费资源

使用线程池可能是更优一点的方案,但是无法解决阻塞IO的阻塞问题,而且还需要考虑如果线程池的数量设置较小就会拒绝大量的Socket客户端的连接,如果线程池数量设置较大的时候,会导致大量的上下文切换,而且程序要为每个线程的调用栈都分配内存,其默认值大小区间为 64 KB 到 1 MB,浪费虚拟机内存

BIO模型适用于链接数目固定而且比较少的架构,但是使用这种模型写的代码更直观简单易于理解

二、NIO

JDK 1.4版本以来,JDK发布了全新的I/O类库,简称NIO,是一种同步非阻塞IO模型

1、非阻塞IO模型

同步非阻塞IO模型实现:

非阻塞IO模型

 

 

应用进程调用recvfrom系统调用,如果内核数据没有准备好,会直接返回一个EWOULDBLOCK错误,应用进程不会阻塞,但是需要应用进程不断的轮询调用recvfrom,直到内核数据准备就绪,之后等待数据从内核复制到用户空间(这段时间会阻塞,但是耗时极小),复制完成后返回

2、IO复用模型

 

 

IO复用模型,利用Linux系统提供的select,poll系统调用,将一个或者多个文件句柄(网络编程中的客户端链接)传递给select或者poll系统调用,应用进程阻塞在select上,这样就形成了一个进程对应多个Socket链接,然后select/poll会线性扫描这个Socket链接的集合,当只有少数socket有数据的时候,会导致效率下降,而且select/poll受限于所持有的文件句柄数量,默认值是1024个

3、信号驱动 IO模型

 

 

系统调用sigaction执行一个信号处理函数,这个系统调用不会阻塞应用进程,当数据准备就绪的时候,就为该进程生成一个SIGIO信号,通过信号回调通知应用程序调用recvfrom来读取数据

4、NIO的核心概念

Buffer(缓冲区)

Buffer是一个对象,它包含一些要写入或者读出的数据,在NIO中所有数据都是用缓存区处理的,在读数据的时候要从缓冲区中读,写数据的时候会先写到缓冲区中,缓冲区本质上是一块可以写入数据,然后可以从中读取数据的一个数组,提供了对数据的结构化访问以及在内部维护了读写位置等信息

实例化一个ByteBuffer

//创建一个容量为1024个byte的缓冲区 ByteBuffer buffer=ByteBuffer.allocate(1024); 复制代码

如何使用Buffer:

(1)写入数据到Buffer

(2)调用flip()方法将Buffer从写模式切换到读模式

(3)从Buffer中读取数据

(4)调用clear()方法或者compact()方法清空缓冲区,让它可以再次被写入

 

Channel(通道)

Channel(通道)数据总是从通道读取到缓冲区,或者从缓冲区写入到通道中,Channel只负责运输数据,而操作数据是Buffer

通道与流类似,不同地方:

(1)在于条通道是双向的,可以同时进行读,写操作,而流是单向流动的,只能写入或者读取

(2)流的读写是阻塞的,通道可以异步读写

 

 

数据从Channel读到Buffer

inChannel.read(buffer); 

数据从Buffer写到Channel

outChannel.write(buffer); 

 

以复制文件为例

FileInputStream fileInputStream=new FileInputStream(new File(src)); 
FileOutputStream fileOutputStream=new FileOutputStream(new File(dst)); 
//获取输入输出channel通道 
FileChannel inChannel=fileInputStream.getChannel(); 
FileChannel outChannel=fileOutputStream.getChannel(); 
//创建容量为1024个byte的buffer 
ByteBuffer buffer=ByteBuffer.allocate(1024); 
while(true){     
//从inChannel里读数据,如果读不到字节了就返回-1,文件就读完了     
int eof =inChannel.read(buffer);     
if(eof==-1){         
break;     
}
//将Buffer从写模式切换到读模式     
buffer.flip();     
//开始往outChannel写数据     
outChannel.write(buffer);     
//清空buffer     
buffer.clear(); 
} 
inChannel.close(); 
outChannel.close(); 
fileInputStream.close(); 
fileOutputStream.close(); 

Selector(多路复用选择器)

Selector是NIO编程的基础,主要作用就是将多个Channel注册到Selector上,如果Channel上发生读或写事件,Channel就处于就绪状态,就会被Selector轮询出来,然后通过SelectionKey就可以获取到已经就绪的Channel集合,进行IO操作了

Selector与Channel,Buffer之间的关系

 

 

 

5、NIO模型 网络编程

JDK中NIO使用多路复用的IO模型,通过把多个IO阻塞复用到一个select的阻塞上,实现系统在单线程中可以同时处理多个客户端请求,节省系统开销,在JDK1.4和1.5 update10版本之前,JDK的Selector基于select/poll模型实现,在JDK 1.5 update10以上的版本,底层使用epoll代替了select/poll

epoll较select/poll的优点在于:

(1)epoll支持打开的文件描述符数量不在受限制,select/poll可以打开的文件描述符数量有限

(2)select/poll使用轮询方式遍历整个文件描述符的集合,epoll基于每个文件描述符的callback函数回调

select,poll,epoll都是IO多路复用的机制。I/O多路复用就是通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写

NIO提供了两套不同的套接字通道实现网络编程,服务端:ServerSocketChannel和客户端SocketChannel,两种通道都支持阻塞和非阻塞模式

服务端代码

服务端接受客户端发送的消息输出,并给客户端发送一个消息

 //创建多路复用选择器Selector         
Selector selector=Selector.open();         
//创建一个通道对象Channel,监听9001端口         
ServerSocketChannel channel = ServerSocketChannel.open().bind(new InetSocketAddress(9001));         
//设置channel为非阻塞         
channel.configureBlocking(false);         
//         
/**          
* 1.SelectionKey.OP_CONNECT:连接事件          
* 2.SelectionKey.OP_ACCEPT:接收事件          
* 3.SelectionKey.OP_READ:读事件          
* 4.SelectionKey.OP_WRITE:写事件          
*          
* 将channel绑定到selector上并注册OP_ACCEPT事件          
*/         
channel.register(selector,SelectionKey.OP_ACCEPT);         
while (true){             
//只有当OP_ACCEPT事件到达时,selector.select()会返回(一个key),如果该事件没到达会一直阻塞             selector.select();             
//当有事件到达了,select()不在阻塞,然后selector.selectedKeys()会取到已经到达事件的SelectionKey集合             
Set keys = selector.selectedKeys();             
Iterator iterator = keys.iterator();            
while (iterator.hasNext()){                 
SelectionKey key = (SelectionKey) iterator.next();                 
//删除这个SelectionKey,防止下次select方法返回已处理过的通道                 
iterator.remove();                 
//根据SelectionKey状态判断                 
if (key.isConnectable()){                     
//连接成功                 
} else if (key.isAcceptable()){                     
/**                      
* 接受客户端请求                      
*                      
* 因为我们只注册了OP_ACCEPT事件,所以有客户端链接上,只会走到这                      
* 我们要做的就是去读取客户端的数据,所以我们需要根据SelectionKey获取到serverChannel                     
 * 根据serverChannel获取到客户端Channel,然后为其再注册一个OP_READ事件                      
*/                     
// 1,获取到ServerSocketChannel                     
ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();                     
// 2,因为已经确定有事件到达,所以accept()方法不会阻塞                     
SocketChannel clientChannel = serverChannel.accept();                     
// 3,设置channel为非阻塞                     
clientChannel.configureBlocking(false);                     
// 4,注册OP_READ事件                     
clientChannel.register(key.selector(),SelectionKey.OP_READ);                 
} else if (key.isReadable()){                     
// 通道可以读数据                     
/**                      
* 因为客户端连上服务器之后,注册了一个OP_READ事件发送了一些数据                      
* 所以首先还是需要先获取到clientChannel                      
* 然后通过Buffer读取clientChannel的数据                      
*/                     
SocketChannel clientChannel = (SocketChannel) key.channel();                     
ByteBuffer byteBuffer = ByteBuffer.allocate(BUF_SIZE);                     
long bytesRead = clientChannel.read(byteBuffer);                     
while (bytesRead>0){                         
byteBuffer.flip();                         
System.out.println("client data :"+new String(byteBuffer.array()));                         
byteBuffer.clear();                         
bytesRead = clientChannel.read(byteBuffer);                     
}                     
/**                      
* 我们服务端收到信息之后,我们再给客户端发送一个数据                      
*/                     
byteBuffer.clear();                     
byteBuffer.put("客户端你好,我是服务端,你看这NIO多难".getBytes("UTF-8"));                     
byteBuffer.flip();                     
clientChannel.write(byteBuffer);                 
} else if (key.isWritable() && key.isValid()){                     
//通道可以写数据                 
}             
}         
} 

客户端代码

客户端连接上服务端后,先给服务端发送一个消息,并接受服务端发送的消息

Selector selector = Selector.open(); 
SocketChannel clientChannel = SocketChannel.open(); 
//将channel设置为非阻塞 
clientChannel.configureBlocking(false); 
//连接服务器 
clientChannel.connect(new InetSocketAddress(9001)); 
//注册OP_CONNECT事件 
clientChannel.register(selector, SelectionKey.OP_CONNECT); 
while (true){     
//如果事件没到达就一直阻塞着     
selector.select();     
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();     
while (iterator.hasNext()){         
SelectionKey key = iterator.next();         
iterator.remove();         
if (key.isConnectable()){             
/**              
* 连接服务器端成功              
*              
* 首先获取到clientChannel,然后通过Buffer写入数据,然后为clientChannel注册OP_READ时间              
*/             
clientChannel = (SocketChannel) key.channel();             
if (clientChannel.isConnectionPending()){                 
clientChannel.finishConnect();             
}             
clientChannel.configureBlocking(false);             
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);             
byteBuffer.clear();             
byteBuffer.put("服务端你好,我是客户端,你看这NIO难吗".getBytes("UTF-8"));             
byteBuffer.flip();             
clientChannel.write(byteBuffer);             
clientChannel.register(key.selector(),SelectionKey.OP_READ);         
} else if (key.isReadable()){             
//通道可以读数据             
clientChannel = (SocketChannel) key.channel();             
ByteBuffer byteBuffer = ByteBuffer.allocate(BUF_SIZE);             
long bytesRead = clientChannel.read(byteBuffer);             
while (bytesRead>0){                 
byteBuffer.flip();                 
System.out.println("server data :"+new String(byteBuffer.array()));                 
byteBuffer.clear();                 
bytesRead = clientChannel.read(byteBuffer);             
}         
} else if (key.isWritable() && key.isValid()){             
//通道可以写数据         
}     
}
} 

使用原生NIO类库十分复杂,NIO的类库和Api繁杂,使用麻烦,需要对网络编程十分熟悉,才能编写出高质量的NIO程序,所以并不建议直接使用原生NIO进行网络编程,而是使用一些成熟的框架,比如Netty

三、AIO

JDK1.7升级了Nio类库,成为Nio2.0,最主要的是提供了异步文件的IO操作,以及事件驱动IO,AIO的异步套接字通道是真正的异步非阻塞IO

1、异步IO模型

 

 

在Linux系统中,应用进程发起read操作,立刻可以去做其他的事,内核会将数据准备好并且复制到用空间后告诉应用进程,数据已经复制完成read操作

2、aio模型 网络编程

异步操作

aio不需要通过多路复用器对注册的通道进行轮询操作就可以实现异步读写,从而简化了NIO的编程模型

aio通过异步通道实现异步操作,异步通道提供了两种方式获取操作结果:

(1)通过Future类来获取异步操作的结果,不过要注意的是future.get()是阻塞方法,会阻塞线程

(2)通过回调的方式进行异步,通过传入一个CompletionHandler的实现类进行回调,CompletionHandler定义了两个方法,completed和failed两方法分别对应成功和失败

Aio中的Channel都支持以上两种方式

AIO提供了对应的异步套接字通道实现网络编程,服务端:AsynchronousServerSocketChannel和客户端AsynchronousSocketChannel

服务端

服务端向客户端发送消息,并接受客户端发送的消息

AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress("127.0.0.1", 9001)); 
//异步接受请求 
server.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {     
//成功时     
@Override     public void completed(AsynchronousSocketChannel result, Void attachment) {         
try {             
ByteBuffer buffer = ByteBuffer.allocate(1024);             
buffer.put("我是服务端,客户端你好".getBytes());             
buffer.flip();             
result.write(buffer, null, new CompletionHandler<Integer, Void>(){                 
@Override                 public void completed(Integer result, Void attachment) {                     System.out.println("服务端发送消息成功");                 
}                 
@Override                 public void failed(Throwable exc, Void attachment) {                     System.out.println("发送失败");                 
}             
});             
ByteBuffer readBuffer = ByteBuffer.allocate(1024);             
result.read(readBuffer, null, new CompletionHandler<Integer, Void>() {                 
//成功时调用                 
@Override                 public void completed(Integer result, Void attachment) {                     System.out.println(new String(readBuffer.array()));                 
}                 
//失败时调用                 
@Override                 public void failed(Throwable exc, Void attachment) {                     System.out.println("读取失败");                 
}             
});         
} catch (Exception e) {             
e.printStackTrace();         
}     
}     
//失败时     
@Override     public void failed(Throwable exc, Void attachment) {         
exc.printStackTrace();     
} 
}); 
//防止线程执行完 
TimeUnit.SECONDS.sleep(1000L); 

客户端

客户端向服务端发送消息,并接受服务端发送的消息

AsynchronousSocketChannel client = AsynchronousSocketChannel.open(); 
Future<Void> future = client.connect(new InetSocketAddress("127.0.0.1", 9001)); 
//阻塞,获取连接 
future.get(); 
ByteBuffer buffer = ByteBuffer.allocate(1024); 
//读数据 
client.read(buffer, null, new CompletionHandler<Integer, Void>() {     
//成功时调用     
@Override     public void completed(Integer result, Void attachment) {         
System.out.println(new String(buffer.array()));     
}     
//失败时调用     
@Override     public void failed(Throwable exc, Void attachment) {         
System.out.println("客户端接收消息失败");     
} 
}); 
ByteBuffer writeBuffer = ByteBuffer.allocate(1024); 
writeBuffer.put("我是客户端,服务端你好".getBytes()); 
writeBuffer.flip(); 
//阻塞方法 
Future<Integer> write = client.write(writeBuffer); 
Integer r = write.get(); 
if(r>0){     
System.out.println("客户端消息发送成功"); 
} 
//休眠线程 
TimeUnit.SECONDS.sleep(1000L);

总结

各IO模型对比:

 

 

伪异步IO是指使用线程池处理请求的Bio模型

 

Linux上的TCP监听fd的accept/select/poll/epoll惊群问题 同一个TCP端口(地址相同)是不能被多次绑定、监听的。因此,多线程程序无法并发地accept连接。而多进程可以并发accept新连接,办法就是先创建、绑定好端口,完成listen调用,然后fork出子进程,子进程继承父进程的文件描述符,然后子进程、父进程都可以accept。        很多石器时代的C/C++程序员认为,如果有一个新连接建立完成,此时阻塞在accept系统调用上的进程都会被唤... 阅读详情

相关推荐

高效爬取懂车帝车型数据:从静态解析到动态反爬实战

本文详细解析了如何高效爬取懂车帝车型数据,从静态HTML解析到动态接口反爬的完整实战路径。文章重点介绍了使用浏览器开发者工具定位数据、应对CSS混淆与参数加密等反爬策略,并提供了整合静态与动态抓取逻辑的Python代码示例,帮助开发者稳健地获取结构化车型信息。

wind6的博客 938

关于select、poll和epoll

常规的TCP-socket通信的流程一般如下;1.服务端创建监听套接字(socket),初始化网卡(SOCKADDR_IN),监听套接字绑定网卡(bind),调用(listen)函数开始监听;2.客户端创建套接字1(socket),根据服务端的IP地址还有端口初始化网卡(SOCKADDR_IN),调用(connect)函数与服务端连接。3.服务端accept函数,取出连接,获得一个套接字2,之后双方的通信在套接字1和套接字2之间进行。有个问题?

qq_42059175的博客 182

opencv读取海康威视摄像头相关配置

1、开发环境 海康威视的网络摄像头使用: 开发工具:vs2015 C++ 海康SDK 2、相关操作 下载海康威视SDK:网址:http://www.hikvision.com/cn/download_61.html • 1:对照自己的开发平台可以下载设备网络SDK_Win32设备网络SDK_Win64,解压到本地文件下: • 2:VS配置 、Opencv配置。参考址 http://blog.youkuaiyun.com/poem_qianmo/article/details/19809337 (建议自己创

HMJ115的博客 988

socket可能造成阻塞的函数有:connect()、accept()、读写函数、select()、poll()、gethostbyname()等

阻塞模式 是socket的缺省方式,也是最常用的方式,即函数阻塞直到调用完毕。可参见前面的例子。 可能造成阻塞的函数有:connect()、accept()、读写函数、select()、poll()、gethostbyname()等。 http://staff.ustc.edu.cn/~mengning/np/linux_socket/new_page_15.htm ...

studyvcmfc的专栏 899

FPS游戏自动枪械识别+压枪(以PUBG为例)

使用Python3.9作为开发环境,实现一个通用的FPS游戏自动检测枪械配件+压枪宏的软件开发思路

weixin_37827742的博客 3万+

VisionMaster图像源模块的5个隐藏功能:从自动切换到二次开发接口

本文深入解析了VisionMaster图像源模块的5个隐藏功能,从基础的自动切换与字符触发过滤,到高级的脚本扩展与基于COM组件的二次开发接口。这些功能能显著提升工业视觉项目的自动化水平、灵活性与系统集成能力,帮助开发者实现更高效的离线测试流水线和外部精确控制。

rgv23456789的博客 652

一文看懂java io系统

原文:chenmingyu.top/nio/ 学习java IO系统,重点是学会IO模型,了解了各种IO模型之后就可以更好的理解java IO Java IO 是一套Java用来读写数据(输入和输出)的API。大部分程序都要处理一些输入,并由输入产生一些输出。Java为此提供了java.io包 java中io系统可以分为Bio,Nio,Aio三种io模型 关于Bio,我们需要知道什么是同步阻...

weixin_30733003的博客 381

硬件电路RS485通信EMC 设计

RS485通讯硬件设计与STM32实现要点 本文详细介绍了RS485通讯系统的硬件设计和STM32实现方案。硬件设计重点包括:采用总线型拓扑结构、120Ω终端电阻匹配、屏蔽双绞线布线、TVS管和自恢复保险丝保护等核心要素。EMC设计强调共模电感抑制干扰、屏蔽层单端接地、光电隔离等技术。软件实现方面,提供了基于STM32F103的完整程序框架,包括UART初始化、收发控制逻辑和中断处理机制,特别强调了收发切换时机、波特率精度等关键注意事项。文中还给出了工业传感器节点的实际应用案例,展示了一个完整的EMC防护电

qq_37999850的博客 1384

你真的懂IO流吗

目录什么是IO流IO流的分类输入输出流字节字符流 什么是IO流 在我们的程序运行当中,不可避免的要与数据打交道,我们应该如何获取这些数据?这就用到IO流了 IO:Input/Output,输入输出流 作用:通过IO流可以完成硬盘文件的读写操作 IO流的分类 输入输出流 输入(Input):也就是从外部文件中获取数据(即读取外部数据) eg:在腾讯视频上看一部电影 输出(Output):也就是把内存中的文件保存到硬盘上(即把数据写到电脑中) eg:保存world文档到C盘 字节字符流 字节流:一看

m0_47630931的博客 5089

IPv6之001-IPv6是什么

技术本质:IPv6(Internet Protocol version 6)是互联网工程任务组(IETF)设计的网络层核心协议,用于替代IPv4核心使命:解决IPv4地址枯竭问题,重构互联网基础架构,支撑万物互联时代革命性特征fill:#333;color:#333;color:#333;fill:none;IPv6128位地址空间无状态自动配置原生IPsec加密协议头部精简。

老韩的Linux云计算架构师进阶之路 1396

多堆燃料电池-蓄电池混合动力系统能量管理策略研究

摘要 本研究针对多堆燃料电池-蓄电池混合动力系统,提出三种能量管理策略并进行对比分析。系统采用双燃料电池堆与锂离子蓄电池并联结构,通过建立精确的数学模型描述各组件动态特性。研究设计了规则型策略、模糊逻辑控制策略和等效氢耗最小化策略,重点解决了多堆系统功率分配与蓄电池SOC平衡问题。基于MATLAB/Simulink平台的仿真结果表明,模糊逻辑控制策略在氢耗经济性方面表现最优,相比传统规则型策略可降低5%-10%的氢耗,同时有效抑制燃料电池功率波动。本文提出的策略框架为重型商用车的燃料电池混合动力系统提供了可

huanghm88的专栏 177

Java 中的阻塞 IO 和非阻塞 IO

IO(输入输出)操作是一个基础而又关键的部分。在 Java 中,处理 IO 通常涉及到阻塞 IO 和非阻塞 IO 两种模式。本文将介绍这两种模式的概念、特点以及在 Java 编程中的应用场景与区别。

✨ 欢迎来到【Seal ^_^ 的优快云博客】!✨ 5871

银行统一监管报送系统

依据《银行业金融机构数据治理指引》,银行业金融机构应当建立适应监管数据报送工作需要的信息系统,实现流程控制的程序化,提高监管数据加工的自动化程度。银行业金融机构应当将监管数据纳入数据治理,建立工作机制和流程,确保监管数据报送工作有效组织开展,监管数据质量持续提升。银行通常要对接报送EAST5.0、1104、CRSS等近40个监管应用,涉及近1000张报表。表13-01是主要的监管报送应用、报送依据、报送规范、监管机构名称。

银行信息系统应用架构详解 4350

Linux问题排查 ——IO篇

在解决IO问题的时候,主要搞清楚三个问题: 问题是否真的出现在IO 哪个进程在大量使用IO 这个进程访问了哪些文件 通常我们在弄清楚第二个问题的时候,就已经知道IO是什么问题引起的了。 如果还不能,就继续弄清楚第三个问题,当我们知道进程访问了哪些文件后,就能反推程序中哪些地方使用了。 问题是否真的出现在IO 这个问题比较好确定,常见的iostat就能打印出IO相关的信息: 这个命令分三行,首...

解码者 2491

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Android IO流程你真的清楚了吗|硬核科普

前言 最近在看《Linux内核设计与实现》的时候,就想着要不把知识串联一下吧。 聊什么呢?今天先来聊聊 Android IO 的调用链路。 说起 IO,这可真是一个很复杂的过程,里面涉及了很多内容,先是软件,最后到硬件,用一张图来表示一下吧: 本文打算简单得和大伙讨论一下 IO 的流程。 一、应用层 作为应用开发者,我们通常是 IO 发起点,比如用户说这本小说很好看,我要下载到本地,或者,这张图拍的不错,分享给你看一下。 虽然这些都是常见的 IO 场景,但是你知道有哪些 IO 吗? 1. IO的分类 通常

qq_35063091的博客 4113

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

java io系统_JAVA IO之系统IO

JAVA IO之系统IO基本概念VFS(Virtual File System):VFS(virtual File System)的作用就是采用标准的Unix系统调用读写位于不同物理介质上的不同文件系统,即为各类文件系统提供了一个统一的操作界面和应用编程接口。VFS是一个可以让open()、read()、write()等系统调用不用关心底层的存储介质和文件系统类型就可以工作的粘合层。FD(File...

weixin_32831131的博客 202

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

详解java以及操作系统的IO模型

什么是IO? IO就是文件的输入和输出。计算机中处理数据都是要在内存中进行的,而文件又是存储在磁盘上的,所以无论从磁盘读取数据到内存,还是从内存写入数据到磁盘都要进行IO 操作,那么java中的IO模型都有哪些呢?和操作系统中的IO模型又有什么关系呢?

qq_40884264的博客 1104

一段话讲懂java中的3种IO、网络编程

​ 服务器的读数据的方法不会一直在进程对应的内存中等待,而是过一段时间询问进程对应的内存是否有新的数据复制进来,如果没有等待操作系统内核把数据复制到进程区域的内存,它需要我们主动每隔一端时间进行对内存数据准备区进行询问,直到有一次我们问它,刚好它有数据了,我们的方法就可以返回具体的数据,没有也会方法也会立马返回,不会阻塞。​ 既然IO可以进行数据的输入输出操作,内存既可以是数据源也可以是数据接收方,那么这个时候如果是两台计算机,那么我们就可以实现两个计算机的内存的数据相互收发。

qq_64039411的博客 1333

IO编程,真的很简单

文章目录1、io的基本概念2、io流的分类3、Java中常用的IO类3.1四个抽象类3.2输入操作3.3输出操作3.4缓存流的使用 1、io的基本概念 I/O操作指的是进行输入、输出的操作,输入/输出操作都是基于数据流的,这些数据流表示了字节或字符流动的序列。Java中的I/O流提供了读写数据的标准方法,任何表示数据源的对象都会以数据流的方式读写它的数据方法。 java把用于操作输入/输出的类放在...

Simon郎的博客 1716

Java IO系统及IO模型详细笔记

学习Java IO系统,重点是学会IO模型,了解了各种IO模型之后就可以更好的理解Java IO。 java中IO系统可以分为Bio,Nio,Aio三种io模型 关于Bio,我们需要知道什么是同步阻塞IO模型,Bio操作的对象:流,以及如何使用Bio进行网络编程,使用Bio进行网络编程的问题 关于Nio,我们需要知道什么是同步非阻塞IO模型,什么是多路复用Io模型,以及Nio中的Buffer,Channel,

xgb2018的博客 548

Java IO系统

Java IO系统 (1)先理解字节和字符的区别 计算机中存储信息的最小单位为bit(位),二进制的一个'0'或'1'叫1位 计算机中存储信息的基本单位为byte(字节),8个二进制位组成1个字节,一般而言:一个英文字母占一个字节,一个汉字占2个字节 字符是一种符号,比如:1,2,*,=,等,在不同的编码标准下字符所占的字节长度不同, 比如:在ASCII码中,一个...

凑和吧的博客 190

java io

 Java IO       本篇主要讲述IO相关的内容,主要包括:与IO相关的简单的历史背景知识;Java IO的简单分类;与IO设计相关的两个模式;同时列举几个简单的例子;分析其中几个实现的源代码;最后给大家一些简单扩展的例子。治学先治史,下面我们先从简单的历史开始吧! 一、      历史背景       “对语言设计人员来说,创建好的输入/输出系统是一项特别困难的任务。

因为了解所以无知 3万+

从操作系统底层彻底理解Java IO演进之路

本文从操作系统调用的角度,分析了Java中四种I/O模型(BIO、NIO、IO多路复用、AIO)的优缺点及适用场景。BIO是同步阻塞I/O,适用于连接数较少的场景,但并发性能较差。NIO是同步非阻塞I/O,通过轮询I/O事件提高并发性能,适用于高并发服务器应用。IO多路复用通过内核通知应用程序哪些连接有数据,减少了线程数量,适用于高并发场景。AIO是异步I/O,由操作系统完成I/O操作后通知应用程序,适用于高并发网络应用如聊天室。每种模型都有其特定的使用场景和性能特点,开发者应根据实际需求选择合适的I/O模

m0_74447524的博客 1196

【Linux】Java文件IO之普通IO与Buffer IO

在Java中,输入输出(IO)操作是编程中一项重要的任务。无论是从外部文件中读取数据,还是向文件写入数据,或者是与用户进行交互,都需要用到IO操作。

morris 4万+

大白话聊懂什么是IO的零拷贝

本文深入浅出地讲解了IO零拷贝技术。零拷贝是操作系统层面的高效IO技术,通过减少CPU数据拷贝次数(甚至为零)来提升性能。文章首先解释了DMA、内核空间/用户空间等关键概念,对比了传统IO流程(4次数据拷贝+4次状态切换)与零拷贝的两种实现方式:mmap(3次拷贝+4次切换)和sendFile(2次DMA拷贝+2次切换)。重点介绍了Linux2.4引入SG-DMA技术后实现的真正零拷贝(0次CPU拷贝)。最后指出Java通过FileChannel支持零拷贝,但需要注意2G文件大小限制。文章用通俗语言解析了这

曹举的个人博客 1029

JAVA IO系统简介

最近学习IO系统,写两篇文章,第一篇介绍IO系统基础知识,即什么为io系统,流的概念,流的类型即输入流输出流,字节流或字符流,第二篇介绍常用的IO流的通常用法,即流的应用。 Java io系统简介: I/O是Input/Output的缩写, I/O技术是非常实用的技术,用于 处理设备之间的数据传输。如读/写文件,网络通讯等。通常情况下。程序读入数据,对于数据修改之后写出到指定位置,这整个过程即为JAVA io系统的工作,对于数据的输入/输出操作以“流(stream)” 的方式进行较为通俗的理解:将Ja

尚拙的博客 401
上一篇: 线上数据库诡异死锁?如何排查问题?
下一篇: 面试官一般会怎么考察Java工程师?
加班不秃顶
博客等级 码龄7年 1822粉丝 599原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值