IO-2-字节流

字节流

​ 在计算机中,所有文件都能以二进制的形式存在,这个二进制形式就是字节数据

​ java 的io中针对字节传输操作提供了一系列的流,为字节流。

两个抽象基类

InputStream、OutpuStream。

分别处理字节流的输入和输出

所有的字节都继承自这俩。

void close() 关闭此流并释放相关联所有系统资源
//操作IO流的时候回占用宝贵的系统资源,当操作完成后就应该讲IO所占用的系统资源释放

输入、输出,相对于谁?

当然,输出和输出这个概念出现了,就必须要有一个参照物,这里的参照物是——程序。

InputStream类的方法

boolean markSupported() 	此输入流是否支持mark和reset
void mark(int readlimit)	在此输入流中标记当前位置
void reset()				将此流重新定位到上次调用mark时的位置
int available 		返回此输入流下一个方法调用,可以不受阻赛地从此输入流读取(或跳过)的估计字节数
long skip(long n)	跳过和丢弃此输入流中数据的n个字节

最常用就是三个重载的read()和close()。

int read() 			 从输入流中逐个读取数据每个字节
int read(byte[] b)	 从输入流中读取一定数量的字节,存储在缓冲区数组b中,并返回读取的字节数
int read(byte[] b,int off,int len)将输入流中最多len个数据字节读入b数组
//后面这两个带数组的都是,一次性全部读入,提高读取效率。

OutputStream类的方法

void wirte(byte[] b) 将b数组中的字节全部写入此输出流
void wirte(int b)	将指定的字节写入此输出流
void wirte(byte[] b)	将指定的b数组中的从偏移量off开始的len个字节写入此输出流
void close() 	关闭此输出流,并释放相关所有系统资源
void flush()	刷新此输出流,强制写出所有缓冲区的输出字节

字节流读取文件

FileInputStream

FileOutputStream

如何从文件中读取数据?

首先新建一个文本文件read.txt 内容如下

Look at me now!
package test1;
import java.io.*;

public class Class1{
public static void main(String[] args){

//定义一个文件输出流
	FileInputStream fis = null;
	try{
		//创建文件输入流对象
		fis = new FileInputStream("F:/eclipse/test1/src/test1/read.txt");
		//设定读取的字节数,设定缓冲数组buffer
		int n = 512; 
		byte buffer[] = new byte[n];
		
		//读取输入流,一直读到 n = -1,就读完了 一定要有while才有效
		while((fis.read(buffer,0,n) != -1)&&(n > 0)){
			System.out.print(new String(buffer));
		}
	}catch(Exception e){
		System.out.println(e);
	}finally{
		try{
			fis.close();
		}catch(IOException e){
			e.printStackTrace();
		}
	}
	
}}
I'm so handsome.

若中途出现错误,程序会直接中断,所以一定将close()方法写到finally中。

因为finally中不能直接访问try中的内容,所以要将FileInputStream定义在try的外面。

遇到问题:找不到文件

java.io.FileNotFoundException: read.txt (系统找不到指定的文件。)

原因是:没有加上路径,即使和当前类创建在同一个目录下,eclipse也不会去寻找

在要打开的文件前加上路径即可。


以下两种皆可:

1、Unix中,/ 表示目录; \ 表示转义字符。

"F:/eclipse/test1/src/read.txt"

2、Windows中,正斜杠 / 表示除法;反斜杠 \ 用来表示目录。

fis = new FileInputStream("F:\\\\eclipse\\\\test1\\\\src\\\\read.txt");

字节流写入文件

package test1;
import java.io.*;

public class Class1{
public static void main(String[] args) throws IOException{

	System.out.print("输入要保存的内容:");
	int count,n = 512;
	byte buffer[] = new byte[n];
	
//读取标准输入流
	count = System.in.read(buffer);
	
//创建文件输出流对象
	FileOutputStream fos = new FileOutputStream("F:/eclipse/test1/src/test1/read.txt");
//write() 写入字节流
	fos.write(buffer,0,count);
	System.out.println("已成功保存到read.txt。");
	fos.close();//释放资源
	
}}

结果

输入要保存的内容:I'm so handsome.
已成功保存到read.txt。

弊端

虽然当文件不存在的时候,就会自己创建文件,再输出内容到文件中。

这里,read.txt已经存在,从结果看来,程序是将之前的全部覆盖掉了。

遇到报错

Unhandled exception type IOException

原因:未抛出异常。

解决:处理 main()函数,抛出异常即可

public static void main(String[] args) throws IOException{

添加文件内容

如果想要不清除文件内容,就需要

FileOutputStream(String FileName,boolean append)来创关键文件输出流的对象。

并且把指定的参数appedn设定为true。

package test1;
import java.io.*;

public class Class1{
public static void main(String[] args) throws IOException{

	System.out.print("输入要添加的内容:");
	int count,n = 512;
	byte buffer[] = new byte[n];
	
//读取标准输入流
	count = System.in.read(buffer);
//创建文件输出流对象,在构造时比覆写的多一个参数true即可
	FileOutputStream fos = new FileOutputStream("F:/eclipse/test1/src/test1/read.txt",true);
//写入
	fos.write(buffer,0,count);
	System.out.println("已成功保存到read.txt。");
	fos.close();//释放资源
	
}}
I'm so handsome.
I'm so handsome,too.

文件的复制

先创建一个文件copy.txt

package test1;
import java.io.*;


public class Class1{
public static void main(String[] args) throws IOException{

//创建输入流数据
	FileInputStream fis = new FileInputStream("F:/eclipse/test1/src/test1/copy.txt");
//创建输出流数据
	FileOutputStream fos = new FileOutputStream("F:/eclipse/test1/copy.txt");
	int len; //定义len,记录每次读取的字节数

//记录复制文件前的系统时间
	long begin = System.currentTimeMillis();
//读取文件并判断是否到达文件末尾
	while((len = fis.read()) != -1){
		fos.write(len);//将读到的字节写入文件
	}
//复制文件后的系统时间
	long end = System.currentTimeMillis();
	System.out.println("复制文件耗时:" + (end - begin) + "毫秒");
	fos.close();
	fis.close();

}}
复制文件耗时:2毫秒

字节流的缓冲区

上节虽然是复制文件,但是复制方式是一个个字节地复制,效率很低。

这里使用缓冲区,就是说,把一堆字节全部堆到一起,要用的时候,一次性全部带走。

一次性直接输出到文件,大大提高效率。

package test1;
import java.io.*;


public class Class1{
public static void main(String[] args) throws IOException{

//创建输入流数据
	FileInputStream fis = new FileInputStream("F:/eclipse/test1/src/test1/copy.txt");
//创建输出流数据
	FileOutputStream fos = new FileOutputStream("F:/eclipse/test1/copy.txt");
//定义缓冲区数组b的大小。	定义i,记录每次读取的字节数
	byte[]b = new byte[512];
	int i; 

//记录复制文件前的系统时间
	long begin = System.currentTimeMillis();
//读取文件并判断是否到达文件末尾
	while((i = fis.read()) != -1){
		fos.write(len);//将读到的字节写入文件
	}
//复制文件后的系统时间
	long end = System.currentTimeMillis();
	System.out.println("复制文件耗时:" + (end - begin) + "毫秒");
	fos.close();
	fis.close();

}}
复制文件耗时:1毫秒

应用缓冲区后,操作文件的次数减少了,从而提高了读写效率。

装饰设计模式

就是在不改变原来的类和使用的继承的情况下,动态扩展一个对象的功能。

创建一个包装对象,来装饰包裹真实的对象。

就像买了一套房,再安装一台空调,这样夏天才不会太热,过几年空调太老化了,想换就换掉。

要求

首先,装饰对象和被装饰的都要实现同一个接口。装饰对象要拥有被装饰对象的实例。

如图,Scource\Decorator都实现了Sourceable接口。

package test1;
import java.io.*;


public class Class1{
public static void main(String[] args) throws IOException{

//实例化source
	Sourceable source = new Source();
	System.out.println("----------装饰前----------");
	source.method();
	System.out.println("----------装饰后----------");
//创建装饰类对象,并且将被装饰类当成参数传入
	Sourceable obj =new Decorator(source);
	obj.method();
	}

}

//定义公共接口
interface Sourceable{
	public void method();
}

//定义被装饰类,只给一个method,房子
class Source implements Sourceable{
	public void method(){
		System.out.println("只是一栋房子");
	}
}

//定义装饰类,
class Decorator implements Sourceable{
//定义一个
	private Sourceable source;
//构造方法	
	public Decorator(Sourceable source){
	super();
	this.source = source;
	}
	public void method(){
		source.method();
		System.out.println("有空调啦");
		System.out.println("有电视!");
}}
----------装饰前----------
只是一栋房子
----------装饰后----------
只是一栋房子
有空调啦
有电视!

这样呢,还能动态撤销。

而继承的话,就不可以,是静态的,不能动态地增删。

字节缓冲流

IO中的一些流也用到了装饰设计模式

分别是BufferedInputStream、BufferedOutputStream

在其构造方法中,分别接收InputStream,OutputStream类型的参数作为被装饰对象,在执行的时候提供缓冲。

如图,程序和文件这两个节点互传的数据是节点流,并且是由缓冲流包裹的。

缓冲流就是对已经存在的节点流的连接和封装。

package test1;
import java.io.*;


public class Class1{
public static void main(String[] args) throws IOException{

//创建文件输入流对象
	FileInputStream fis = new FileInputStream("F:/eclipse/test1/src/test1/copy.txt");
//创建文件输出流对象
	FileOutputStream fos = new FileOutputStream("F:/eclipse/test1/copy.txt");
	
//将创建的节点流的对象,作为形参传递给缓冲流的构造方法
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
	int len; //定义len,记录每次读取的字节数

//记录复制文件前的系统时间
	long begin = System.currentTimeMillis();
//读取文件并判断是否到达文件末尾
	while((len = fis.read()) != -1){
		fos.write(len);//将读到的字节写入文件
	}
//复制文件后的系统时间
	long end = System.currentTimeMillis();
	System.out.println("复制文件耗时:" + (end - begin) + "毫秒");
	fos.close();
	fis.close();

}}
复制文件耗时:1毫秒

和之前的字节流缓冲区类似,都是对数据进行缓冲,减少操作次数。

下一节:字符流

posted @ 2021-11-17 00:26  Dinesaw  阅读(279)  评论(0编辑  收藏  举报