黑马程序员_IO流(一)

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

一、IO流概述

概述

IO流用来处理设备之间的数据传输。Java对数据的操作是通过流的方式。

Java用于操作流的对象都在IO包中。输入流和输出流相对于内存设备而言。


IO流常用的基类

字节流:InputStream   OutputStream

字符流:Reader            Writer

字符流基于字节流


在这四个类中,他们的子类共有一个特点:子类名后缀都是父类名,前缀名都是这个子类的功能名称。

比如Reader的子类FileReader,InputStream的子类FileInputStream


二、FileWriter

FileWriter是一个操作字符文件的输入流

写入字符流步骤的代码示例

import java.io.*;
class  FileWriterDemo {
	public static void main(String[] args) throws IOException {
		//创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。
		//而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
		//其实该步就是在明确数据要存放的目的地。
		FileWriter fw = new FileWriter("demo.txt");

		//调用write方法,将字符串写入到流中。
		fw.write("abcde");

		//刷新流对象中的缓冲中的数据。
		//将数据刷到目的地中。
		fw.flush();

		//关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。
		//将数据刷到目的地中。
		//和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。
		fw.close();
	}
}
续写

上面的代码有一个弊端,就是即使存在已有文件,也会将其覆盖。所以为了保证不覆盖并且能在文件的末尾出续写,可以往FileWriter中传入参数true

代码示例

FileWriter fw = new FileWriter("demo.txt",true);
fw.write("abcde");


IO流的异常处理方式:为防止代码异常导致流无法关闭,因此在finally中对流进行关闭。

代码示例

import java.io.*;

class FileWriterDemo {
	public static void main(String[] args) {
		//在try外建立引用,在try内进行初始化。这样fw变量就作用于整个函数
		FileWriter fw=null;
		try {
			fw=new FileWriter("demo.txt",true);//存在参数true,续写数据
			fw.write("abcdefg");
		}
		catch (IOException e) {
			System.out.println("catch:"+e.toString());
		}
		finally {
			try {
				/*fw.close()是一定执行的语句,所以要放在finally中,
				但fw.close存在异常,所以要单独try一下。
				要是在对象初始化时发生异常,
			  fw就为空,就不能执行close方法所以要进行判断。*/
				if(fw!=null)
					fw.close();
			}
			catch (IOException e) {
				System.out.println("catch:"+e.toString());
			}
		}	
	}
}

三、FileReader

FileReader是文本文件读取流

存在着字符字节读取和字符数组读取两种读取方式


字符字节读取代码示例

import java.io.*;

class  FileReaderDemo {
	public static void main(String[] args) throws IOException {
		//创建一个文件读取流对象,使用FileReader让创建好的流对象和指定名称的文件相关联。
		//要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException
		FileReader fr = new FileReader("demo.txt");

		//调用读取流对象的read方法。
		//read():一次读一个字符。而且会自动往下读。		
		int ch = 0;
    //条件是没有读到结尾
		while((ch=fr.read())!=-1) {
			System.out.println(
		}
		fr.close();
	}
}

字符字节读取比较麻烦一般使用字符数组读取

字符数组读取代码示例

import java.io.*;

class FileReaderDemo2 {
	public static void main(String[] args) throws IOException {
		FileReader fr = new FileReader("demo.txt");
		
		//定义一个字符数组。用于存储读到字符。
		//该read(char[])返回的是读到字符个数,一般是1024的倍数。
		char[] buf = new char[1024];

		int num = 0;
		while((num=fr.read(buf))!=-1) {
			System.out.println(new String(buf,0,num));
		}
		fr.close();
	}
}

注意

调用读取流对象的read方法,read():一次读一个字符,而且会自动往下读,如果读到流的末尾,则返回-1(结束标识)

定义文件路径时,可以用“/”或者“\\”。

在创建一个文件时,如果目录下有同名文件将被覆盖。

在读取文件时,必须保证该文件已存在,否则出异常。


练习:将C盘一个文本文件存储到D盘

/*
复制的原理:
其实就是将C盘下的文件数据存储到D盘的一个文件中。

步骤:
1,在D盘创建一个文件。用于存储C盘文件中的数据。
2,定义读取流和C盘文件关联。
3,通过不断的读写完成数据存储。
4,关闭资源。
*/

import java.io.*;

class CopyText {
	public static void main(String[] args) throws IOException {
		copy_2();
	}

	public static void copy_2() {
		FileWriter fw = null;//在外初始化,作用于整个函数
		FileReader fr = null;
		try	{
			fw = new FileWriter("SystemDemo_copy.txt");//复制的新文件
			fr = new FileReader("SystemDemo.java");//读取的旧文件
			//利用数组存储字符
			char[] buf = new char[1024];

			int len = 0;
			while((len=fr.read(buf))!=-1) {
				fw.write(buf,0,len);
			}
		}		
		catch (IOException e) {
			throw new RuntimeException("读写失败");
		}
		finally {
			if(fr!=null)
				try {
					fr.close();
				}
				catch (IOException e) {
				}
			if(fw!=null)
				try {
					fw.close();
				}
				catch (IOException e) {
				}
		}
	}

	//从C盘读一个字符,就往D盘写一个字符。
	public static void copy_1()throws IOException {
		//创建目的地。
		FileWriter fw = new FileWriter("RuntimeDemo_copy.txt");

		//与已有文件关联。
		FileReader fr = new FileReader("RuntimeDemo.java");

		int ch = 0;

		while((ch=fr.read())!=-1) {  
			//读到流的末尾返回-1
			fw.write(ch);
		}		
		fw.close();
		fr.close();
	}
}

四、字符流缓冲区BufferedReader和BufferWriter

缓冲区的出现就是为了提高流的操作效率,所以在创建缓冲区之前,必须要先有流对象,将流对象初始化到构造函数中去。

缓冲区出现了一个跨平台的换行方法newLine();

BufferedReader提供了readLine方法,一次读一行文本数据,方便了数据的获取。当返回null时,表示读到了文件末尾。

readLine方法读取到的内容中只包括每行数据的回车换行符之前的内容。因此如果同时调用BufferedWriter的write方法时,要同时调用newLine方法,才能实现换行。


练习:通过缓冲区复制一个java文件

import java.io.*;
class CopyTestByBuf {
	public static void main(String[] args) {
		BufferedWriter bufw=null;
		BufferedReader bufr=null;
		try {
			//创建目的地,并使用缓冲技术
			bufw=new BufferedWriter(new FileWriter("bufWriter_copy.java"));
			//与已有文件关联,并使用缓冲技术
			bufr=new BufferedReader(new FileReader("Demo.java"));
			String line=null;
			while((line=bufr.readLine())!=null) {
				bufw.write(line);//写出一行的数据
				bufw.newLine();//readLine不返回换行符,所以newLine和readLine一起使用才能实现换行读取
				bufw.flush();
			}
		}
		catch (IOException e) {
			throw new RuntimeException("读写失败");
		}
		finally {
			try {
				if(bufr!=null)
					bufr.close();
			}
			catch (IOException e) {
				throw new RuntimeException("读取关闭失败");
			}
			try {
				if(bufw!=null)
					bufw.close();
			}
			catch (IOException e) {
				throw new RuntimeException("写入关闭失败");
			}
		}
	}
}

五、装饰设计模式

概述

当想要对已有的对象进行功能增强时,可以定义新的类然后将原有的对象传入,基于已有的对象并提供加强的功能。这个自定义的类称为装饰类。


特点

装饰类通常都会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能


代码示例

class Person {
       void chifan() {
            System.out.println("吃饭");
      }
}

//采用装饰的方式增强Person类
//这个类的出现是为了增强Person而出现的
class NewPerson {
       private Person p;

      NewPerson(Person p) {
             this.p = p;
      }

       public void chifan() {
            System.out.println("开胃酒");
            p.chifan();
            System.out.println("甜点");
      }
}

//采用继承的方式增强Person类
class NewPerson2 extends Person {
       public void chifan() {
            System.out.println("开胃酒");
             super.chifan();
            System.out.println("甜点");
      }
}

public class PersonDemo{
       public static void main(String[] args) {
            Person p = new Person();
            NewPerson np1 = new NewPerson(p);
            np1.chifan();

            System.out.println( "............");

            NewPerson2 np2 = new NewPerson2();
            np2.chifan();
      }
}
//继承和装饰结果相同,那么他们的区别是什么

装饰和继承的区别:

装饰模式比继承要灵活。避免了继承体系的臃肿,且降低了类与类之间的关系。

装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰的类通常都是属于一个体系。

从继承结构转为组合结构。


六、File字节流的读写

概述

基本操作与字符流类相同。但它不仅可以操作字符,还可以操作其他媒体文件。


读写字节流:

InputStream 输入流(读)    OutputStream 输出流(写)


InputStream特有方法

int available();//返回文件中的字节个数

注意!可以利用此方法来指定读取方式中传入数组的长度,从而省去循环判断。但是如果文件较大,而虚拟机启动分配的默认内存一般为64M。

当文件过大时,此数组长度所占内存空间就会溢出。所以,此方法慎用,当文件不大时,可以使用。


注意!FileWriter的write方法不同,这里的不需要刷新动作


通过下面这段代码了解字节流的使用

import java.io.*;
class CopyPic {
	public static void main(String[] args) {
		FileInputStream fis=null;
		FileOutputStream fos=null;
		try {
			fis=new FileInputStream("e:\\1.gif");//字节读取流对象和图片关联
			fos=new FileOutputStream("e:\\2.gif");//字节写入流对象创建一个图片文件
			byte[] buf=new byte[1024];//创建数组用于存储图片数据
			int len=0;
			//返回的是读取字节的个数
			while((len=fis.read(buf))!=-1) {
				fos.write(buf,0,len);//通过循环写出数组中的图片数据
			}
		}
		catch (IOException e) {
			throw new RuntimeException("文件复制失败");
		}
		finally {
			try {
				if(fis!=null)
					fis.close();//不需要刷新流
			}
			catch (IOException e) {
				throw new RuntimeException("读取关闭失败");
			}
			try {
				if(fos!=null)
					fos.close();
			}
			catch (IOException e) {
				throw new RuntimeException("写入关闭失败");
			}
		}
	}
}

七、字节流缓冲区

读写特点

read():会将字节byte型值提升为int型值

write():会将int型强转为byte型,即保留二进制数的最后八位。


练习:复制mp3文件

import java.io.*;

public class CopyMp3Test{
       public static void main(String[] args) throws IOException {
            copy_1();
      }
     
       public static void copy_1() throws IOException {
            //创建输入流,使用缓冲技术
            FileInputStream fis = new FileInputStream("0.mp3" );
            BufferedInputStream bufis = new BufferedInputStream(fis);
 						//创建输出流,使用缓冲技术
            FileOutputStream fos = new FileOutputStream("2.mp3" );
            BufferedOutputStream bufos = new BufferedOutputStream(fos);

             int ch = 0;
<span style="white-space:pre">	</span>     //文件全部被取出read方法返回-1
             while((ch = bufis.read()) != -1){
                  bufos.write(ch);
            }

            bufis.close();
            bufos.close();
      }
}





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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值