您的位置:首页 > 职场人生

黑马程序员————IO流(1)

2015-08-11 16:51 441 查看
------Java培训Android培训iOS培训.Net培训、期待与您交流!-------

一、基本概念

IO流即输入(Input)输出(Output)流,用来处理设备之间的数据传输。

流:可以理解为数据的流动,就是一个数据流。IO流的最终要以对象来体现,对象都存在IO包中。

流的分类:

按操作数据:字节流和字符流

字节流:处理字节数据的流对象。设备上的数据无论是图片或者MP3,文字,它们都以二进制存储的。二进制的最终都是以一个8位为数据单元进行体现,所以计算机中的最小数据单元就是字节。意味着,字节流可以处理设备上的所有数据,所以字节流一样可以处理字符数据。

那么为什么要有字符流呢?因为字符每个国家都不一样,所以涉及到了字符编码问题,那么GBK编码的中文用unicode编码解析是有问题的,就是说一个中文用不能的码表可能出现的结果不同,所以需要获取中文字节数据的同时+ 指定的编码表才可以解析正确数据。为了方便于文字的解析,所以将字节流和编码表封装成对象,这个对象就是字符流。只要操作字符数据,优先考虑使用字符流体系。

按流向:输入流(读),输出流(写)

输入:将外设中的数据读取到内存中

写入:将内存中的数据写入到外设中

IO流的体系:有四个顶层的基类

字节流的顶层基类:

1.InputStream 2.OutputStream

字符流的顶层基类:

1.Reader 2.Writer

注:这四个类派生出的子类的名称,都是以父类的名作为子类名的后缀

例如:OutputStream的子类FileOutputStream

Reader的子类FileReader

二、字符流

1.一些需求来了解字符流

(1)需求1:将一些文字存储在硬盘中的文件中

public static void main(String[] args) throws IOException { //读、写都会发生IO异常
/*
1:创建一个字符输出流对象,用于操作文件。该对象一建立,就必须明确数据存储位置,是一个文件。
2:对象产生后,会在堆内存中有一个实体,同时也调用了系统底层资源,在指定的位置创建了一个存储数据的文件。
3:如果指定位置,出现了同名文件,文件会被覆盖。
*/
FileWriter fw = new FileWriter("demo.txt"); // FileNotFoundException
/*
IO异常出现的原因是,如果我写入的路径是"k:/demo.txt",可是将这个程序给别人,被人没有k盘,就出现了异常。下面会说具体的处理方法。
*/
/*
调用Writer类中的write(String)方法写入字符串。字符串并未直接写入到目的地中,而是写入到了流中,(其实是写入到临时存储缓冲区中)。怎么把数据弄到文件中?
*/
fw.write("abcde");
fw.flush(); // 刷新缓冲区,将缓冲区中的数据刷到目的地文件中。
fw.close(); // 关闭流,其实关闭的就是java调用的系统底层资源。在关闭前,会先刷新该流。
}


close()和flush()的区别:

flush():将缓冲区的数据刷到目的地中后,流可以使用。可以使用多次

close():将缓冲区的数据刷到目的地中后,流就关闭了,该方法主要用于结束调用的底层资源。这个动作一定做。只能用一次,后面不能在写入数据了。

补充:

1.换行

private static final String LINE_SEPARATOR =System.getProperty("line.separator");
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("demo.txt");
fw.write("abc"+LINE_SEPARATOR+"cdef");
fw.close();
}


2.续写

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

在原来的demo.txt文件后面续写内容

(2)异常的处理

FileWriter fw = null;
try {
fw = new FileWriter("x:/Demo.txt");//可能没有x盘
fw.write("haha");	//写入失败
} catch (IOException e) {
System.out.println(e.toString());
}finally{
try {
if(fw!=null)  //因为路径错误,fw就创建不出来,就会出现空指针异常
fw.close();
} catch (IOException e) {
throw new RuntimeException("关闭失败");
}
}



(2)需求2:读取文本文件

注意:使用Reader体系,读取一个文本文件中的数据。返回 -1 ,标志读到结尾。

读取方式一:demo.txt文件的内容是 ab,每次读一个

FileReader fr = new FileReader("demo.txt");
int ch=0;
while((ch=fr.read())!=-1)
System.out.println((char)ch);
读取方式二:用字符数组
FileReader fr = new FileReader("demo.txt");
char[] buf = new char[1024];
int len = 0;
while((len = fr.read(buf))!=-1){
System.out.println(new String(buf,0,len));
}


(3)需求3:复制文本文件

方式一:

FileReader fr = new FileReader("Io_test.txt");
FileWriter fw = new FileWriter("Io_test1.txt");
int len = 0;
while((len = fr.read())!=-1){
fw.write(len);
}
fw.close();
fr.close();


方式二:

FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader("Io_test.txt");
fw = new FileWriter("Io_test2.txt");
char[] buf = new char[1024];
int len = 0;
while((len = fr.read(buf))!=-1){
fw.write(buf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(fr!=null)
try{fr.close();}
catch(IOException e){
throw new RuntimeException("关闭失败");
}
if(fw!=null)
try{fw.close();}
catch(IOException e){
throw new RuntimeException("关闭失败");
}
}


(4)需求4:高效的复制--------用字符流缓冲区

字符流缓冲区:

BufferedWriter

-----newLine()方法:写一行换一行

BufferedReader

-----readLine()方法:读一行换一行

复制文本文件:

FileReader fr = new FileReader("Buffered.txt");
BufferedReader bufr = new BufferedReader(fr);
FileWriter fw = new FileWriter("copy_Buffered.txt");
BufferedWriter bufw = new BufferedWriter(fw);
String line = null;
while((line = bufr.readLine())!=null){
bufw.write(line);
bufw.newLine();
bufw.flush();
}
bufw.close();
bufr.close();


(5)装饰设计模式

含义:就是对已有的对象的功能进行增强

例子:

class Person{
void chifan(){
System.out.println("吃饭");
}
}
class NewPerson{ //为了不改变源代码,并且增强Person,这个类就出现了
private Person p;
NewPerson(Person p){
this.p = p;
}
void chifan(){
System.out.println("喝点红酒");
p.chifan();
System.out.println("吃点甜点");
}
}


装饰和继承的区别:

相同点:

都能进行功能的扩展增强

不同点:

装饰更灵活,而继承如果体系多了,会显得比较臃肿。

比如说:

有一个体系:

Writer

|--TextWriter:用于操作文本

|--MediaWriter:用于操作媒体。

想要对操作的动作进行效率的提高

此时的体系就变为:

Writer

|--TextWriter:用于操作文本

|--BufferTextWriter:加入了缓冲技术的操作文本的对象。

|--MediaWriter:用于操作媒体。

|--BufferMediaWriter:加入了缓冲技术的操作媒体的对象。

如果这个体系还要进行功能的扩展,又多了流对象,那么这个流要提高效率,也要产生子类,这时就会发现只为提高功能,进行的继承,导致继承体系越来越臃肿。不够灵活。

而用装饰:

class BufferWriter extends Writer

{

BufferWriter(TextWriter text)

{}

BufferWriter(MedianWriter media)

{}

}

// 上面这个类扩展性很差。

// 找到其参数的共同类型,通过多态的形式,可以提高扩展性。例如:

class BufferWriter extends Writer

{

private Writer r;

BufferWriter(Writer r)

{}

}

Writer

|--TextWriter:用于操作文本

|--MediaWriter:用于操作媒体。

|--BufferWriter:用于提高效率。

三、字节流

需求1:复制Mp3

方法1:

FileInputStream fis = new FileInputStream("0.mp3");
FileOutputStream fos = new FileOutputStream("2.mp3");
byte[] buf = new byte[1024];
int len=0;
while((len=fis.read(buf))!=-1){
fos.write(buf,0,len);
fos.flush();
}
fis.close();
fos.close();


方法2:

BufferedInputStream buis = new BufferedInputStream(new FileInputStream("0.mp3"));
BufferedOutputStream buos = new BufferedOutputStream(new	 FileOutputStream("5.mp3"));
int ch = 0;
while((ch=buis.read())!=-1){
buos.write(ch);
buos.flush();
}
buis.close();
buos.close();


需求2:复制一个文本文件

BufferedReader bufr = new BufferedReader(new FileReader("键盘录入.txt"));
BufferedWriter bufw = new BufferedWriter(new FileWriter("键盘录入1.txt"));
String line = null;
while((line = bufr.readLine())!=null){
if("over".equals(line))
break;
bufw.write(line);
bufw.newLine();
bufw.flush();
}
bufr.close();
bufw.close();


需求3:将键盘录入信息,并写入到一个文件中

BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new FileWriter("键盘录入.txt"));
String line = null;
while ((line = bufr.readLine()) != null) {
if ("over".equals(line))
break;
bufw.write(line);
bufw.newLine();
bufw.flush();
}
bufr.close();
bufw.close();


需求4:将一个文本的内容显示在控制台上

BufferedReader bufr = new BufferedReader(new FileReader("键盘录入.txt"));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line = bufr.readLine())!=null){
if("over".equals(line))
break;
bufw.write(line);
bufw.newLine();
bufw.flush();
}
bufr.close();                                                                                                                                                                                                                 bufw.close();


需求5:将键盘录入的信息显示在控制台上

BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line=bufr.readLine())!=null){
if ("over".equals(line))
break;
bufw.write(line);
bufw.newLine();
bufw.flush();
}
bufr.close();
bufw.close();


四、流的操作规律

1,明确源和目的(汇)

源:InputStream Reader

目的:OutputStream Writer

2,明确数据是否是纯文本数据。

源:是纯文本:Reader

否:InputStream

目的:是纯文本 Writer

否:OutputStream

3,明确具体的设备。

源设备:

硬盘:File

键盘:System.in

内存:数组

网络:Socket流

目的设备:

硬盘:File

控制台:System.out

内存:数组

网络:Socket流

4,是否需要其他额外功能。

1,是否需要高效(缓冲区);

是,就加上buffer.

2,转换。

五、转换流的编码解码

发现转换流有一个子类就是操作文件的字符流对象:

InputStreamReader

|--FileReader

OutputStreamWriter

|--FileWrier

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(

"gbk_3.txt"), "GBK");

// FileWriter fw = new FileWriter("gbk_1.txt");

/*

* 这两句代码的功能是等同的。 FileWriter:其实就是转换流指定了本机默认码表(简体中文版的系统默认码表是GBK)的体现。而且这个转换流的子类对象,可以方便操作文本文件。

* 简单说:操作文件的字节流+本机默认的编码表。 这是按照默认码表来操作文件的便捷类。

* 如果操作文本文件需要明确具体的编码。FileWriter就不行了。必须用转换流。

*/

osw.write("你好");

osw.close();

如果需要制定码表,必须用转换流。

转换流 = 字节流+编码表。

转换流的子类File = 字节流 + 默认编码表。

凡是操作设备上的文本数据,涉及编码转换,必须使用转换流。

------Java培训Android培训iOS培训.Net培训、期待与您交流!-------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: