黑马程序员-IO流

IO概述

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

java用于操作流的对象都在IO包中。

流按操作数据分为两种:字节流与字符流

流按流向分为:输入流和输出流

字符流对象中融合了编码表。只有文字涉及到编码

字节流的抽象基类:

inputStream,OutputStream

字符流的抽象基类:

Reader Writer

Writer 方法:

write(String str)   
写入字符串。

write(int
c)        写入单个字符。

write(String str, int off, int len)

写入字符串的某一部分。

write(char[] cbuf)

写入字符数组。

write(char[] cbuf, int off, int len)
//从off开始,len表示要写入的个数。

flush()   刷新该流的缓冲。

先学习下字符流的特点:

既然IO流是用于操作数据的,那么数据最常见的体现形式:文件。

Reader:数据的读取,要么读字节,要么读字符, 要么读取字节。没有读取字符串什么的东东。

BufferedReader, CharArrayReader,
FilterReader, InputStreamReader, PipedReader, StringReader

read(char[])方法:

‘1234567‘ ,char[3]
read(char[]),第一次读取缓冲区内容[123],第二次[456],

第三次[756],但是我们第三次取的时候只能取7,5和6没有被取代

FileReader:

FileWriter(String fileName, boolean
append) :对已有文件的续写,boolean判断是否续写。

字符流缓冲区  缓冲区作用:提高效率(里面封装了数组)

|--提高了对数据的读写效率

|--对应类:

BufferWriter

BufferReader

|--缓冲区要结合流才可以使用

|--在流的基础上对流的功能进行了加强

装饰设计模式:

当要对自己已有的对象进行增强时,可以定义类,

将已有对象传入,基于已有的功能,并提供增强功能。

那么该自定义类称为装饰类。

装饰类通常会通过构造方法接受被装饰的对象。

并基于被装饰的对象的功能,提供更强的功能。

装饰类的由来

应用:去年的功能,要增强,用装饰设计,既可以用增强的方法,也可以用以前的方法

通过多态的形式,提高扩展性

class buffered extends myReader{//该类只是增强版,但仍然是myReader的子类或者接口

buffered(myReader,my){//将其父类传入

}

}

MyReader//专门用于读取数据

|-MyTextReader

|-MyMediaReader

|-MyDataReader

|-MyBufferedReader

装饰模式比继承模式灵活,避免了继承体系的臃肿。为了几个方法而去继承降低了类与类之间的关系。

装饰类:对已有的类进行增强 将已有的类传入,定义需要的增强的方法。然后再使用装饰类就可以使用该增强的方法了。

装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能所以装饰类和被装饰类通常都属于一个体系中,从继承结构变成了组合结构(我里面有你)。

BufferedReade类中特有方法readLine,做一个自定义myReadLine

思路;

1.定义一个my类

2.定义一个myreadline方法

3.定义一个myclose方法

ps;父类有抽象方法,子类不覆盖无法new对象

import java.io.*;

class lianxi{

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

myBufferedReader mybu = new myBufferedReader(new FileReader("fi.txt"));

String line = null;

while ((line=mybu.myReadLine())!=null){

System.out.println(line);

}

mybu.myclose();

}

}

class myBufferedReader{

private FileReader fr ;

myBufferedReader(FileReader fr) throws
Exception{

this.fr= fr;

}

public String myReadLine() throws
Exception{

StringBuilder sb = new StringBuilder();

int ch = 0;

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

if
(ch==‘\r‘){//ch不用强转,因为换行字符也被转成了int型\r=13,\n=10

continue;

}

if(ch==‘\n‘)

return sb.toString();

else

sb.append((char)ch);

}

if (sb.length()!=0)

return sb.toString();//有条件的return 不能算吧!

return null;

}

//覆盖抽象方法

public void myclose() throws
Exception{

fr.close();

}

public void read(char[] cbuf, int off,
int len){

//直接返回其子类(调用本方法的对象)

return fr.read(cbuf, off, len)

}

}

lineNumberReader BufferedReader的子类:跟踪行号

int   getLineNumber();获取当前行号

void setLineNumber(int lineNumber)

自定义字节流InputStream缓冲区

思路:定义read方法,使用数组,返回低八位

1.抓一票数据放在byte数组中,并且返回数组的长度count

2.从数组取出来,定义指针pos,到结尾后从零位再重新来

3.count-- 等于零,在抓一票

class myBufferedInputStream{

private InputStream in;

int count =0 ;

int pos=0;

byte[] by = new byte[1024];

myBufferedInputStream(InputStream in)
throws Exception{

this.in=in;

}

public void myclose() throws
Exception{

in.close();

}

public int myread()throws Exception{

if
(count==0){//count=0,表示数组取完

pos=0;

//一次读一个字节,从缓冲区(字节数组)获取,这个数组封装在bufferedReader内部

count =in.read(by);//将流存入1024的数组中

byte b = by[pos];//取出一个字节

count--;

pos++;

return b&255;//返回调用者读取的一个字符。

}

if
(count>0){//第二次调用read(),count=1023

byte b =by[pos];

pos++;

count--;

return b&255;

}

if (count<0){

return -1;

}

return -1;

}

}

在读取二进制的时候,可能会读到11111111 ,-1字节。但是read方法返回的是int型。所以会进行类型提升。

为防止-1与我们的结束标记相同,导致读取失败。会在提升为int型是,将高24位全部补零,即%255.

键盘录入:最常见写法

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

它与System.in的区别,前者转成了【字符流】,可以直接读取一行,

而后者是inputStream流只能读一个【字节】

读取键盘录入

System.in:对应标准输入设备:键盘

System.out.:对应标准输出设备,控制台

转换流:

InputStreamReader:字节流转字符流,读取的时候按【字符流】读取。用字符更方便的读取

InputStreamReader(【InputStream】
in)

创建一个使用默认字符集的 InputStreamReader。

OutputStreamWtriter:【注意这个还得flush】为什么要转?

本身仍是字符流。但是存储的时候一字节的形式存储

OutputStreamWriter(OutputStream out)

创建使用默认字符编码的 OutputStreamWriter。

转换流:真正的应用:使用指定的码表进行读取和存储。  

* 1.InputStreamReader(InputStream
in, Charset cs)

*
2.OutputStreamWriter(OutputStream out, Charset cs)

记住;转换流什么时候使用,通常,涉及到字符编码转换的时候。

字符串默认:GBK

InputStreamReader的子类FileReader:使用默认编码表,当使用其他的编码表

就只能使用父类来制定码表。
区别:

1,

转换流:字节流+编码表

转换流的子类:FileReader&FileWriter:字节流+本地默认码表(GBK)。

2,

转换流可以指定任意码表。

而转换流子类需要构造一个其父类的对象有字节和字符。

PrintWriter在什么情况下可以自动刷新?

构造函数中,如果参数是输出流,那么可以通过指定另一个参数true完成自动刷新,该true对println方法有效。

PrintWriter对象的println自动刷新图

注意,自动刷新功能只对字节流对象和字符流对象有效。

字节流为什么不用刷新?

字符流需要刷新是因为,例如一个字节,因为一个汉字有两个字节,读完一个字节

要临时存起来,而字节流不需要缓冲,可以直接将字节输出。因为是对字节最小单位操作

实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,

而字符流在操作时使用了缓冲区,通过缓冲区再操作文件

什么叫缓冲区:简单理解为一段内存区域。

某些情况下,如果一个程序频繁地操作一个资源(如文件或数据库),则性能会很低,

此时为了提升性能,就可以将一部分数据暂时读入到内存的一块区域之中,

以后直接从此区域中读取数据即可,因为读取内存速度会比较快,这样可以提升程序的性能。

在字符流的操作中,所有的字符都是在内存中形成的,在输出前会将所有的内容暂时保存在内存之中,

所以使用了缓冲区暂存数据。例如一个汉字,又两个字符组成,必须读完两个字节之后,才能去查表,

找出对应的汉字,所以第一个字节就要先存放在内存中(缓存)。

而字节流,获取一个字节就可以查表,然后存到指定的地方。

OutputStream 特有方法:

int available()  ;返回流中(即关联文件的字节数)的字节数,包括换行。

用于定义刚刚好的缓冲区的长度  byte[] chs = new byte[is.available()];

有局限,慎用,还是定义1024的整数倍最好。虚拟机内存。

BufferedOutputStream

该类通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。

缓冲区原理:通过底层流对象,将数据存到内存的数组中(如:存了[1024]),然后再从内存中取。

如果没有缓冲,则每次调用 read() 或 readLine() 都会导致从文件中读取字节,

并将其转换为字符后返回,而这是极其低效的。

流操作的基本规律:

明确三个完成。

1.明确源和目的。

源:输入流。Reader InputStream

目的:输出流。Writer OutputStream

2.明确,操作的数据是否是纯文本。

是:字节流

否:字符流

3.体系明确后,明确使用哪个具体对象

通过设备进行区分:

源设备:内存,硬盘,键盘

目的设备:内存,键盘,控制台。

4. 
  明确需要额外功能吗?如指定编码表,高效等.

实例:1.将一个文本文件数据存储到另一个文件中。复制文件分析;

(1):从哪来来

源:       因为是源,使用输入流。

是否是纯文本:是选择;reader,体系明确

设备:    源设备:硬盘上的文件,使用FileReader

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

是否需要提高效率:是,加入BufferedReader

..........

(2):到哪儿去

目的: 因为是目的,使用输出流。

是否是纯文本:是,writer

设备:硬盘,一个文件。FileWriter

FileWriter fr = new FileWriter("b.TXT");

是否需要提高效率:是,加入BufferedWriter

练习:异常日志的信息 建立异常日志文件

如何将异常信息存到文件中:

throwble类的方法
(包括erro和exception

void
printStackTrace(PrintStream s)

将此 throwable 及其追踪输出到指定的输出流。

Reader:

--|int read():返回要读取的字符,以Int型表示

--|int read(char[] ch):返回的字符数量

InputStream:

--|read();下一个数据字节;如果到达流的末尾,则返回 -1。

Writer:

--|write(int),
writr(char[]),write(String )返回值是:void,可写入String,要刷新

--|写入单个字符。要写入低16位。

OutputStream :

--|wirte(byte[]),返回值是:void,无法写入字符串,可用String.getBytes(),不需要flush()

--|write(int)
 写入字节,即低八位

BufferedInputStream:

--|

BufferedReader:

--|eadLine()  读取一个文本行。

BufferedOutputStream:

--|write(),write(char[])没有返回值

BufferedWriter:

--|newLine()  写入一个行分隔符。跨平台

时间: 2024-08-09 22:02:43

黑马程序员-IO流的相关文章

黑马程序员 IO流 文件的分割与合并

---------------------- ASP.Net+Unity开发..Net培训.期待与您交流! ----------------------package cn.itcast.IO; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;

黑马程序员——IO流总结

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 什么是IO流? IO流是用来处理设备之间的数据传输 有哪些流? 流按操作数据的种类分为:字符流和字节流 流按流的方向分:输入流和输出流 字节流的基类:InputStream和OutputStream 字符流的基类:Writer和Reader 常用写字符流:FileWriter,BufferedWriter,OutputStreamWriter,PrinterWriter 常用读字符流  : F

黑马程序员-IO流其他流与File类

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- 1:其他的流 1: DataOutputStream ;多了一些操作基本数据类型的功能 DataInputStream:读取文件. 用DataOutputStream流写进去的数据,就用DataInputStream流来读取. 1 imp

黑马程序员——IO流

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- IO流 IO流概述 IO流用来处理设备之间的数据传输.Java对数据的操作是通过流的方式.Java用于操作流的对象都在IO包中. 流按照流向分为两种:输入流和输出流. 输入流和输出流相对于内存设备而言.将外设中的数据读取到内存中:输入.将内存的数写入到外设中:输出. 流按照操作数据分为两种:字节流和字符流. 字节流读取文字字节数据后,不直接操作而是先查指定的编码表,获取对应的文字.再对这个文字

黑马程序员 - IO流(上)

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- IO流用于处理设备间的数据传输按操作数据分:字节流和字符流按流向分:输入流和输出流IO流常用基类:字节流的抽象基类:InputStream OutputStream字节流的抽象基类:Reader Writer注意:这4个类派生出的子类名称均以其父类名作为子类名的后缀.数据的最常见体现形式是:文件下面代码演示常用的写入,读取操作. import java.io.*; class FWDemo{

黑马程序员——IO流概述、字符流、字节流、流操作规律(一)

第一节     IO概述 概述 1.IO流:即InputOutput的缩写. 2.特点: 1)IO流用来处理设备间的数据传输. 2)Java对数据的操作是通过流的方式. 3)Java用于操作流的对象都在IO包中. 4)流按其操作数据的类型分为两种:字节流和字符流. 5)流按其流向分为:输入流和输出流. 注意:流只能操作数据,而不能操作文件. 3.IO流的常用基类: 1)字节流的抽象基流:InputStream和OutputStream 2)字符流的抽象基流:Reader和Writer 注:此四个

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

package IO; import java.io.FileWriter; /*IO(Inout Output)流 * Io流用来处理设备之间的数据传输 * Java对数据的操作是通过流的方式 * Java用于操作流的对象都在Io包中 * 流按操作数据分为两种:字节流与字符流 * 流按流向分为:输入流,输出流 * * IO流常用基类 * 字节流的抽象基类 * InputStream OutputStream * 字符流的抽象基类 * Reader Writer * 由这四个类派生出来的子类的名

黑马程序员 - IO流(下)

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 用于操作字节数组的流对象ByteArrayInputStream:在构造的时候需要接收数据源,而且数据源是一个字节数组.ByteArrayOutputStream: 在构造时,不用定义数据目的地, 因为该对象中已经封装流一个可变长度的字节数组,该数组就为数据目的地.因为这两个流对象都操作的数组,并没有使用系统资源,所以不用进行close关闭,而且其不会产生IO异常.这种方法是用流的思想操作数组

黑马程序员—IO流综合练习

有5个学生有3门课的成绩,从键盘输入以上数据(包括学生姓名和三门课的成绩),输入的格式为zhangsan,30,40,50, 计算出总成绩,并把学生的信息和计算出的总分数按有高到低的顺序存放在磁盘文件a.txt中. 分析: 1.描述学生对象 2.定义一个可操作学生对象的工具类 思路: 1.通过获取键盘录入一行数据,并将该行中的数据取出封装成学生对象. 2.因为学生对象有很多,那么久需要存储,使用到集合. 又因为要对学生的总分进行排序,所以要使用TreeSet. 3.将集合中的信息写入到一个文件中