JAVA中的IO流(二)字节流

前言

上回简单的介绍了IO流,并且顺便把File给介绍了,今天我们好好的介绍字节流。

介绍

字节流顾名思义就是操作字节的输入输出流。我们通过它可以读取硬盘中的字节数据放入内存中的字节数组,并将这些字节取出输出到硬盘上。
而字节流的顶层是两个抽象类:InputStreamOutputStream。这两个是无法实例化的,所以就有不同形式的子类了,接下来一一介绍。

FileInputStream、FileOutputStream

这是关于操作文件的字节流,在我们拿到文件的File对象后,可以以此拿到文件的字节流

//流的使用格式
InputStream in = new FileOutputStream(new File("c:/aaa.txt"));//建立文件字节输入流
OutputStream out = new FileOutputStream(new File("c:/bbb.txt"),"utf-8");//建立文件字节输出流,可以指定编码格式

//流的读写。。。。。。。。。。。。。。。。。

//关闭流
in.close();
out.close();

建立流后的读写(用完记得关闭流哦)

//很low的读写方式
	int read = in.read('a');//此处读写读到的是int型的ASCII码,并且是一次一次的读的,写的时候记得强转为char类型
	out.write('a');//无返回值,一次读写一个字符

//常用的读写方式
	in.read('b');//一次一次读实在太麻烦了,我们可以选择一次读入byte数组,这样可以很高提高效率
	int data = -1;
	byte[] bytes = new byte[1024 * 10];

	while ((data = in.read(bytes)) != -1) {// 此处读入返回值为实际读取内容的大小,-1意味着读取结束
	out.write(bytes);//将字节数组输出
	out.write(bytes, 0, data);
}

BufferedInputStream、BufferedOutputStream
  • 用于包装字节流的缓冲字节流,有人说用缓冲流包文件字节流可以提高读写效率,如果你的文件字节流选择的是一个一个读写的确可以提高效率,但是通常情况下我们都是读写字节数组,在这种情况下缓冲流不会提高效率的。
  • 在我们读写流的时候,是往后按顺序读写的。但是使用了缓冲流,只要流未关闭的情况下,我们可以跳转指定位置重新读写。
//流的使用格式
// 缓冲输入流
	InputStream is = new FileInputStream(new File("c:/aaa.txt"));
	is = new BufferedInputStream(is);
	boolean flag = is.markSupported();// 判断是否具有缓冲功能
	int data = is.read();
	is.mark(0);// 做标记,参数随意
	int data1 = is.read();
	int data2 = is.read();
	is.reset();// 重置,此时跳转到mark(0)位置读入
	int data3 = is.read();
// 缓冲输出流
	OutputStream os = new FileOutputStream(new File("c:/d.txt"));
	os = new BufferedOutputStream(os, 2);// 规定缓冲大小,在缓冲流中当flush、close、满缓冲区才会输出
	os.write('a');
	os.write('b');//只会输出'a','b'
	os.write('c');
	is.close();
	os.close();

实际演示
三个打

ObjectInputStream、ObjectOutputStream
  • 对象流可以将对象转为字节,并将字节转为对象。将对象转为字节的过程我们称之为序列化(Serializable),将字节转为对象的过程我们称之为反序列化。我们平常创建对象是在内存中创建的,有了序列化技术我们就可以将对象固定的存储在硬盘中存放了,这个技术真nb。
  • 要实现序列化技术,需要让我们要序列化的对象实现序列化,也就是实现Serializable接口,我们的八大基本数据类型的包装类和String已经实现了序列化接口,它们是不用手动实现的了。

手动实现序列化

class Stu implements Serializable {
	public int age;
	public transient String name;// 瞬时修饰符,不让其序列化

	public Stu() {

	}

	public Stu(int age, String name) {
		this.age = age;
		this.name = name;
	}

}

对象流使用,之前我的声明都是多态的,但是由于要使用特有方法所以引用对象类型是对象流

	ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(new File("c:/d.txt")));
	String s1 = new String();// String和八个基本类型的包装类已经实现序列化接口了,它们都是final的,不可以被继承
	Stu stu = new Stu(11, "jjy");
// writeObject是特有方法
	os.writeObject(s1);
	os.writeObject(stu);
	os.close();

// 反序列化deSerializable
	ObjectInputStream is = new ObjectInputStream(new FileInputStream(new File("c:/d.txt")));
	Object readObject = is.readObject();
	Object readObject2 = is.readObject();
// 判断类型
	if (readObject2 instanceof Stu) {
		stu = (Stu) readObject2;
	}

	System.out.println(readObject);
	System.out.println(stu + " " + stu.name + " " + stu.age);
	is.close();
ByteArrayInputStream、ByteArrayOutputStream

字节数组流我感觉平常真的用不到,但是该讲还是得讲,不过字节数组输出流中的toByteArray()方法很好用啊。
字节数组流跟一般流不同,在构造自己之后,它还需要传入别的流中的构造,因为用这个流的目的就是为了获取流中的字节数组,所以需要别的流。

//流的使用
public static Object copyObj(Object srcObject) {

		ByteArrayInputStream bis = null;
		ObjectInputStream ois = null;
		if (srcObject != null) {
			// 如果对象不为空则进行复制操作
			try (ByteArrayOutputStream bos = new ByteArrayOutputStream();				
					ObjectOutputStream oos = new ObjectOutputStream(bos);
			// ????
			) {
				// 序列化,将对象变为字节写入字节数组
				oos.writeObject(srcObject);
				// 取出字节数组
				byte[] bs = bos.toByteArray();
				// 取出对象
				bis = new ByteArrayInputStream(bs);
				ois = new ObjectInputStream(bis);
				return ois.readObject();

			} catch (Exception e) {
			} finally {
				if (bis != null && ois != null) {
					try {
						ois.close();// 会顺便把bis关了
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}

		} else {
			throw new RuntimeException("给定对象为空!");
		}

		return null;

	}

DataInputStream、DataOutputStream

数据字节流主要用于传输数据的,针对于八大基本类型和String

// data流用于传输数据(包括八种基本数据类型,和String)
		DataOutputStream os = new DataOutputStream(new FileOutputStream(new File("c:/d.txt")));
		os.writeByte(11);// Byte的范围-2的7次方-1到2的7次方,1个字节是八位,有一位是符号位不算
		os.writeShort(3);// short 2字节
		os.writeInt(123);// int 4字节
		os.writeLong(12131241);// long 8字节
		os.writeBoolean(true);// boolean 1位、1字节 实际没有规定大小
		os.writeChar('a');// char 2字节,英文字符实际占1字节
		os.writeFloat(2.4f);// float 4字节
		os.writeDouble(2.4);// double 8字节
		os.close();
		DataInputStream is = new DataInputStream(new FileInputStream(new File("c:/d.txt")));
		System.out.println(is.read());
		is.close();

异常处理

关于IO操作,异常处理是不可避免的,如果不知道如何处理异常的可以看看我之前关于异常的博客,这里简单写一下关于流的异常处理。
有了try-with-resources,我们处理流的异常就很简单了,我们只需要声明不需要关闭了,try-with-resources隐式地实现了AutoColoseable接口,所以会自动关闭了资源。注意要jdk1.7的版本以后实现。

	try (FileOutputStream out = new FileOutputStream(new File("c:/aa.txt"))){

}
	catch (IOException e) {
			e.printStackTrace();
		}

原始的异常处理(捕捉或声明)
声明就是方法直接 throws IOException
捕捉则要麻烦一点

	FileOutputStream out =null;
	try {
	out = new FileOutputStream(new File("c:/aa.txt"))
	}catch (IOException e) {
			e.printStackTrace();
	}finally{
		if (out!=null) {
					try {
						out.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
			}
	}

介绍

啊,终于介绍完了字节流,写了一个上午感觉对于字节流感悟更深了,后面会介绍字符流的。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值