[Java IO]02_字节流

概要

字节流有两个核心抽象类:InputStream 和 OutputStream。所有的字节流类都继承自这两个抽象类。

InputStream 负责输入,OutputStream 负责输出。

字节流主要操作byte类型数据。

以下为 JDK8 版本中字节流的族谱图:

具体详情可查看Java API文档。

由上图可以看出,InputStream 和 OutputStream对于数据源的操作往往是成对出现的。

InputStream

InputStream的作用是用来表示哪些从不同数据源产生输入的类。

InputStream类型表

功能

构造器

ByteArrayInputStream

允许将内存的缓冲区当做InputStream使用

缓冲区,字节将从中取出

StringBufferInputStream

将String转换成InputStream

字符串。底层实现实际使用StringBuffer

FileInputStream

从文件中读取信息

字符串,表示文件名、文件或FileDescriptor对象

PipedInputStream

产生用于写入相关PipedOutputStream的数据。实现“管道化”概念

PipedOutputStream

SequenceInputStream

将多个InputStream对象合并为一个InputStream

两个InputStream对象或一个容纳InputStream对象的容器Enumeration

FilterInputStream

抽象类,作为“装饰器”的接口。其中“装饰器”为其他InputStream类提供有用功能

OutputStream

OutputStream决定了数据的输出形式。

OutputStream类型表

功能

构造器

ByteArrayOutputStream

允许将内存的缓冲区当做InputStream使用

缓冲区初始化尺寸(可选的)

FileOutputStream

从文件中读取信息

字符串,表示文件名、文件或FileDescriptor对象

PipedOutputStream

产生用于写入相关PipedOutputStream的数据。实现“管道化”概念

PipedInputStream

FilterOutputStream

抽象类,作为“装饰器”的接口。其中“装饰器”为其他OutputStream类提供有用功能

文件字节流

文件字节流有两个类:FileOutputStream 和 FileInputStream。

它们提供了方法将字节写入到文件和将数据以字节形式从文件中读取出来。

一般情形下,文件字节流操作遵循以下几个步骤:

(1)使用File类绑定一个文件。

(2)把File对象绑定到流对象上。

(3)进行读、写操作。

(4)关闭输入、输出。

FileOutputStream

向文件写入数据

import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 
 public class FileOutputStreamDemo {
 public static void write1(OutputStream out, byte[] b) throws IOException {
         out.write(b); // 将内容输出,保存文件
     }
 
 public static void write2(OutputStream out, byte[] b) throws IOException {
 for (int i = 0; i < b.length; i++) { // 采用循环方式写入
             out.write(b[i]); // 每次只写入一个内容
         }
     }
 
 public static void main(String args[]) throws Exception {
 // 第1步、使用File类找到一个文件
         File f = new File("d:" + File.separator + "test.txt"); // 声明File对象
 
 // 第2步、通过子类实例化父类对象
         OutputStream out = new FileOutputStream(f); // 通过对象多态性,进行实例化
 // 实例化时,默认为覆盖原文件内容方式;如果添加true参数,则变为对原文件追加内容的方式。
 // OutputStream out = new FileOutputStream(f, true);
 
 // 第3步、进行写操作
         String str = "Hello World\r\n"; // 准备一个字符串
  byte b[] = str.getBytes(); // 只能输出byte数组,所以将字符串变为byte数组
         write1(out, b);
 // write2(out, b);
 
 // 第4步、关闭输出流
         out.close();
     }
 };

FileInputStream

从文件中读取数据

import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 
 public class FileInputStreamDemo {
 public static void read1(InputStream input, byte[] b) throws IOException {
 int len = input.read(b); // 读取内容
         System.out.println("读入数据的长度:" + len);
     }
 
 public static void read2(InputStream input, byte[] b) throws IOException {
 for (int i = 0; i < b.length; i++) {
             b[i] = (byte) input.read(); // 读取内容
         }
     }
 
 public static void read3(InputStream input, byte[] b) throws IOException {
 int len = 0;
 int temp = 0; // 接收每一个读取进来的数据
  while ((temp = input.read()) != -1) {
 // 表示还有内容,文件没有读完
             b[len] = (byte) temp;
             len++;
         }
     }
 
 public static void main(String args[]) throws Exception { // 异常抛出,不处理
 // 第1步、使用File类找到一个文件
         File f = new File("d:" + File.separator + "test.txt"); // 声明File对象
 
 // 第2步、通过子类实例化父类对象
         InputStream input = new FileInputStream(f); // 准备好一个输入的对象
 
 // 第3步、进行读操作
 // 有三种读取方式,体会其差异
  byte[] b = new byte[(int) f.length()];
         read1(input, b);
 // read2(input, b);
 // read3(input, b);
 
 // 第4步、关闭输入流
         input.close();
         System.out.println("内容为:\n" + new String(b)); // 把byte数组变为字符串输出
     }
 };

内存操作流

ByteArrayInputStream 和 ByteArrayOutputStream是用来完成内存的输入和输出功能。

内存操作流一般在生成一些临时信息时才使用。  如果临时信息保存在文件中,还需要在有效期过后删除文件,这样比较麻烦。

使用内存操作流完成一个转换为小写字母的程序

import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 
 public class ByteArrayDemo {
 public static void main(String args[]) {
         String str = "HELLOWORLD";
 
         ByteArrayInputStream bis = new ByteArrayInputStream(str.getBytes()); // 内存输入流
         ByteArrayOutputStream bos = new ByteArrayOutputStream(); // 内存输出流
 
 // 用ByteArrayInputStream读取字符串内容,
 // 全转为小写后,写入ByteArrayOutputStream
  int temp = 0;
 while((temp = bis.read()) != -1) {
 char c = (char) temp; // 读取的数字变为字符
             bos.write(Character.toLowerCase(c)); // 将字符变为小写
         }
 
 // 所有的数据就全部都在ByteArrayOutputStream中
         String newStr = bos.toString();    // 取出内容
  try {
             bis.close();
             bos.close();
         } catch(IOException e) {
             e.printStackTrace();
         }
         System.out.println(newStr);
     }
 };

管道流

管道流的主要作用是可以进行两个线程间的通信。

如果要进行管道通信,则必须把PipedOutputStream连接在PipedInputStream上。

为此,PipedOutputStream中提供了connect()方法。

import java.io.IOException;
 import java.io.PipedInputStream;
 import java.io.PipedOutputStream;
 
 class Send implements Runnable {
 private PipedOutputStream pos = null; // 管道输出流
 
 public Send() {
 this.pos = new PipedOutputStream(); // 实例化输出流
     }
 
 public void run() {
         String str = "Hello World!!!"; // 要输出的内容
  try {
 this.pos.write(str.getBytes());
         } catch (IOException e) {
             e.printStackTrace();
         }
 try {
 this.pos.close();
         } catch (IOException e) {
             e.printStackTrace();
         }
     }
 
 public PipedOutputStream getPos() { // 得到此线程的管道输出流
  return this.pos;
     }
 };
 
 class Receive implements Runnable {
 private PipedInputStream pis = null; // 管道输入流
 
 public Receive() {
 this.pis = new PipedInputStream(); // 实例化输入流
     }
 
 public void run() {
 byte b[] = new byte[1024]; // 接收内容
  int len = 0;
 try {
             len = this.pis.read(b); // 读取内容
         } catch (IOException e) {
             e.printStackTrace();
         }
 try {
 this.pis.close(); // 关闭
         } catch (IOException e) {
             e.printStackTrace();
         }
         System.out.println("接收的内容为:" + new String(b, 0, len));
     }
 
 public PipedInputStream getPis() {
 return this.pis;
     }
 };
 
 public class PipedDemo {
 public static void main(String args[]) {
         Send s = new Send();
         Receive r = new Receive();
 try {
             s.getPos().connect(r.getPis()); // 连接管道
         } catch (IOException e) {
             e.printStackTrace();
         }
 new Thread(s).start(); // 启动线程
  new Thread(r).start(); // 启动线程
     }
 };

数据操作流

数据操作流提供了格式化读入和输出数据的方法,分别为DataInputStream 和 DataOutputStream。

DataOutputStream

将格式化的订单数据写入到文件

import java.io.DataOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 
 public class DataOutputStreamDemo {
 public static void main(String args[]) throws IOException {
 // 第1步、使用File类找到一个文件
         File f = new File("d:" + File.separator + "order.txt");
 
 // 第2步、通过子类实例化父类对象
         DataOutputStream dos = new DataOutputStream(new FileOutputStream(f)); // 实例化数据输出流对象
 
 // 第3步、进行写操作
         String names[] = { "衬衣", "手套", "围巾" }; // 商品名称
  float prices[] = { 98.3f, 30.3f, 50.5f }; // 商品价格
  int nums[] = { 3, 2, 1 }; // 商品数量
 // 循环输出
  for (int i = 0; i < names.length; i++) {
             dos.writeChars(names[i]);
             dos.writeChar('\t');
             dos.writeFloat(prices[i]);
             dos.writeChar('\t');
             dos.writeInt(nums[i]);
             dos.writeChar('\n');
         }
 
 // 第4步、关闭输出流
         dos.close();
     }
 };

DataInputStream

将订单文件中的格式化数据读取出来

import java.io.DataInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 
 
 public class DataInputStreamDemo {
 public static void main(String args[]) throws IOException { // 所有异常抛出
 // 第1步、使用File类找到一个文件
         File f = new File("d:" + File.separator + "order.txt");
 
 // 第2步、通过子类实例化父类对象
         DataInputStream dis = new DataInputStream(new FileInputStream(f)); // 实例化数据输入流对象
 
 // 第3步、进行读操作
         String name = null; // 接收名称
  float price = 0.0f; // 接收价格
  int num = 0; // 接收数量
  char temp[] = null; // 接收商品名称
  int len = 0; // 保存读取数据的个数
  char c = 0; // '\u0000'
  try {
 while (true) {
                 temp = new char[200]; // 开辟空间
                 len = 0;
 while ((c = dis.readChar()) != '\t') { // 接收内容
                     temp[len] = c;
                     len++; // 读取长度加1
                 }
                 name = new String(temp, 0, len); // 将字符数组变为String
                 price = dis.readFloat(); // 读取价格
                 dis.readChar(); // 读取\t
                 num = dis.readInt(); // 读取int
                 dis.readChar(); // 读取\n
                 System.out.printf("名称:%s;价格:%5.2f;数量:%d\n", name, price, num);
             }
         } catch (Exception e) {
         }
 
 // 第4步、关闭输入流
         dis.close();
     }
 };

合并流

合并流的主要功能是将多个InputStream合并为一个InputStream流。

合并流的功能由SequenceInputStream完成。

需要稍微留意的是,由前面的字节流族谱图,可以得知并没有对应的OutputStream。

将两个文件内容合并为一个文件

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.SequenceInputStream;

public class SequenceDemo {
 public static void main(String args[]) throws IOException {
 // 第1步,绑定要操作的文件
        InputStream is1 = new FileInputStream("d:" + File.separator + "a.txt"); // 输入流1
        InputStream is2 = new FileInputStream("d:" + File.separator + "b.txt"); // 输入流2    
        OutputStream os = new FileOutputStream("d:" + File.separator + "ab.txt"); // 输出流
 
 // 第2步,绑定要合并的InputStream对象到SequenceInputStream
        SequenceInputStream sis = new SequenceInputStream(is1, is2); // 实例化合并流

 // 读取两个InputStream流的数据,然后合并输出到OutputStream
 int temp = 0; // 接收内容
 while ((temp = sis.read()) != -1) { // 循环输出
            os.write(temp); // 保存内容
        }
 
 // 第4步,关闭相关流
        sis.close();
        os.close();    
        is1.close();
        is2.close();
    }
};

参考资料

《Java编程思想》

《Java开发实战经典》

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏苍云横渡学习笔记

【JavaSE(十三)】JavaIO流(中)

Java中使用 IO流 来读取和写入,读写设备上的数据、硬盘文件、内存、键盘等等,一个流被定义为一个数据序列。

773
来自专栏Java 技术分享

Java 基础 -- 泛型、集合、IO、反射

3329
来自专栏互联网杂技

分享史上Java最牛逼,最简短的代码

确实是12306的最核心代码呀 <script> alert("当前访问用户过多,请稍后重试!"); </script> 确实牛 public clas...

44910
来自专栏闻道于事

Java之IO流概述和File基本操作

IO流图解 ? IO(in / out)流的分类 流向:     输入流  读取数据     输出流  写出数据 数据类型:     字节流     一个字...

2769
来自专栏用户3030674的专栏

java写文件读写操作(IO流,字节流)

/** * IO流的数据写入和读取 * 在本质上是用的FileReader("c:text.txt")或FileWriter("c:text2.txt")...

821
来自专栏desperate633

Java中的异常处理2堆栈追踪finally自动尝试关闭资源语法

想要知道异常的根源,以及多重方法调用下异常的传播,可以利用异常对象自动收集的堆栈的追踪来取得相关信息,例如,调用调用异常对象的printStacktrace()...

532
来自专栏日常分享

在Struts2 Action中快速简便的访问Request、Session等变量

全部方法(共四种)可以参考:http://blog.csdn.net/itmyhome1990/article/details/7019476

862
来自专栏10km的专栏

fastjson:实现对java.nio.ByteBuffer数据类型的支持

一般情况下,我们都用byte[]作为保存二进制数据的数据类型,较少用ByteBuffer来表示字节数组。然而最近的工作中需要二进制数据(字节数组)即支持fast...

2148
来自专栏老马说编程

(58) 文本文件和字符流 / 计算机程序的思维逻辑

上节我们介绍了如何以字节流的方式处理文件,我们提到,对于文本文件,字节流没有编码的概念,不能按行处理,使用不太方便,更适合的是使用字符流,本节就来介绍字符流。 ...

1945
来自专栏Android知识点总结

Java总结IO篇之其他IO流对象

582

扫码关注云+社区