JAVA BIO 回顾

应用程序难免会有输入和输出,输入输出的对象包括内存、文件、网络等,Java.io包就是用于进行这个工作的,但是这个包也并没有处理所有的输入输出类型,比如GUI或网页上的输出。

1.关于输入和输出流
我们通常将OutputStream称为输出流,表示我们可以向其中写入数据;把InputStream称为输入流,可以从其中读取数据;输出流需要和一个可以写入数据的目标媒介相关联,输入流需要和一个能够读取数据的数据源相关联。常见的有:文件、管道、内存、网络连接、System.in、System.out、System.err等。上面提到了流的概念,从概念上来说,流可以认为是一个连续的数据,你既可以从流中读取数据也可以向其中写入数据。在Java IO根据读写单位的不同可以分为字节流、字符流。也就是说我们总是通过InputStream和Reader流从数据源来读取数据,通过OutputStream和Writer来向目标媒介写入数据。最后一个问题就是Java IO为什么会包含那么多不同的类,这是因为Java 为不同的媒介(数据源)分别提供了不同的类,包括文件访问、网络访问、内存缓存访问、线程内部通信(管道)、缓冲、过滤、解析、读写文本 (Readers / Writers)、读写基本类型数据 (long, int etc.)、读写对象

2.文件读写
读文件:二进制文件可以使用FileInputStream来读取,可以一次读取一个字节(此时返回这个字符的ascii码)或将读取的内容装到传入的一个字符数组中去。文本文件文件可以使用FileReader读取,可以一次读取一个字符(返回的还是编码对应的数字)或将读取的内容写入到传入的字符数组中去。
写文件:如果要写入的是二进制数据,可以使用FileOutputStream,可以一次写入一个字节或写入一个字节数组;如果写入的是文本数据,则使用FileWriter,可以一次写入一个字符或写入一个字符数组。
数据会按照写入的顺序存储在文件中。
随机存储:RandomAccessFile可以实现对文件的随机存储,这里的随机指的是可以从指定的位置进行读写操作,而并不是说读写的位置是随机的。通过这个类,我们可以覆盖文件的一部分、读取文件中间的一部分、在文件的末尾追加一些数据。
文件和目录信息的获取:可以通过File类来获取文件或目录的一些信息,比如文件的类型、大小,目录下的文件列表。这里需要注意File对象并不实际代表一个文件或目录,它只代表一个包含相关信息的逻辑对象,所以我们不能通过File对象来对文件进行读写操作。

3.管道
Java IO中的管道为运行在同一个JVM中的两个线程提供了通信能力,所以管道也可以作为数据源和目标媒介进行操作。unix/Linux中的管道可以为运行与不同地址空间的进程进行通信,而Java中只能用于同进程下的线程通信。管道一般只能传递字节/字符数据,如果需要在线程间传递完整对象的话,可以选择其它通信方式。具体的来说 ,可以通过PipeInputStream和PipeOutputSteam、PipeReader和PipeWriter来创建管道。一个PipedInputStream流应该和一个PipedOutputStream流相关联。一个线程通过PipedOutputStream写入的数据可以被另一个线程通过相关联的PipedInputStream读取出来;这种关联关系可以在创建的时候指定,也可以通过他们的connect方法进行管理,PipedInputStream和PipedOupputStream都有一个connect方法。注意,使用两个相关联的管道流时,务必将他们分配给不同的线程。因为read()和write()方法调用时会阻塞,则意味着如果在一个线程中同时进行读写,可能会造成线程死锁。

4.网络
对网络进行数据操作和文件没有什么不一样,当使用Java API建立了网络连接以后,再获取其InputStream和OutPutStream就可以进行数据的读写了。本质上操作的还是InputStream和OutputStream。

关于各个具体类之间的具体作用可以参考之前的博客:http://blog.youkuaiyun.com/acm_lkl/article/details/46775867

<think>好的,我现在需要回答用户关于Java BIO流的使用方法和示例的问题。首先,我得回顾一下用户提供的引用内容,看看里面有哪些相关的信息可以利用。用户提供了五个引用,其中引用[2]、[3]、[5]提到了BIO的相关内容。 根据引用[5],BIO是同步阻塞IO模型,适用于连接数少且稳定的场景。这意味着每个连接需要一个独立的线程处理,可能导致资源耗尽。引用[2]提到了BIO的工作机制和一些实例,比如传统编程、多发多收消息、多客户端处理、伪异步IO和文件上传。引用[3]则详细说明了BIO的单线程和多线程模式,以及优缺点。 用户需要的是使用方法和示例,特别是代码示例。所以,我应该根据这些引用中的信息,整理出BIO的基本使用步骤,并给出相应的代码例子。比如,传统BIO的服务端和客户端代码,多线程模式,以及文件上传的例子。 需要注意的是,用户可能不太清楚BIO的工作流程,所以需要分步骤解释,比如服务端创建ServerSocket,客户端连接,读写数据时的阻塞情况等。同时,引用[2]中提到了伪异步IO,这可能是指用线程池来管理连接,避免为每个连接都创建新线程,这样可以优化资源使用,但本质上还是阻塞的,所以需要解释清楚。 另外,要确保代码示例符合Java标准,语法正确。比如,ServerSocket的accept方法会阻塞,直到有客户端连接;InputStream的read方法也会阻塞,直到有数据可读。在多线程模式中,每个连接交给一个线程处理,这样可以同时处理多个客户端,但线程数量过多会导致性能问题。 还需要指出BIO的优缺点,如引用[3]和[5]提到的,优势是编程简单,适合低并发;缺点是阻塞导致资源消耗大,高并发下性能差。同时,可以提到优化方法,如伪异步IO(线程池)来缓解资源问题,但根本的阻塞问题仍在。 最后,生成相关问题,可能涉及BIO与NIO的区别,优化方法,适用场景等,参考用户提供的示例问题结构。</think>### BIO流(Java Blocking IO)使用方法详解 BIO(Blocking I/O)是同步阻塞式IO模型,其核心特点是**每个连接需要独立的线程处理**,且I/O操作会阻塞线程直到完成[^5]。以下是具体使用方法和示例: --- ### 一、BIO基本工作流程 1. **服务端**:通过`ServerSocket`监听端口 2. **客户端**:通过`Socket`连接服务端 3. **数据传输**:通过`InputStream`/`OutputStream`读写数据 4. **线程阻塞**:`accept()`、`read()`等操作会阻塞当前线程 --- ### 二、基础代码示例 #### 1. 单线程服务端(仅处理单个客户端) ```java // 服务端代码 ServerSocket server = new ServerSocket(8080); Socket client = server.accept(); // 阻塞等待连接 BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); System.out.println("收到消息:" + in.readLine()); // 阻塞等待读取数据 // 客户端代码 Socket socket = new Socket("localhost", 8080); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); out.println("Hello BIO"); // 发送数据 ``` #### 2. 多线程服务端(处理多个客户端) ```java // 服务端改进代码 ExecutorService threadPool = Executors.newCachedThreadPool(); ServerSocket server = new ServerSocket(8080); while(true) { Socket client = server.accept(); // 主线程阻塞等待连接 threadPool.execute(() -> { // 子线程处理具体IO操作 BufferedReader in = new BufferedReader( new InputStreamReader(client.getInputStream()) ); System.out.println("客户端消息:" + in.readLine()); }); } ``` --- ### 三、关键特性说明 | 特性 | 说明 | |-------|-------| | **同步阻塞** | `accept()`和`read()`会阻塞线程直到完成操作[^5] | | **1:1线程模型** | 每个连接需要独立的处理线程[^3] | | **适用场景** | 连接数较少(<1000)且稳定的场景 | --- ### 四、优化方法:伪异步IO 通过线程池限制最大线程数,防止资源耗尽: ```java // 固定大小线程池 ExecutorService pool = Executors.newFixedThreadPool(10); ServerSocket server = new ServerSocket(8080); while(true) { Socket client = server.accept(); pool.execute(new ClientHandler(client)); // 提交任务到线程池 } // 客户端处理类 class ClientHandler implements Runnable { private Socket socket; public void run() { // 处理IO操作 } } ``` *注意:这仍属于阻塞模型,但能控制资源消耗[^2]* --- ### 五、典型应用场景 1. 文件上传/下载服务 2. 低并发的数据库连接 3. 传统桌面应用程序 --- ### 六、BIO的局限性 1. 线程数过多时会导致内存溢出(每个线程约占用1MB内存)[^3] 2. 高并发场景下性能急剧下降 3. 无法充分利用现代多核CPU资源 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值