Java_IO流

这篇我们聊一聊java中的IO流。

什么是流呢?流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流。流的本质是数据的传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。

IO流的分类

根据处理数据类型的不同分为:字符流和字节流;

根据数据流向不同分为:输入流和输出流。

字符流和字节流

字符流的由来:因为数据编码的不同,而有了对字符进行高效操作的对象。本质其实就是基于字节流读取时,去查了指定的码表。

字节流与字符流的区别:

1)读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可以读多个字节;

2)处理对象不同:字节流能处理所有类别的对象(如图片、avi等),而字符流只能处理字符类型的数据;

3)字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作;而字符流在操作的时候是会用到缓冲区的,是通过缓冲区来操作文件。

结论:尽可能使用字节流。硬盘上所有文件都是以字节的形式进行传输或保存的,字符只是在内存中才会形成的,所以在开发中,字节流使用更广泛。

输入输出流

对输入流只能进行读操作,对输出流只能进行写操作。程序中需要根据传输数据的不同特性而使用不同的流。

java流 体系统:

 

首先我们先看下常用的几个类:

1、输入字节流——InputStream

从上面的体系图我们可以看出来,InputStream是所有输入字节流的父类,它是一个抽象类。

BufferedInputStream、FileInputStream是InputStream常用的子类。

1)FileInputStream:文件字节输入流,一切文件在系统中都是以字节的形式保存的,无论你是文档文件。视频文件、音频文件...这些文件都可以用FileInputStream去读取其保存在存储介质(磁盘等)上的字节序列。FileInputStream在创建时通过把文件名作为构造参数连接到该文件的内容字节,建立起字节流传输通道。

然后通过read(),read(byte[]),read(byte[],int begin,int len)三种方法从字节流中读取一个字节,一组字节。

2)BufferedInputStream:带缓冲的字节流,上面我们知道文件字节输入流读取的时候,是直接同字节流中读取的。由于字节流是与硬件(存储介质)进行的读取,所以速度较慢。CPU需要使用数据时通过read().read(byte[])读取数据时就要受到硬件IO的限制。而且,CPU与内存之间的读写速度比硬件IO快了不止十倍,所以,优化读写的思路就有了。在内存中建立缓冲区,先把存储介质中的字节读取到缓冲区中。CPU需要数据时直接从缓冲区读就行了,缓冲区要足够大,在被读完后又触发fill()函数自动从存储介质的文件字节内容中读取字节存储到缓冲区数组。

BufferedInputStream内部有一个缓冲区,默认大小为8M,每次调用read()方法的时候,它首先尝试从缓冲区里读取数据,若读取失败(缓冲区无可读数据),则选择从物理数据源(譬如文件)读取新数据(这里会尝试尽可能读取多的字节)放入到缓冲区,最后再将缓冲区中的内容返回个用户,由于从缓冲区中读取数据远比直接从存储介质读取速度快,所以BufferedInputStream的效率很高。

一个栗子:

public class Test03 {
	public static void main(String[] args) throws IOException {
		String fileName = "D:"+File.separator+"c.txt";
		File file = new File(fileName);
		InputStream in = null;
		if(!file.exists()){
			file.createNewFile();
		}
		try {
			in = new FileInputStream(file);
			byte[] b = new byte[(int) file.length()];
			in.read(b);
			System.out.println("文件长度为:"+file.length());
			System.out.println(new String(b));
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			in.close();
		}
	}
}

 2、输出字节流——OutputStream

从上面的体系图我们可以看出来,OutputStream是所有输出字节流的父类,它是一个抽象类。

ByteArrayOutputStream、FileOutputStream是两种基本的介质流,它们分别向byte数组,和本地文件中写入数据。

一个栗子:

//向文件中一个字节一个字节写入字符串 
public class Test07 {
	public static void main(String[] args) throws IOException {
		String fileName = "D:"+File.separator+"bb.txt";
		File file = new File(fileName);
		if(!file.exists()){
			try {
				file.createNewFile();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		OutputStream out = null;
		try {
			out = new FileOutputStream(file);
			String str = "Hello Stream !!";
			byte[] b = str.getBytes();
			for(int i=0;i<b.length;i++){
				out.write(b[i]);
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			out.close();
		}
	}
}

 

3、字符输入流——Reader

从上面的体系图我们可以看出来,Reader是所有字符输入流的父类,它是一个抽象类。

CharReader,StringReader是两种基本的介质流,它们分别从char数组,String数组中读取数据。

一个栗子:

//字符流——循环方式从文件中读取内容
public class Test11 {
	public static void main(String[] args) throws IOException {
		String fileName = "D:"+File.separator+"bb.txt";
		File file = new File(fileName);
		char[] ch = new char[100];
		Reader reader = new FileReader(file);
		int temp = 0;
		int count = 0;
		while((temp=reader.read())!=-1){
			ch[count++]=(char)temp;
		}
		reader.close();
		System.out.println("内容为:"+ new String(ch,0,count));
	}
}

 

4、字符输出流——Writer

从上面的体系图我们可以看出来,Writer是所有输出字符流的父类,它是一个抽象类。

CharArrayWriter,StringWriter是两种基本的介质流,它们分别向Char数组,String中写入对象。

一个栗子:

//字符流——写入数据
public class Test12 {
	public static void main(String[] args) throws IOException {
		String fileName = "D:"+File.separator+"cc.txt";
		File file = new File(fileName);
		Writer writer = new FileWriter(file);
		String str = "Hello R";
		writer.write(str);
		writer.close();
	}
}

 

5、字符流与字节流转换:

转换流的特点:

1)是字符流与字节流之间的桥梁;

2)可对读取到的字节数据经过指定编码转换成字符;

3)可对读取到的字符数据经过指定编码转换成字节。

何时使用转换流?

当字节和字符之间有转换动作时;

流操作的数据需要编码或解码时。

具体的对象体现?

InputStreamReader:字节到字符的桥梁;

OutputStreamWriter:字符到字节的桥梁。

这两个流对象是字符体系中的成员,它们有转换作用,本身又是字符流,所以在构造的时候需要传入字节流对象进来。

字节输出流转换为字符输出流栗子:

public class Test13 {
	public static void main(String[] args) throws IOException {
		String fileName = "D:"+File.separator+"aa.txt";
		File file = new File(fileName);
		Writer out = new OutputStreamWriter(new FileOutputStream(file));
		out.write("HHHBBB");
		out.close();
	}
}

 字节输入流转换为字符输入流栗子:

public class Test14 {
	public static void main(String[] args) throws IOException {
		String fileName = "D:"+File.separator+"bb.txt";
		File file = new File(fileName);
		Reader reader = new InputStreamReader(new FileInputStream(file));
		char[] ch = new char[100];
		int len = reader.read(ch);
		System.out.println(new String(ch,0,len));
		reader.close();
	}
}

 

File类:

常见方法:

1)创建一个文件:file.createNewFile();

2)删除一个文件:file.delete();

3)创建一个文件夹:file.mkdir();

4)列出目录下的所有文件:file.list(),filelistFiles();

一个栗子:

//list()列出的不是完整路径
public class Test15 {
	public static void main(String[] args) {
		String fileName = "D:"+File.separator+"Resources";
		File file = new File(fileName);
		String[] str = file.list();
		for(int i = 0;i < str.length;i++){
			System.out.println(str[i]);
		}
	}
}

//listFiles()可列出指定目录下所有文件完整路径
public class Test16 {
	public static void main(String[] args) {
		String fileName = "D:"+File.separator+"Resources";
		File file = new File(fileName);
		File[] f = file.listFiles();
		for(int i=0;i<f.length;i++){
			System.out.println(f[i]);
		}
				
	}
}

 5)判断一个指定路径是否为目录:isDirectory;

 

RandomAccessFile类:

该对象并不是流体系的一员,其封装了字节流,同时还封装了一个缓冲区(字符数组),通过内部的指针来操作字符数组中的数据。

特点:该对象只能操作文件,所以构造函数接收两种类型的参数:字符串文件路径;File对象。

该对象既可以对文件进行读操作,也可以进行写操作,在进行对象实例化时可指定操作模式(r,rw)。

注意:该对象实例化时,如果操作的文件不存在,会自动创建;如果文件存在,写数据未指定位置,会从头开始写,即覆盖原有内容。可以用于多线程下载会多个线程同时写数据到文件。

一个栗子:

public class Test17 {
	public static void main(String[] args) throws IOException {
		String fileName = "D:"+File.separatorChar+"aa.txt";
		File file = new File(fileName);
		RandomAccessFile raf = new RandomAccessFile(file,"rw");
		raf.writeBoolean(true);
		raf.writeBytes("abc");
		raf.writeChar('A');
		raf.writeFloat(3.14f);
		raf.writeDouble(6.128);
		raf.close();
	}
}

 

参考时光孤岛博文:https://www.cnblogs.com/QQ846300233/p/6046388.html

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2019-04-28 10:37  一枚路过的小码农  阅读(196)  评论(0编辑  收藏  举报