IO流(上)


IO流 (上)

1.理解:IO流即Input流和Output流;
输入流:外围设备——>核心处理器;
输出流:核心处理器——>外围设备;

总之:以内存为中心。

2.作用:用来处理设备之间的数据传输;设备又分为输入设备和输出设备;
3.字节流和字符流:
字节流:处理的数据都是字节;
字符流:由来:早期的字节流和编码表;
作用:为了更便于对文字数据的操作;在内部可以融合编码表。
体系技巧:该体系中的子类对象中,后缀名都是父类名称,前缀名都是该流对象的功能名称。

4.字节流的抽象基类:InputStream和OutputStream ;
5.字符流的抽象基类:Reader和Writer;
读——>输入; 写——>输出

操作文件中的数据:
1. 写:将字符串写入到指定文件中;
1.创建输出流对象;对象一建立就会将指定的文件创建出来,若存在同名文件,则被覆盖;
2.通过调用write方法来写入数据;该数据被写入到了缓冲区中;
3.通过调用flush()方法刷新流对象。将缓冲区的数据写入到目的地中;
4.通过调用close()方法将流对象关闭,但关闭之前会刷新流。

代码体现:

			FileWriter fw=new FileWriter("c:\\jdk.txt");
			fw.write("abscds");
			fw.flush();
			fw.close();

flush和close方法的区别:
flush():刷新流对象,流没有关闭; close():刷新流对象且关闭流。

IO异常的处理方式:
1.在创建输出流对象时,可能路径不存在,所以会抛异常;
2.写数据时可能磁盘空间不足,仍会抛异常;
3.关闭资源时,可能关闭失败,抛异常;
4.所以将这三句使用try...catch,将异常捕获;
5.但如果对象创建失败,就不能再调用close方法即不能关闭流对象;而使用完资源后必须关闭资源,所以将close放在finally语句块中;
6.在finally语句块中仍然需要抛异常;
7.对象变量名在try语句块中,则只能在try中使用,finally中就不能使用,则不能调用close方法;所以将变量定义在try外,将其初始化为空;

8.如果流对象创建失败,则一直为空,就不能调用close方法,则发生空指针异常;所以要判断到底是否为空,不为空再调用close方法。

代码体现如下:

		FileWriter fw = null;
		try {
			fw = new FileWriter("demo.txt",true);			
			fw.write("hello"+LINE_SPARATOR+"world");
		} catch (IOException e) {
			System.out.println(e.toString());
		} finally {
			if (fw != null)
				try {
					fw.close();
				} catch (IOException e) {

					throw new RuntimeException("关闭失败");
				}
		}


小细节;1.续写文件中的内容:通过构造函数FileWriter(String,boolean):boolean 为真则续写;
2.将文件中的内容换行:

		private static final String LINE_SEPARATOR=System.getProperty(line.separator);//获取当前系统的换行符
	 	       fw.write("Hello"+LINE_SEPARATOR+"World");

2.读:将指定文件的内容读取并打印出来;

第一种方式:通过read()读取单个字符,返回int,码值,若到结束标记则返回-1;

			FileReader fr=new FileReader("d:\\demo.java");//对象一建立,就必须要明确被读取的文件
			int i=0;//定义一个变量表示读取后的数值
			while((i=fr.read())!=-1) {
				System.out.println((char)i); //打印i所对应的字符 
			}
			fr.close();

第二种方式:通过read(char[] chs)将读取到的字符存入到字符数组中,返回读取的字符个数,若到结束标记则返回-1;

			FileReader fr=new FileReader("d:\\demo.java");//对象一建立,就必须要明确被读取的文件
			int len=0;//定义一个变量表示读取的字符个数
			char[] chs = new char[1024];//定义字符数组存储读取的字符,长度为2kb,因为一个字符2字节;
			while((len=fr.read(chs))!=-1) {
				System.out.println(new String(chs,0,len)); //打印字符数组中的"有效字符" 
			}
			fr.close();


注意:如果在 char[] chs = new char[3];//若字符串为abcdeint len1=fr.read(chs);则此时,读取到的len1为3,读取到的内容是abc;若再 int len2=fr.read(chs);此时因数组长度至始至终都为3,从d开始 读,d覆盖a,读完e就遇到结束标记,而此时e就将b覆盖了,所以最终数组中的三个元素时dec;若再 int len3=fr.read(chs);此时已经读到结束标记了,所以返回-1.而chs中的元素仍然是dec.

3.复制文件的原理:从指定文件中读取文件的数据,将读取到的数据写入到另一个目的地。

6.字符流的缓冲区

1.好处:提高了对字符流读写数据的效率;若流不存在,则缓冲区存在没有意义;
2.对应抽象基类:BufferedWriter;BufferedReader
3.原理:将数据进行存储到数组中,字符流——>字符数组
4.方法:缓冲区中的写方法都是将数据写入到缓冲区中,读方法是从内存中读数据;
close():内部调用的是流对象中的close()方法,所以关闭缓冲区即关闭流;
newLine():内部调用System.getProperty("line.separator");获取系统的换行符;是缓冲区对象才能使用,特有方法。
5.BufferedReader 类:该类对象一建立,就创建了一个字符数组,默认长度为8192,同时多了一个提高行的效率;
read():读内存中的数据 ;而流对象中的read方法是从硬盘读数据;
readLine():读取一行文本,返回行内容,不返回行终止符,若到了末尾,则返回null;

readLine方法原理:内部调用了BufferedReader中的read方法,读到行终止符之前,将缓冲区中读取出来的字符临时存储,直到读到行终止符,将临时存储的数据转成字符返回。
6.缓冲区的基本思想,提高效率的原理?
缓冲区的基本思想就是对要处理的数据进行临时存储。譬如购物车以及篮子。
原理:减少频繁的操作,给读取流对象和写入流对象提供中转站,相对于来回跑的麻烦,利用缓冲区的容量,可以一边先存储,满了后再写入的方式, 这样就提高了效率。

7.缓冲区的原理分析:缓冲区一建立就已创建一个数组;

缓冲区中的read()方法:内部调用流的read([])方法,将硬盘上读出来的一部分数据到缓冲区的数组中;若缓冲区的数组中有数据,则调用read()方法将数组中的元素一个一个的取出。
readLine():基于read()方法,read方法将缓冲区数组中的元素一个一个取出,当识别到数组中的元素为行终止符时,则不再取元素,将之前的元素取出打印,再去识别数组中的元素。

8.装饰设计模式:

对一组对象进行功能的增强,职责的增强,还不改变原有对象(并不建议继承,否则体系逐渐庞大,不利于扩展和维护)。
建议;建立另一个类,持有原对象的引用,即与源对象相关联,对原对象进行装饰,比继承更灵活;
记住:被装饰类和装饰类必须属于同一个体系。

9.LineNumberReader 类:

BufferedReader 的子类,返回文本行,已定义了方法setLineNumber(int)和getLineNumber(),可分别用于设置和获取当前行号;默认 行标号从0开始 ,行号随数据读取在每个行结束符递增,还可以更改行号;若读完了返回null。
getLineNumber():获取行号;

10.字节流:什么数据都能处理;
InputStream OutputStream
FileOutputStream演示:

		//1.自定义缓冲区数组 :复制mp3文件
		FileInputStream fis=new FileInputStream("c:\\1.mp3"); 
		FileOutputStream fos=new FileOutputStream("c:\\2.mp3");
		byte[] by=new byte[1024];
		int ch=0;
		while((ch=fis.read())!=-1){
			fos.write(by,0,ch);
		}
		fis.close();
		fos.close();

		//2.使用available()创建长度刚刚好的数组;
		FileInputStream fis=new FileInputStream("c:\\1.mp3"); 
		FileOutputStream fos=new FileOutputStream("c:\\2.mp3");
		byte[] by=new byte[fis.available()];
		int ch=0;
		while((ch=fis.read())!=-1){
			fos.write(by,0,ch);
		}
		fis.close();
		fos.close();

		//3.使用缓冲区复制
		FileInputStream fis=new FileInputStream("c:\\1.mp3"); 
		BufferedInputStream bis=new BufferedInputStream(fis);
		FileOutputStream fos=new FileOutputStream("c:\\2.mp3");
		BufferedOutputStream bos=new BufferedOutputStream(fos);
		int by=0;
		while((by=bis.read())!=-1){
			bos.write(by);
		}
		bis.close();
		bos.close();

		//4.不使用缓冲区
		FileInputStream fis=new FileInputStream("c:\\1.mp3"); 
		FileOutputStream fos=new FileOutputStream("c:\\2.mp3");
		int ch=0;
		while((ch=fis.read())!=-1){
			fos.write(ch);
		}
		fis.close();
		fos.close();

开发时,建议使用第一种;

11.字节流和字符流读取区别:
字节流:一次只能读一个字节,半个中文;
字符流:一次能读两个字节,一个字符,一个中文;

注意:使用字符流不可以复制图片,因为字符流就是字节流+编码表,而用字符流去复制图片时,字符流会默认将图片的字节码格式进行编码,这样可能会导致 复制后的图片与原图不一致。

12.字节流和字符流的桥梁:转换流,将字节流和编码表进行了封装,提供了对字符操作的更便捷方式。

由来:字节流读取中文,先将中文读取到字节数组中,通过String类的getBytes()方法将字节数组中的元素转为字符串,但这样不能读取单个中文,要读取 单个中文还得通过toCharArray()方法将其转为数组;太过麻烦;所以引出字节流和字符流的桥梁——>InputStreamReader,OutputStreamWriter.

转换流的两个桥梁都是从哪里到哪里?
首先将文件通过InputStreamReader的方式将字节流数据转成字符流,为了高效,将其先存储到缓冲区中;
然后通过OutputStreamWriter将缓冲区中的字符数据转成字节,最后输出。

			FileReader fr=new FileReader("XXX");

			FileInputStream fis=new FileInputStream("XXX");
			InputStreamReader isr=new InputStreamReader(fis);

上面三句话,第一句是第二句和第三句话的封装;FileReader是InputStreamReader类的子类,因为只有有了转换流,对字节进行查表编码,才可以读取字符,所以FileReader方法都是来自转换流转化后的读写方法。

子父类的区别:FileReader是用于操作文本文件使用默认编码表的便捷类,因为它将字节流和编码表进行封装;如果操作的不是文件且不是默认编码表, 就不能用RileReader类操作文件,而是用转换流,通过传入的具体字节流对象来确定指定操作的数据,而且还可以传入指定要使用的编码 表。

便捷类弊端 :因其是将文件、字节流和默认编码表封装,所以只能操作文件,而且只能使用默认编码表。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章