JAVA基础学习day20--IO流二-缓冲流、字节流
一、缓冲流
1.1、字符流的缓冲区
缓冲区的出现是为了提高IO的读写效率
对应类
BufferedReader
BufferedWriter
缓冲区要结合流才可以使用
在流的基础上对流的功能进行了增强
1.2、BufferedReader、BufferedWriter
public class BufferedWriterextends Writer
构造方法摘要 | |
---|---|
BufferedWriter(Writer out) 创建一个使用默认大小输出缓冲区的缓冲字符输出流。 |
|
BufferedWriter(Writer out,
int sz)
创建一个使用给定大小输出缓冲区的新缓冲字符输出流。 |
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
该类提供了 newLine() 方法,它使用平台自己的行分隔符概念,此概念由系统属性 line.separator 定义。并非所有平台都使用新行符 ('\n') 来终止各行。因此调用此方法来终止每个输出行要优于直接写入新行符。
通常 Writer 将其输出立即发送到底层字符或字节流。除非要求提示输出,否则建议用 BufferedWriter 包装所有其 write() 操作可能开销很高的 Writer(如 FileWriters 和 OutputStreamWriters)。例如,
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
将缓冲 PrintWriter 对文件的输出。如果没有缓冲,则每次调用 print() 方法会导致将字符转换为字节,然后立即写入到文件,而这是极其低效的。
public class BufferedReaderextends Reader
构造方法摘要 | |
---|---|
BufferedReader(Reader in) 创建一个使用默认大小输入缓冲区的缓冲字符输入流。 |
|
BufferedReader(Reader in,
int sz) 创建一个使用指定大小输入缓冲区的缓冲字符输入流。 |
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
通常,Reader 所作的每个读取请求都会导致对底层字符或字节流进行相应的读取请求。因此,建议用 BufferedReader 包装所有其 read() 操作可能开销很高的 Reader(如 FileReader 和 InputStreamReader)。例如,
BufferedReader in = new BufferedReader(new FileReader("foo.in"));
将缓冲指定文件的输入。如果没有缓冲,则每次调用 read() 或 readLine() 都会导致从文件中读取字节,并将其转换为字符后返回,而这是极其低效的。
通过用合适的 BufferedReader 替代每个 DataInputStream,可以对将 DataInputStream 用于文字输入的程序进行本地化
1.3、示例
在创建缓冲区之前,必须先有流对象
package com.pb.io.demo2; /** 创建缓冲区之间必须,先创建流 使用缓冲区,要flush,刷新 */ /** 创建缓冲区之间必须,先创建流 使用缓冲区,要flush,刷新 */ import java.io.*; class BufferedReaderAndWriterDemo1 { public static void main(String[] args) { File source=new File("d:\\demo.txt"); File objFile=new File("d:\\a.txt"); useBuffered(source,objFile); } public static void useBuffered(File source,File objFile){ BufferedReader br=null; BufferedWriter bw=null; try{ //声明缓冲区对象,并将字符流做为参数传入 br=new BufferedReader(new FileReader(source)); bw=new BufferedWriter(new FileWriter(objFile)); //接收读取的长度 String line=null; //读取内容并放入buf中,判断是不是最后 while((line=br.readLine())!=null){ //写入,有多长写多长 bw.write(line,0,line.length()); bw.newLine(); } System.out.println("读写完成!"); }catch(IOException e){ System.out.println(e.toString()); }finally{ try{ if(bw!=null) bw.flush(); bw.close(); }catch(IOException e){ System.out.println(e.toString()); } try{ if(br!=null) br.close(); }catch(IOException e){ System.out.println(e.toString()); } } } }
二、MyBuffered
2.1、示例
package com.pb.io.demo2; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class MyBuffered { private FileReader fr; public MyBuffered(FileReader fr) { this.fr = fr; } /* * 可以一次读一行的方法 */ public String myReadLine() throws IOException { // 定义一个临时 容器,原BufferedReader封装的是字符数组 // 为了方便,定义一个StringBuilder StringBuilder sb = new StringBuilder(); int ch = 0; while ((ch = fr.read()) != -1) { if (ch == '\r') { continue; } if (ch == '\n') { return sb.toString(); } // 读一个存一个 sb.append((char)ch); } if(sb.length()!=0){ return sb.toString(); } return null; } public void myClose() throws IOException{ if (fr != null) fr.close(); } public static void main(String[] args) throws IOException { File file=new File("d:\\demo.txt"); MyBuffered mb=new MyBuffered(new FileReader(file)); String line=null; while((line=mb.myReadLine())!=null){ System.out.println(line); } mb.myClose(); } }
三、装饰设计模式
3.1、装饰设计模式
装饰设计模式:
当想要对已经有的对象进行功能增强时,
可以定义类,将已经对象传入,基于已经有的功能,并提供加强功能。
那么自定义的该类就称为装饰类
package com.pb.io.demo3; class Person{ public void eat(){ System.out.println("吃饭"); } } class SuperPerson{ private Person p; public SuperPerson(Person p) { super(); this.p = p; } public void superEat(){ System.out.println("开胃酒"); p.eat(); System.out.println("甜点"); System.out.println("来一根"); } } public class PersonTest { public static void main(String[] args) { Person p=new Person(); p.eat(); SuperPerson sp=new SuperPerson(p); sp.superEat(); } }
3.2、与继承之间的关系
装饰类通常会通过构造方法接收被被装饰的对象,并基于被装饰的对象的功能,提供更强的功能
装饰模式比继承灵活,避免了继承体系臃肿
而且降低了类于类之间的关系
装饰类因为增强已有对象,具备的功能和已经的是相同的,只不过提供了更强的功能。
所以装饰类和被装饰类通常是都属于一个体系中。
四、LineNumberReader
4.1、
构造方法摘要 | |
---|---|
LineNumberReader(Reader in) 使用默认输入缓冲区的大小创建新的行编号 reader。 |
|
LineNumberReader(Reader in,
int sz) 创建新的行编号 reader,将字符读入给定大小的缓冲区。 |
方法摘要 | |
---|---|
int |
getLineNumber()
获得当前行号。 |
void |
mark(int readAheadLimit)
标记该流中的当前位置。 |
int |
read()
读取单个字符。 |
int |
read(char[] cbuf,
int off, int len) 将字符读入数组中的某一部分。 |
String |
readLine()
读取文本行。 |
void |
reset()
将该流重新设置为最新的标记。 |
void |
setLineNumber(int lineNumber)
设置当前行号。 |
long |
skip(long n)
跳过字符。 |
4.2、示例
package com.pb.io.demo4; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.LineNumberReader; public class LineNumberReaderDemo { public static void main(String[] args) { LineNumberReader lnr=null; try { lnr=new LineNumberReader(new FileReader("d:\\demo.txt")); //设置开始行叼 lnr.setLineNumber(100); String line=null; while((line=lnr.readLine())!=null){ //getLineNumber默认从1开始,设置后从设置的行号开始 System.out.println(lnr.getLineNumber()+":"+line); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ try { if(lnr!=null) lnr.close(); } catch (IOException e) { e.printStackTrace(); } } } }
4.3、自定义
package com.pb.io.demo4; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.Reader; public class MyLineNumberReader { private Reader reader; private int lineNumber; public MyLineNumberReader(Reader reader) { this.reader = reader; } /* * 读一行 */ public String myReadLine() throws IOException { lineNumber++; StringBuilder sb = new StringBuilder(); int ch=0; while ((ch = reader.read()) != -1) { if (ch == '\r') continue; if (ch == '\n') return sb.toString(); sb.append((char) ch); } if (sb.length() != 0) return sb.toString(); return null; } public void myClose() throws IOException{ reader.close(); } public Reader getReader() { return reader; } public void setReader(Reader reader) { this.reader = reader; } public int getLineNumber() { return lineNumber; } public void setLineNumber(int lineNumber) { this.lineNumber = lineNumber; } public static void main(String[] args) throws IOException { File file=new File("d:\\demo.txt"); MyLineNumberReader mln=new MyLineNumberReader(new FileReader(file)); String line=null; //mln.setLineNumber(100); while((line=mln.myReadLine())!=null){ System.out.println(mln.getLineNumber()+":"+line); } mln.myClose(); } }
五、字节流
5.1、字节流
OutputStream写、InputStream读
FileOutputStream、FileInputStream 字节流输出、输入流
构造方法摘要 | |
---|---|
OutputStream() |
方法摘要 | |
---|---|
void |
close()
关闭此输出流并释放与此流有关的所有系统资源。 |
void |
flush()
刷新此输出流并强制写出所有缓冲的输出字节。 |
void |
write(byte[] b)
将 b.length 个字节从指定的 byte 数组写入此输出流。 |
void |
write(byte[] b,
int off, int len) 将指定 byte 数组中从偏移量 off 开始的
len 个字节写入此输出流。 |
abstract
void |
write(int b)
将指定的字节写入此输出流。 |
构造方法摘要 | |
---|---|
InputStream() |
方法摘要 | |
---|---|
int |
available()
返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。 |
void |
close()
关闭此输入流并释放与该流关联的所有系统资源。 |
void |
mark(int readlimit)
在此输入流中标记当前的位置。 |
boolean |
markSupported()
测试此输入流是否支持 mark 和 reset 方法。 |
abstract
int |
read()
从输入流中读取数据的下一个字节。 |
int |
read(byte[] b)
从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。 |
int |
read(byte[] b,
int off, int len) 将输入流中最多 len 个数据字节读入 byte
数组。 |
void |
reset()
将此流重新定位到最后一次对此输入流调用 mark 方法时的位置。 |
long |
skip(long n)
跳过和丢弃此输入流中数据的 n 个字节。 |
5.2、FileInputStream与FileOutputStream
package com.pb.io.demo5; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /** * 使用字节流复制文件 * */ public class FileOutputAndFileInputStreamDemo { public static void main(String[] args) { File source=new File("d:\\1.jpg"); File objFile=new File("d:\\4.jpg"); InputAndOutput2(source,objFile); } public static void InputAndOutput(File source,File objFile){ //声明字节流输入,输出对象 FileInputStream fis=null; FileOutputStream fos=null; try { fis=new FileInputStream(source); fos=new FileOutputStream(objFile); //声明缓冲区 byte [] buf=new byte[1024]; int len=0; while((len=fis.read(buf))!=-1){ fos.write(buf, 0, len); } System.out.println("=======读写完成========"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ try { if(fos!=null) fos.close(); } catch (IOException e) { e.printStackTrace(); } try { if (fis!=null) fis.close(); } catch (IOException e) { e.printStackTrace(); } } } /* * 不建议使用 */ public static void InputAndOutput2(File source,File objFile){ //声明字节流输入,输出对象 FileInputStream fis=null; FileOutputStream fos=null; try { fis=new FileInputStream(source); fos=new FileOutputStream(objFile); //声明大小刚刚缓冲区 byte [] buf=new byte[fis.available()]; //不建议使用available fis.read(buf); fos.write(buf,0,buf.length); System.out.println("=======读写完成========"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ try { if(fos!=null) fos.close(); } catch (IOException e) { e.printStackTrace(); } try { if (fis!=null) fis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
六、字节流缓冲区
6.1、示例复制.mp3
package com.pb.io.demo5; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class BufferedStreamDemo { public static void main(String[] args) { File file1=new File("d:\\gm.mp3"); File file2=new File("d:\\mg.mp3"); copy1(file1,file2); } public static void copy1(File file1,File file2){ //声明字节流缓冲区对象 BufferedOutputStream bos=null; BufferedInputStream bis=null; try { bis=new BufferedInputStream(new FileInputStream(file1)); bos=new BufferedOutputStream(new FileOutputStream(file2)); //声明缓冲区大小 int by=0; while((by=bis.read())!=-1){ bos.write(by); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ try { if(bos!=null) bos.close(); } catch (IOException e) { e.printStackTrace(); } try { if(bis!=null) bis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
6.2、自定义
package com.pb.io.demo5; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; public class MyBufferedStream { private InputStream is; private byte[] buf = new byte[1024]; private int pos = 0; private int count = 0; public MyBufferedStream(InputStream is) { this.is = is; } /* * 一次读一个字节,从缓冲区的(字节数组)获取 */ public int myRead() throws IOException { // 通过in对象读取硬盘上的数据,并存在buf中 if (count == 0) { count = is.read(buf); if (count < 0) { return -1; } pos = 0; byte b = buf[pos]; count--; pos++; return b & 0xff; } else if (count > 0) { byte b = buf[pos]; count--; pos++; return b & 0xff; } return -1; } public void myClose() throws IOException { is.close(); } public static void main(String[] args) { File file1 = new File("d:\\gm.mp3"); File file2 = new File("d:\\kk.mp3"); copy1(file1, file2); } public static void copy1(File file1, File file2) { // 声明字节流缓冲区对象 BufferedOutputStream bos = null; MyBufferedStream mbs = null; try { mbs = new MyBufferedStream(new FileInputStream(file1)); bos = new BufferedOutputStream(new FileOutputStream(file2)); // 声明缓冲区大小 int by = 0; while ((by = mbs.myRead()) != -1) { bos.write(by); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (bos != null) bos.close(); } catch (IOException e) { e.printStackTrace(); } try { mbs.myClose(); } catch (IOException e) { e.printStackTrace(); } } } }
七、转换
7.1、字节流转换字符流
InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset
读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset
将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
Writer out = new BufferedWriter(new OutputStreamWriter(System.out));
7.2、示例
接收键盘输入,使用转换流实现
package com.pb.io.demo6; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; /** * 接收键盘输入,并将内容写入文件 * */ public class Demo { public static void main(String[] args) { BufferedReader br=null; BufferedWriter bw=null; try { //声明输入流,使用转换流实现 br=new BufferedReader(new InputStreamReader(System.in)); //声明输出流,使用转换流实现 bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("d:\\t.txt"))); //接收键盘录入 String str=null; System.out.println("请输入要写入文件的内容,输入over结束!"); //输入over结束 while(!(str=br.readLine()).equals("over")){ bw.write(str); bw.newLine(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ try { if(bw!=null) bw.close(); } catch (IOException e) { e.printStackTrace(); } try { if(br!=null) br.close(); } catch (IOException e) { e.printStackTrace(); } } } }
八、流操作的规律
1、明确源和目的
源:输入流。InputStream,Reader
目的:输出流 .OutputStream,Writer
2、操作的数据是否为纯文本
是:字符流。Reader、Writer
不是:字节流。InputStream、OutputStream
3、当体系明确后,在明确要使用哪个具体对象。
通过设备来进行区别。
源设备:内存、硬盘、键盘
目的设备:内存、硬盘、控制台
九、重定向IO
9.1、示例
//设置输入流的 System.setIn(new FileInputStream("d:\\demo.txt")); //设置的输出流的方向 System.setOut(new PrintStream("d:\\zz.txt"));
十、系统信息
10.1、示例
package com.pb.io.demo6; import java.util.Properties; public class Demo1 { public static void main(String[] args) { Properties prop=System.getProperties(); prop.list(System.out); //可以设置为输出流对象new PrintWriter(文件) } }
-- listing properties -- java.runtime.name=Java(TM) SE Runtime Environment sun.boot.library.path=C:\Java\jre1.8.0_60\bin java.vm.version=25.60-b23 java.vm.vendor=Oracle Corporation java.vendor.url=http://java.oracle.com/ path.separator=; java.vm.name=Java HotSpot(TM) 64-Bit Server VM file.encoding.pkg=sun.io user.script= user.country=CN sun.java.launcher=SUN_STANDARD sun.os.patch.level= java.vm.specification.name=Java Virtual Machine Specification user.dir=F:\work\IODemo java.runtime.version=1.8.0_60-b27 java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment java.endorsed.dirs=C:\Java\jre1.8.0_60\lib\endorsed os.arch=amd64 java.io.tmpdir=C:\Users\ADMINI~1\AppData\Local\Temp\ line.separator= java.vm.specification.vendor=Oracle Corporation user.variant= os.name=Windows 7 sun.jnu.encoding=GBK java.library.path=C:\Java\jre1.8.0_60\bin;C:\Windows\Su... java.specification.name=Java Platform API Specification java.class.version=52.0 sun.management.compiler=HotSpot 64-Bit Tiered Compilers os.version=6.1 user.home=C:\Users\Administrator user.timezone= java.awt.printerjob=sun.awt.windows.WPrinterJob file.encoding=UTF-8 java.specification.version=1.8 user.name=Administrator java.class.path=F:\work\IODemo\bin java.vm.specification.version=1.8 sun.arch.data.model=64 java.home=C:\Java\jre1.8.0_60 sun.java.command=com.pb.io.demo6.Demo1 java.specification.vendor=Oracle Corporation user.language=zh awt.toolkit=sun.awt.windows.WToolkit java.vm.info=mixed mode java.version=1.8.0_60 java.ext.dirs=C:\Java\jre1.8.0_60\lib\ext;C:\Window... sun.boot.class.path=C:\Java\jre1.8.0_60\lib\resources.jar... java.vendor=Oracle Corporation file.separator=\ java.vendor.url.bug=http://bugreport.sun.com/bugreport/ sun.cpu.endian=little sun.io.unicode.encoding=UnicodeLittle sun.desktop=windows sun.cpu.isalist=amd64