黑马程序员_java之IO流
IO流
IO流处理设备之间的数据传输,Java对数据的操作是通过流的方式,Java用于操作流的对象都在IO包中。
按操作数据分为:字节流、字符流;按流向分为:输入流、输出流。字符流融合了编码表。
字节流抽象基类:InputStream、OutputStream.;字符流抽象基类: Writer、Reader。
字符流读写操作:
子类名称都是以其父类作为子类名的后缀,流创建文件时,如文件已存在,则会覆盖该文件;想对已有文本文件续写,则可在FileWriter传递一个true参数,不覆盖已有文件,在文件末尾进行数据续写。flush和close区别:filush刷新流对象中缓冲中的数据,可继续使用;close刷新后关闭流资源。void write(char[] cbuf); void write(String str);void write(String str, int off, int len) ;abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。void write(int c)写入单个字符。
凡是和设备数据发生数据关系的都有IO异常。
处理IO异常范例:fileWriter fw=null;
try{
Fw=new FileWriter(“a.txt”);
Fw.write(“abc”);
}
Catch(IOException e){ //异常处理e.toString() ,}
fnally{
try{
If (fw!=null){ Fw.close();}
}
Catch(IOException e){//异常处理 }
}
字符流读取数据有3种操作。
读取方法:int read() 读取单个字符;int read(char[] cbuf) 将字符读入数组,读取的字符数; abstract int read(char[] cbuf, int off, int len)
分别简写为 1、不需要缓冲区 int ch =0; while ((ch=fis.read())!=-1){Sop((char)ch)} fis.close();
2、用数组做缓冲区char [] buf=new char [1024];int len =0; while((len =fis.read(buf))!=-1){ Sop(new String(buf,0,len);}fis.close();
注:若文件里有abcdefg 7个字符,缓冲区长度为3,则若不用循环,read(buf)四次,并打印数组Sop(new String(buf),则结果为abc,def,gef,gef,其中len结果为3,3,1,-1
3、用BufferedReader: BufferedReader bufr=new BufferedReader(fr); String line=null;while((line=bufr.readLine())!=null){ Sop(line);} bufr.close();
缓冲区的出现提高了数据的读写效率,要结合流才可使用(创建一个流对象和文件相关联),在流的基础上对流的功能进行增强;
缓冲原理是对象里面封装了数组。字符流缓冲区对应的类:BufferedWriter、BufferedReader.字节流缓冲区对应的类:BufferedInputStream、BufferedOutputStream.。
BufferedWriter 特有void newLine() 写入一个行分隔符;BufferedReader特有方法String readLine()读取一个文本行。只返回回车符之前的数据内容,不返回回车符;
readLine()原理:read方法一次读一个方法,对象里面封装了数组,为了方便,定义StringBuilder容器
public String myReaderLine() throws IOException{//标识异常,谁调用谁处理
StringBuilder sb=new StringBuilder();
int ch=0;
while((ch=fr.read())!=-1){
if(ch=='\r')
continue;
if(ch=='\n')
return sb.toString();
else
sb.append((char)ch);
}
if(sb.length()!=0)
return sb.toString();
return null;
}
public void myClose() throws IOException{
fr.close();
}
注:其实关闭缓冲区就是关闭缓冲区中流对象
装饰设计模式:想要对已有得对象进行功能增强时,可以定义类,将已有得对象传入,基于已有的功能,并提供加强功能,那么自定义的类称为装饰类。装饰类通常通过构造方法接收被装饰的对象。
装饰模式和继承区别:装饰比继承灵活,避免继承体系臃肿,且降低类与类之间的关系;装饰类因为增强已有功能,所以装饰类和被装饰类通常都是属于一个体系
小知识点:跟踪行号的缓冲字符输入流LineNumberReader是BufferedReader子类,其中setLineNumber设置行号,gerLineNumber得到行号。
字节流读写操作:
字节流:InputStream OutputStream
OutputStream 写入方法:void write(byte[] b) void write(byte[] b, int off, int len) abstract void write(int b),要写字符串则str.getBytes()
InputStream 读方法 abstract int read() ;int read(byte[] b) ;int read(byte[] b, int off, int len)
写的时候不需要刷新fos.write(“abd”.getBytes),字符流底层用的是字节流缓冲区,字符流有个临时存储数据的数组,所以需要刷新,字节没使用指定缓冲区,故不需要刷新。
读有三种操作。分别简写为 1、不需要缓冲区 int ch =0; while((ch=fis.read())!=-1){ Sop((char)ch);}fis.close();
2、一般用法 byte[] buf=new byte [1024];int len =0; while((len =fis.read(buf))!=-1){Sop(new String(buf,0,len);}fis.close();
3、不常用法 byte [] buf=new byte [fis.available()];//定义一个刚好的数组 fis.read(buf); Sop(new String(buf);fis.close();
注:txt文件里有abcqq回车z则available为8个
字节流缓冲简单实例:
Pubic static void copy () throwsTOException{
BufferedInputStream bufis =new BufferedInputStream(new FileInputStream(“c:\\a.mp3”);
BufferedOutputStream bufos =new BufferedOutputStream (new FileOutputStream(“c:\\b.mp3”);
int by=0;
while((by=bufis.read())!=-1){
bufos.write(by);
}
bufos.colse();
bufis.close();
}
自定义字节流的缓冲区 read和write特点
Class MyBufferedInputStream
{
Private InputStream in;
Private byte []=new byte[1024];
Private int pos=0,count=0;
MyBufferedInputStream (InputStream in){
This.in=in;}
Public void myClose() throws IOException{
in.close();
}
Public int myRead () throws IOException{//问题1返回类型为什么是int而不是byte
If(count= =0){
count=in.read(buf);
byte b=buf[pos];
If(count <0)
return -1;
pos=0;
count--;
pos++;
return b&255;// 问题 2为什么 要&&上255
}
else if(count >0){
byte b=buf[pos];
count--;
pos++;
return b&Oxff;
}
return -1;
}
}
问题1:返回的也是byte的话碰到11111111时候会停止读取,而返回的是int问题得到转化。
问题2:返回的是int话,由1个字节变成4字节,类型提升,不过还是-1,但是与上255的话就会变成前3字节全由0组成后1字节不变,这样保留了自己数据不变,又可避免-1的出现。
Read方法 补0向上提升,保证不会出现-1情况
Write方法 强转动作,把最低8位写出去,将指定字节写出去
读取键盘录入
System.in 对应标准输入设备 默认键盘,read方法阻塞式方法
System.out 对应标准输出设备 默认控制台
例:键盘录入a若读三次结果97,13,10,类型提升
转换流(字符流的子类):转换流什么时候使用?字节和字符之间的桥梁,涉及到字符编码转换
读取转换流(字节通向字符)InputStreamReader有子类FileReader
写入转换流(字符通向字节)OutputStreamWriter 如录字符存字节;有子类FileWriter
例:BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw=new BufferedWriter (new OutputStreamWriter (System.out));
流操作规律:
三个明确:
1、 明确源和目的 源:输入流 读 InputStream Reader
目的:输出流 读 OutputStream Writer
2、 操作数据是否纯文本? 是: 字符流 否:字节流
3、 当体系明确后,明确哪个具体对象,通过设备区分
源设备:内 存、硬盘、键盘 ArrayStream FileStream System.in
目的设备:内 存、硬盘、控制台 ArrayStream FileStream System.out
4、有时候提高效率使用缓冲技术
改变标准输入输出设备
System.setIn(InputStream in), System.setOut (PrintStream out)
System.setIn(new FileInputStream(“a.txt”));//将输入设备变成文本文件
System. setOut (new PrintStream(“a.txt”));//将输出设备变成文本文件
异常日志信息 log 4j
try{}
Catch(Exception e){
try{
Date d=new Date();
SimpleDateFormat sdf=new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);
String s=sdf.format(d);
PrintStream ps=new PrintStream(“exception.log”);
Ps.println(s);
System. setout(ps);}
Catch(IOException ex){
Throw new RuntimeException(“创建失败”);}
e.PrintStackTrace(System.out);//直接写入打印流
}