Quantcast
Channel: CSDN博客推荐文章
Viewing all articles
Browse latest Browse all 35570

黑马程序员_day23_流的操作

$
0
0

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

一、装饰设计模式

装饰设计模式。

解决的问题:给已有的对象提供增强额外的功能。还不用对原有对象进行修改。 

比继承更为灵活。

 Writer

|--TextWriter

|--MediaWriter

现有一个体系用于各种数据的写入。

但是,发现写入效率有点低。想要对其进行效率的提高。

可以使用缓冲技术来完成的。

已有对象中的写入方法,不够高效,可以通过派生子类的形式对其进行复写,定义高效的写入动作。

 Writer

|--TextWriter

|--BufferTextWriter

  |--MediaWriter

|--BufferMediaWriter

|--DataWriter

|--BufferDataWriter

通过继承的方式提高了效率。

但是对于扩展性是一个问题。而且所需的功能越多,子类就越多。

如何解决这个问题呢?优化!

既然都需要缓冲,对数据写入效率进行提高 。

可以转变一下思想,这样来做,将缓冲技术单独进行封装。

哪个对象需要缓冲,就把哪个对象传递给缓冲对象即可。 

 class Buffer{

Buffer(TextWriter w){

}

Buffer(MediaWriter w){

}

}

 体系就变成了这样:

 Writer

|--TextWriter

  |--MediaWriter

  |--BufferWriter

BufferWriter的出现,增强了Writer体系中的功能。

这种设计方式比原理更为灵活,避免了继承的臃肿。

将这样解决方式就定义了一个名称方便于后人使用:装饰设计模式。

记住:装饰类和被装饰类都所属于同一个体系。 

 二、行号装饰类

public static void main(String[] args) throws IOException {

FileReader fr = new FileReader("tempfile\\demo.java");

LineNumberReader lnr = new LineNumberReader(fr);

String line = null;

lnr.setLineNumber(100);

while((line=lnr.readLine())!=null){

System.out.println(lnr.getLineNumber()+":"+line);

}

lnr.close();

}

三、字符流:

FileReader

FileWriter

BufferedReader

BuffereWriter

字节流。

InputStream  OutputStream

FileInputStream FileOutputStream

BufferedInputStream BufferedOutputStream

转换流:

字节流--->字符流的桥梁。InputStreamReader 

字符流--->字节流的桥梁。OutputStreamWriter

public static void main(String[] args) throws IOException {

需求:将一个字符串写入一个文件中。使用FileOutputStream来演示。

FileOutputStream fos = new FileOutputStream("tempfile\\fos.txt");

fos.write("abcdef".getBytes());//字节流的直接操作文件写入时,直接将数据写入到目的地。

为啥FileWriter就需要刷呢?

那是因为FileWriter底层使用了字节流在操作字符数据时,会先将这些数据进行临时存储,并查指定的编码表。按照指定的编码表中的内容写入到目的地。

"你好"FileWriter ---> 编码表 GBK--->数字字节--->目的地。

而字节流处理的数据不一定都是文字数据,所以是不需要指定查表的。 

直接在操作文件数据时,就将具体的字节数据写入到目的地。

fos.flush();使用的是父类OutputStreamflush。该方法什么都没有做,只有OutputStram某一些子类定义了该方法的具体内容。 

fos.close();//必须有,因为要关闭资源。

}

需求:读取一个文件。用字节流。

int ch = fis.read();

System.out.println("ch="+ch);

//一次读一个,打一个。

int ch = 0;

while((ch=fis.read())!=-1){

System.out.println((char)ch);

}

//读取并存储到数组,将数组打印。以该种方式。

byte[] buf = new byte[1024];

int len = 0;

while((len=fis.read(buf))!=-1){

System.out.println(new String(buf,0,len));

}

//直接创建一个刚刚好的大小的数组缓冲区。

byte[] buf = new byte[fis.available()];//如果文件过大,内存溢出,bang 一声!慎用!//

fis.read(buf);//将数据存储到刚刚好的数组中。

System.out.println(new String(buf));

fis.read();

System.out.println(fis.available());//获取流关联的文件的字节数。

fis.close();

四、复制mp3

1自定义数组缓冲区的方式。 

public static void copy_1() throws IOException {

//1,读取流对象,和mp3关联。

FileInputStream fis = new FileInputStream("C:\\0.mp3");

//2,写入流对象,明确存储mp3数据的目的。

FileOutputStream fos = new FileOutputStream("c:\\1.mp3");

//3,定义一个字节缓冲区。

byte[] buf = new byte[1024*8];

int len = 0;

while((len=fis.read(buf))!=-1){

fos.write(buf,0,len);

}

fos.close();

fis.close();

}

2不建议。使用刚刚好的缓冲区。因为文件过大会溢出。

public static void copy_3() throws IOException {

FileInputStream fis = new FileInputStream("C:\\0.mp3");

FileOutputStream fos = new FileOutputStream("c:\\3.mp3");

byte[] buf = new byte[fis.available()];

fis.read(buf);

fos.write(buf);

fos.close();

fis.close();

}

3使用字节流已有的缓冲区。 

public static void copy_2() throws IOException {

FileInputStream fis = new FileInputStream("C:\\0.mp3");

FileOutputStream fos = new FileOutputStream("c:\\2.mp3");

BufferedInputStream bufis = new BufferedInputStream(fis);

BufferedOutputStream bufos = new BufferedOutputStream(fos);

int by = 0;

while((by=bufis.read())!=-1){

bufos.write(by);

}

bufos.close();

bufis.close();

}

4读一个 写一个

public static void copy_4() throws IOException {

FileInputStream fis = new FileInputStream("C:\\0.mp3");

FileOutputStream fos = new FileOutputStream("c:\\4.mp3");

int by = 0;

while((by=fis.read())!=-1){

fos.write(by);

}

fos.close();

fis.close();

五、键盘录入

读取键盘录入。 

public static void readKey() throws IOException{

//获取到读取键盘录入的流对象。类型是InputStream

InputStream in = System.in;

//用流读取数据。如果没有数据录入,那么控制台会一致等待输入。read方法就是一个阻塞式的方式。 

int ch = in.read();

System.out.println("ch="+ch);

int ch1 = in.read();

System.out.println("ch1="+ch1);

int ch2 = in.read();

System.out.println("ch2="+ch2);

in.close();//不需要关闭。 

//注意:系统中获取的流对象都是唯一的,如果将其关闭,就不能在使用了。

//想要在使用只有重新再次运行这个程序才可以。 

//所以一般情况下,从System获取到的流对象,一般不需要关闭。随着程序的停止而结束。 

// InputStream in2 = System.in;这里会出错 。

// int ch4 = in2.read();

// System.out.println("ch4="+ch4);

六、键盘录入练习

 需求:读取键盘录入的数据,将这些数据转成大写打印在屏幕上,

如果录入的是 over, 程序结束。 

 思路:

1,通过键盘录入读取字节数据。

2,将这些读到的字节数据进行存储以变成字符串。

3,对这个字符串进行判断。如果不是over就将其转成大写打印。如果是over就结束。 

public static void readKey2() throws IOException {

//1,获取键盘录入流对象。 

InputStream in = System.in;

//2,定义一个容器用于存储读取到的字节。

StringBuilder sb = new StringBuilder();

//3,循环读取键盘。

int ch = 0;

while((ch=in.read())!=-1){

//需要对读取到的字节进行判断。

//如果是/r 或者 /n,不存储,并视为一次录入内容结束符。对之前的录入数据进行判断。

if(ch=='\r')

continue;

if(ch=='\n'){

String s = sb.toString();

if("over".equals(s)){//记住:如果要使用键盘录入,一定要自定义结束标记。

break;

}

else{

System.out.println(s.toUpperCase());

//清空缓冲区。 

sb.delete(0, sb.length());

}

}

else

sb.append((char)ch);

}

}

七、转换流 

既然键盘录入转成大写输出,并判断over结束的程序中

使用了到对字节数据的存储,并对回车符进行判断。

 发现这个功能和readLine方法一致。

因为readLine是字符流BufferedReader对象中过的方法。

而键盘录入是字节流。

能不能将这个字节读取流转成字符流呢?因为BufferedReader只能对字符流进行装饰 。

这就用到了转换流

转换流:

字节流--->字符流的桥梁。InputStreamReader 

字符流--->字节流的桥梁。OutputStreamWriter

从键盘读取数据,转成大写,显示在屏幕上。 

获取键盘录入,数据源。

InputStream in = System.in;

为了处理文字数据方便。将字节数据转成字符数据.这个功能在转换流中。InputStreamReader

InputStreamReader isr = new InputStreamReader(in);

//为了提高了读取的效率。使用缓冲区。 

BufferedReader bufr = new BufferedReader(isr);

//打印到显示器上。目的。

OutputStream out = System.out;

//因为要打印到显示器上的数据都是文字数据。所以必须将这些文字数据转成字节数据。

//具备这个功能的对象是OutputStreamWriter.

OutputStreamWriter osw = new OutputStreamWriter(out);

//为了提高写入的效率。

BufferedWriter bufw = new BufferedWriter(osw);

//频繁的读写操作。 

String line = null;

while((line=bufr.readLine())!=null){

if("over".equals(line))

break;

bufw.write(line.toUpperCase());

bufw.newLine();//newLine()需要有BufferedWriter对象

bufw.flush();

}

//因为是从System获取的流可以不关闭,随着系统的结束而结束。

bufw.close();

bufr.close();

}

八、流的操作规律:

规律就是四个明确?

1,明确源和目的。

源:InputStream   Reader 一定是被读取的。

目的:OutputStream  Writer 一定是被写入的。 

2,处理的数据是否是纯文本的数据?

是:使用字符流。Reader Writer

否:使用字节流。 InputStream OutputStream

如果是源并且是纯文本,Reader

如果是目的并且是纯文本,Writer

到这里,两个明确确定完,就可以确定出要使用哪个体系。

接下来,就应该明确具体这个体系要使用哪个具体的对象。

3,明确数据所在的设备:

源设备:

键盘(System.in)

硬盘(FileXXX)

内存(数组)

网络(Socket)

目的设备:

显示器(控制台System.out)

硬盘(FileXXX)

内存(数组)

网络(Socket)

具体使用哪个对象就可以明确了。

4,明确是否需要额外功能?

1,是否需要高效?缓冲区Buffered

2,是否需要转换?转换流

后面会学到更多。

九、需求练习

需求1:复制一个文本文件。

直接明确具体对象并创建。

FileReader fr = new FileReader("a.txt");

FileWriter fw = new FileWriter("b.txt");

然后是频繁的读写操作。

需要额外功能吗?

需要,高效。 使用缓冲区。

BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));

BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));

需求3:读取键盘录入,存储到一个文件中。

明确是否是纯文本?一般键盘录入的都是文字,所以是纯文本的。 

InputStream in = System.in;

FileWriter fw = new FileWriter("a.txt");

需要将键盘录入的字节转成字符。

使用转换流。而且是 将字节-->字符的转换流对象。InputStreamReader

InputStreamReader isr = new InputStreamReader(System.in);

FileWriter fw = new FileWriter("a.txt");

需要,高效。

BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

BufferedWriter bufw = new BufferedWriter(new FileWriter("a.txt"));

需求4:读取一个文本文件,显示到显示器上。

FileReader fr = new FileReader("a.txt");

OutputStream out = System.out;

需要将已有的字符数据转成字节。字符-->字节的桥梁 OutputStreamWriter

FileReader fr = new FileReader("a.txt");

OutputStreamWriter osw = new OutputStreamWriter(System.out);

需要高效。

BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));

BufferedWriter bufw = new BufferedWriter(new OutputStreamWrier(System.out));

需求5:读取一个文本文件,将文件中文本按照指定的编码表UTF-8写入到另一个文件中。

FileReader fr = new FileReader("a.txt");

FileWriter fw = new FileWriter("b.txt");

这样做不行,满足不了需求,为什么呢?

因为这个两个对象在操作文本数据,都是用了默认的编码表。在我的本机中默认码表是GBK.而需求中希望写入到文件的数据是按照utf-8的码表。其实这两个对象就是字节流+默认编码表。 

源对象不变。

FileReader fr = new FileReader("a.txt");

需要目的为指定编码表。

这时就要用到转换流。因为转换流中可以指定具体的编码表。 需要往里传递一个字节流,而且要操作文件,FileOutputStream

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"),"UTF-8");

需要高效

BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));

BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("b.txt"),"UTF-8"));

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------


作者:huasen1990 发表于2013-4-10 1:08:11 原文链接
阅读:117 评论:0 查看评论

Viewing all articles
Browse latest Browse all 35570

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>