---------------------- 黑马程序员 Android培训、期待与您交流! ----------------------
IO流(input out)
l IO流用来处理设备之间的数据传输
l Java对数据的操作是通过流的方式
l Java用于操作流的对象都在IO包中
l 流按操作数据分为两种:字节流与字符流 。
l 流按流向分为:输入流,输出流。
IO流常用基类
字节流的抽象基类:
• InputStream ,OutputStream。
字符流的抽象基类:
• Reader ,Writer。
注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
• 如:InputStream的子类FileInputStream。
• 如:Reader的子类FileReader。
字符流FileWriter写入文件
/*
* 概述:字符流是对应汉字的映射关系的GBK编码表,从最初的2312->18000->GBK的演化
*
* 字符流和字节流
* |--字符流的两个基类:InputStream OutputStream
*
* |--字节流的两个基类:Reader Writer
*
* 先学习下字节流的特点。
* 既然IO流是用来操作数据的,那么数据的最常见体现形式是:文件。
*
* 需要:在硬盘上创建一个文件,并写入一些文字数据。
*
* 找到一个专门用于操作文件的Writer子类对象,FileWriter..后缀名是父类名,前缀名是功能。
*
* ------------------------------------------
* 注意:FileWriter对象存在抛出异常,所以要在函数上抛出IOException异常
* |--write:也存在抛出异常
* |--flush:也存在抛出异常
* |--close:也存在抛出异常
*/
public class _01_FileWrite写入文件 {
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();
}
}
IO异常处理
/*
* IO异常处理方式
* try{}catch{}finally{}
*/
import java.io.*;
public class _02_IO异常处理 {
public static void main(String[]args)
{
FileWriter fw = null;//需要将创建文件的代码块放到外面,这样其它代码块才能访问到
try
{
fw = new FileWriter("k:\\Demo.txt");
fw.write("abcderffda");
}
catch(IOException e)//IOException异常
{
System.out.println(e.toString());
}
finally
{
try
{
if(fw!=null)//判断fw是否为空(即文件夹是否创建成功)
fw.close();
}
catch(IOException e)
{
System.out.println(e.toString());
}
}
}
}
文件的续写
/*
* 演示对已有文件的数据续写
* 判断是否为true;--文件是否存在即为true
* FileWriter fw = new FileWriter("Demo.txt",true);
*
* 续写时的--换行:\r\n 换行符
*/
import java.io.*;
public class _03_文件的续写 {
public static void main(String[]args)
{
FileWriter fw = null;
try
{
//传递一个true参数,代表不覆盖已有文件,并在已有文件的末尾处,进行数据添加
fw = new FileWriter("Demo.txt",true);
fw.write("\r\nhahaha");
}
catch(IOException e)
{
System.out.println(e.toString());
}
finally
{
try
{
fw.close();
}
catch(IOException e)
{
System.out.println(e.toString());
}
}
}
}
文本文件读取方式一
import java.io.*;
public class _04_文本文件读取方式一 {
public static void main(String[]args)throws IOException
{
//创建一个文件读取流对象,和指定名称的文件相关联
//要保证文件是已经存在的,如果不存在会发生异常FileNoFoundException
FileReader fr = new FileReader("Demo.txt");
//调用读取流的read方法。
//read();一次读一个字符,而且会自动往下读
int ch = 0;
while((ch=fr.read())!=-1)
{
System.out.println("ch="+(char)ch);
}
fr.close();
}
}
通过字符数组读取方式二
/*
* 字符数组读取------------------------------------------
* char[]buf = new char[1024];
* 字符数组中通过定义成1024,每满1024个字符,循环就打印一次。
* -----------------------------------------------------
* int num = fr.read(buf);
* System.out.println(new String(buf,0,num));
*/
import java.io.*;
public class _05_通过字符数组读取 {
public static void main(String[]args)throws IOException
{
FileReader fr = new FileReader("Demo.txt");
//字义一个字符数组,用于存储读到的字符
//该read(char[])返回的是读到的字符个数。
//字符数组中通过定义成1024,每满1024个字符,循环就打印一次。
char[]buf = new char[1024];
int num = 0;
//判断,读到-1就表示读取完毕
while((num = fr.read(buf))!=-1)
{
//打印字符数组中从0-num的字符
System.out.println(new String(buf,0,num));
}
fr.close();
}
}
拷贝文件
/*
* 复制原理:
* 1,在D盘创建一个文件,用于存储C盘文件中的数据。
* 2,定义读取流和C盘文件相关联。
* 3,通过不断读写,完成数据存储。
* 4,关闭资源。
*/
import java.io.*;
public class _07_拷贝文本文件 {
public static void main(String[]args)throws IOException
{
//copy1();
copy2();
}
public static void copy1()throws IOException
{
//创建目的地
FileWriter fw = new FileWriter("Demo2.txt");
//创建操作对象
FileReader fr = new FileReader("Demo.txt");
int ch=0;
while((ch = fr.read())!=-1)
{
fw.write(ch);
}
fw.close();
fr.close();
}
public static void copy2()
{
FileWriter fw = null;
FileReader fr = null;
try
{
//对象初始化。
fw = new FileWriter("Demo3.txt");
fr = new FileReader("Demo.txt");
//定义一个数组,将读写到的字符流,先存入数组中
char[] buf = new char[1024];
//声明一个变量,循环判断数组中是否还有字符
int len = 0;
while((len = fr.read(buf))!=-1)
{
fw.write(buf,0,len);//将数组中的字符流,从0到len写入新磁盘
}
}
catch(IOException e)
{
throw new RuntimeException("读写失败!");
}
finally//关闭两个读写资源
{
try
{
if(fr!=null)
fr.close();
}
catch(IOException e)
{}
try
{
if(fw!=null)
fw.close();
}
catch(IOException e)
{}
}
}
}
BufferedWriter缓冲区写入文件
/*
* BufferedWriter:缓冲区
*
* 缓冲区的出现是为了提高流的操作效率而出现的。
*
* 所以创建缓冲区之前必须要有流对象。
*
* 该缓冲区中提供了一个跨平台的换行符:newLine();
*/
import java.io.*;
public class _08_BufferedWriter {
public static void main(String[]args)throws IOException
{
//创建一个字符写入流对象
FileWriter fw = new FileWriter("Demo.txt");
//为了提高字符写入效率,加入了缓冲技术。
//只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。
BufferedWriter buf = new BufferedWriter(fw);
for(int x=0;x<5;x++)
{
buf.write("abdsafa"+x);
buf.newLine();
buf.flush();
}
//记住:只要用到缓冲区,就要记得刷新(因为刷新可以将数据保存到文件上,防止停电,缓冲区释放)
//buf.flush();
//其实关闭缓冲区,就是在关闭缓冲区中的流对象。
buf.close();
}
}
BufferedReader缓冲区读取流
/*
* BufferedReader
* 字符读取流缓冲区:
* readLine();
* 该缓冲区提供了一个一次读一行的方法,方便于对文本数据的获取。
* 当返回null表示文件的末尾。
*/
import java.io.*;
public class _09_BufferReader {
public static void main(String[]args)throws IOException
{
//创建一个读入字符流对象和文件相关联
FileReader fr = new FileReader("Demo.txt");
//为了提高效率,加入缓冲技术。
//将字符读取流对象作为参数传递给缓冲对象的构造函数。
BufferedReader bufr = new BufferedReader(fr);
String line=null;
while((line=bufr.readLine())!=null)
{
System.out.println(line);
}
bufr.close();
}
}
通过缓冲区复制文件
import java.io.*;
public class _10_通过缓冲区复制文件 {
public static void main(String[]args)
{
BufferedReader bufr = null;
BufferedWriter bufw = null;
try
{
//直接对象初始化。创建读入文件和写入文件
bufr = new BufferedReader(new FileReader("Demo.txt"));
bufw = new BufferedWriter(new FileWriter("copyDemo.txt"));
String line = null;
while((line = bufr.readLine())!=null)
{
bufw.write(line);
bufw.newLine();
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
{
//他有一个方法就是吃饭
public void chiFan()
{
System.out.println("吃饭");
}
}
//装饰Person类
class SuperPerson
{
private Person p;
SuperPerson(Person p)
{
this.p = p;
}
public void superChiFan()
{
System.out.println("先来杯开胃酒");
p.chiFan();//调用
System.out.println("再来点甜点");
System.out.println("抽根烟");
}
}
public class _12_装饰设计模式 {
public static void main(String[]args)
{
Person p = new Person();
//p.chiFan();
SuperPerson sp = new SuperPerson(p);//将引用对象传进来
sp.superChiFan();
}
}
装饰与继承的区别
/*
* 装饰专门用与读取数据的类:
* |--MyTextReader
* |--MyBufferedTextReader
* |--MyMediaReader
* |--MyBufferedMediaReader
* |--MyDataReader
* |--MyBufferedDataReader
*
* class MyBufferedReader
* {
* MyBufferedReader(MyBufferedTextReadertxt)
* {}
* MyBufferedReader(MyBufferedMediaReaderMedia)
* {}
* MyBufferedReader(MyBufferedDataReaderDate)
* {}
* }
* 上面这个类的扩展性能很差,找到其参数的共同类型,通过多态的形式可以提高扩展性。
*
* MyBufferedReader extends MyReader
* {
* privateMyReader r;
* MyBufferedReader(MyReaderr)
* {
*
* }
* }
*---------------------------------------------------------------------------
* * 装饰专门用与读取数据的类:
* |--MyTextReader
* |--MyMediaReader
* |--MyDataReader
* |--MyBufferedReader//添加了一个装饰类的子类
*
* 装饰模式比继承要灵活,避免了继承体系臃肿,
* 而且降低了类与类之间的关系
*
* 装饰设计模式的特点:
* 装饰类因为增强已有类对象,具备的功能和已有的是相同的,只不过提供了更强功能。
* 所以装饰类和被装饰类通常都属于一个体系。
*/
LineNumberReader行号
/*
* LineNumberReader:
* |--getLineNumber: 显示行号
* |--setLineNumber: 设置行号起始值
*/
import java.io.*;
public class _14_LineNumberReader行号 {
public static void main(String[]args)throws IOException
{
//创建读取流对象
FileReader fr = new FileReader("Demo.txt");
//创建关联对对象,进行标识
LineNumberReader lnr = new LineNumberReader(fr);
lnr.setLineNumber(10);//起始行号
String line = null;
while((line=lnr.readLine())!=null)
{
System.out.println(lnr.getLineNumber()+":"+line);
}
//关闭标识
lnr.close();
}
}
字节流File读取操作
/*
* 字节流:
* 与字符流的区别:不需要使用刷新,缓冲区,即可写入
*
* FileOutputStream:写入字节
* |--getBytes();将字符串转成字节
*
* FileInputStream:读取字节(推荐使用此方法)
* |byte[] buf = new byte[1024];定义字节数组,接收
*
* --------------------------------------------------
* 创建一个刚好的字节流长度
* available();可以直接获取字节流的长度
*/
import java.io.*;
public class _16_字节流Fill读写操作 {
public static void main(String[]args)throws IOException
{
//创建写入字节流对象
FileOutputStream fos = new FileOutputStream("fos.txt");
fos.write("abcdefafdafd".getBytes());
fos.close();
method3();
}
public static void method1()throws IOException
{
//第一种:一个字节一个字节读:创建写取字节流对象
FileInputStream fis = new FileInputStream("fos.txt");
int ch = 0;
while((ch=fis.read())!=-1)
{
System.out.print("第一种读取方式:"+(char)ch);
}
fis.close();
}
public static void method2()throws IOException
{
//第二种:定义字节数组读取
FileInputStream fis2 = new FileInputStream("fos.txt");
//创建字节流数组
byte[] buf2 = new byte[1024];
int len = 0;
while((len=fis2.read(buf2))!=-1)
{
System.out.println("第二种读取方式:"+new String(buf2,0,len));//读取数组从0到len,并转换成字符串
}
fis2.close();
}
public static void method3()throws IOException
{
//第三种:直接获取字节流长度
FileInputStream fis3 = new FileInputStream("fos.txt");
//定义一个刚刚好的缓冲区,不用再循环了
byte[] buf3 = new byte[fis3.available()];
fis3.read(buf3);
System.out.println(new String(buf3));
fis3.close();
}
}
使用字节流(拷贝图片)
/*
* FileOutputStream:
* FileInputStream:
* }--需要使用byte[]字节数组配合使用,且数组长度为1024
*
* 复制一张图片----使用字节流循环
* 思路:
* 1,用字节读取流对象与图片关联
* 2,用字节写入流对象创建一个图片文件,用于存储获取到的图片数据。
* 3,通过循环读写,完成数据的存储
* 4,关闭资源。
*/
import java.io.*;
public class _17_拷贝图片 {
public static void main(String[]args)
{
FileOutputStream fos=null;
FileInputStream fis=null;
try
{
fis = new FileInputStream("电熨斗1.jpg");//读取
fos = new FileOutputStream("电熨斗11.jpg");//写入
byte[] buf = new byte[1024];
//定义变量,判断是否还有字节。
int len = 0;
while((len=fis.read(buf))!=-1)
{
fos.write(buf,0,len);//写入数组中从0到len(从字节数组中读取到的)字节
}
}
catch(IOException e )
{
throw new RuntimeException("复制文件失败");
}
finally
{
try
{
if(fos!=null)
fos.close();
}
catch(IOException i)
{
throw new RuntimeException("写入文件失败");
}
try
{
if(fis!=null)
fis.close();
}
catch(IOException e)
{
throw new RuntimeException("读取文件失败");
}
}
}
}
拷贝MP3
/*
* 使用字节流缓冲区复制:
* BufferedInputStream:读取
* BufferedOutputStream:写入
*/
import java.io.*;
public class _18_拷贝MP3 {
public static void main(String[]args)throws IOException
{
//获取时间(毫秒)
long start = System.currentTimeMillis();
copyMP3();
long end = System.currentTimeMillis();
System.out.println("复制时间:"+(end-start)+"毫秒");
}
//通过字节流的缓冲区完成复制。
public static void copyMP3()throws IOException
{
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\桌面文件\\喜欢你.mp3"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\桌面文件\\喜欢你2.mp3"));
//定义一字节变量
int by = 0;
while((by=bis.read())!=-1)
{
bos.write(by);
}
bos.close();
bis.close();
}
}
读取键盘录入
/*
* 读取键盘的录入。
* System.out: 对应的是标准输出设备。控制台。
* System.in: 对应的是标准输入设备。键盘。
* System.out.println('\r'+0);打印值为13
* System.out.println('\n'+0);打印值为10
* -------------------------------------
* 需求
* 通过键盘录入数据,
* 当录入一行数据后,就将该行数据打印。
* 如果录入over,就停止录入
*/
import java.io.*;
public class _20_读取键盘录入 {
public static void main(String[]args)throws IOException
{
//读取键盘输入
InputStream in = System.in;
//定义一个缓冲区容器,StringBuiler,可变长度的
StringBuilder sb = new StringBuilder();
while(true)
{
int ch = in.read();
if(ch=='\r')
continue;
if(ch=='\n')
{
String s = sb.toString();
if("over".equals(s))
break;
System.out.println(s.toUpperCase());
sb.delete(0,sb.length());//清空缓冲区
}
else
{
sb.append((char)ch);
}
}
}
}
字节流转字符流(读取转换流)
/*
* 字符流
* -----------------------------------------------------
* FileReader 读取
* FileWriter 写入
*
* BufferedReader 缓冲区-读取
* BufferedWriter 缓冲区-写入
* OutputStreamReader 字符流-->字节流
*
* 字节流
* -----------------------------------------------------
* FileInputReader 读取
* FileOutputReader 写入
*
* BufferedInputReader 缓冲区-读取
* BufferedOutputReader 缓冲区-写入
* InputStreamWriter 字节流-->字符流
*
* ------------------------------------------------------
* 通过刚才的键盘录入一行数据,并打印其大写,其实就是读一行数据原理
* 也就是readLine方法,
*
* 能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢〈〉〈、〉
* readLine的方法是BufferedRead方法。
* 而键盘录入的read方法是字节流InputStream方法。
*
* 那么能不能将字节流转成字符流,再使用字符流缓冲区的readLine方法呢>。
*/
import java.io.*;
public class _21_读取转换流 {
public static void main(String[]args)throws IOException
{
//获取键盘录入对象
InputStream in = System.in;
//将字节流对象转成字符流对象,使用转换流。InputStreamReader
InputStreamReader isr = new InputStreamReader(in);
//为了提高效率,将字符串进行缓冲区技术提高效率。使用BufferedReadder();
BufferedReader bufr = new BufferedReader(isr);
String len = null;
while((len = bufr.readLine())!=null)
{
if("over".equals(len))
break;
System.out.println(len);
}
bufr.close();
}
}
字符流转字节流
/*
* OutputStreamReader:
*
* 压缩为一句话:重点:
*
* 键盘录入对象
* BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
*
* 输出
* BufferedWriter br = new BufferedWriter(new OutputStreamWriter(System.out));
*/
import java.io.*;
public class _22_写入字符流_转_字节流 {
public static void main(String[]args)throws IOException
{
//获取键盘录入对象
//InputStream in = System.in;
//将字节流对象转成字符流对象,使用转换流。InputStreamReader
//InputStreamReader isr = new InputStreamReader(in);
//为了提高效率,将字符串进行缓冲区技术提高效率。使用BufferedReadder();
//BufferedReader bufr = new BufferedReader(isr);
//压缩为一句话:键盘录入对象
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
//OutputStream out = System.out;
//创建字符流转换字节流对象。
//OutputStreamWriter osw = new OutputStreamWriter(out);
//创建BufferedWriter,调用其newLine换行方法。
//BufferedWriter br = new BufferedWriter(osw);
BufferedWriter br = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
br.write(line);//直接输出,不用System.out.prn了
br.newLine();
br.flush();
}
bufr.close();
}
}
流操作规律1
/*
* 1,需求:将控制台信息存储到文件上
* BufferedWriter bufw =
* new BufferedWriter(newOutputStreamReader(new FileOutpurStream("Demo.txt")));
* 源:键盘
* 目的:文件
*
* 2,需求:想把键盘录入的数据存储到一个文件中。
* BufferedReader bufr =
* new BufferedReader(new InputStreamReader(newFileInputStream("Demo.txt"))));
* 源:文件。
* 目的:控制台。
*
*--------------------------------------------------------------------------------
* 流操作的基本规律:
* 最痛苦的就是流对象有很多,不知道该用哪一个。
*
* 通过(三)个明确来完成。
*--------------------------------------------------------------------------------
* 1,明确源和目的
*
* |-源:输入流。InputStream Reader
* |-目的:输出流。OutputStream Writer
*
* 2,操作的数据是否是纯文本
* |-是:字符流
* |-不是:字节流
*
* 3,当体系明确后,在明确要使用哪个具体的对象。
* 通过设备来进行区分。
*
* 源设备:内存,硬盘,键盘
* 目的设备:内存,硬盘,控制台。
*
* -----------------------------------------
* 1,将一个文本文件中数据存储到另一个文件中,复制文件
*
* 源:因为是读取数据,所以使用读取流。InputStream Reader
* 是不是操作文本文件。
* 是! 这时就可以选择Reader
* 这样体系就明确了。
*
* 接下来该明确体系中的哪个对象有。
* 明确设备:硬盘。上一个文件。
* Reader体系中可以操作文件的对象是FileReader
* 是否提高效率:是!.加入Reader体系中缓冲区BufferedReader.
* FileReaderfr = new FileReader("a.txt");
* BufferedReaderbufr = new BufferedReader(fr);
*
*
* 目的:OutputStream Writer
* 是否是纯文本。
* 是!Writer.
* 设备:硬盘。一个文件。
* Writer体系中可以操作文件的对象是FileWriter
* 是否提高效率:是!.加入Writer体系中缓冲区BufferedWriter
* FileWriterfw = new FileWriter("b.txt");
* BufferedWriterbufw = BufferedWriter(fw);
*/
import java.io.*;
public class _23_流操作规律_1 {
public static void main(String[]args)throws IOException
{
//键盘的最常见写法。(BufferedReader 键盘输入流)
BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("Demo.txt")));
//(BufferedWriter 键盘输出流)
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close();
bufw.close();
}
}
流操作规律2
/*
* 需求:将键盘录入的数据,保存到一个文件中。
* 那么这个需求中,源和目的都在。
*
* 那么分别分析:
* 源: InputStream Reader
* 是不是纯文本?是! Reader
*
* 设备:键盘。对应的对象是System.in;
* ---------------------------------
* 不是选择Reader吗?System.in不是对应的字节流吗?
* 为了操作键盘的文本数据方便,转成字符流按照字符串操作是最方便的。
* 所以既然明确了Reader,那么就将System.in转换成Reader;
* 用了Reader体系中的转换流:InputStreamReader
* InputStreamReader isr = newInputStreamReader(System.in);
*
* 需求提高效率吗?需要,BufferedReader
* BufferedReader bufr = new BufferedReader(isr);
*
*----------------------------------------------------------------
* 目的:OutputStream Writer
* 是否是纯文本?是!Writer
* 设备:硬盘。一个文件。使用FileWriter
* FileWriter fw = newFileWriter("c.txt");
*
* 需要提高效率吗?需要
* BufferedWriter bufw = new BufferedWriter(fw);
*/