------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();
}
}