2018-06-06 第三十一天

时间:2021-11-25 18:20:20

一、File***Stream和 Buffered***Stream

Buffered带缓存区,提高了内存和内存之间的交互,减少了内存和磁盘之间的交互,效率更高。


2018-06-06 第三十一天
2018-06-06 第三十一天


二、MyBuffered


import java.io.InputStream;

import java.io.OutputStream;

import java.io.FileInputStream;

import java.io.FileOutputStream;


public class TestMyBufferedStream {


public static void main(String[] args) {

long time = System.currentTimeMillis();

BufferedInputOutputStreamTest.copyFile();

long cost = System.currentTimeMillis()-time;

System.out.println("buffered cost = "+cost);

time = System.currentTimeMillis();

try {

copyFile();

catch (Exception e) {

e.printStackTrace();

}

cost = System.currentTimeMillis()-time;

System.out.println("myBuffered cost = "+cost);

}

static void copyFile() throws Exception{

MyBufferedInputStream mbis = new MyBufferedInputStream(new FileInputStream("c:/77.jpg"));

MyBufferedOutputStream mbos = new MyBufferedOutputStream(new FileOutputStream("c:/99.jpg"));

int value = 0;

while((value = mbis.read()) != -1){

mbos.write(value);

}

mbis.close();

mbos.flush();

mbos.close();

}

}

/**

 * 自定义的带缓冲区的字节输入流,模拟  java.io.BufferedInputStream

 *

 */

public class MyBufferedInputStream {

//定义默认的缓冲区大小

public static final int DEFAULT_BUF_SIZE = 8192;

//字节数组缓冲区

private byte[] buf;

//用于读取数据源的字节输入流的引用,可以是任意的字节输入流

private InputStream is;

//记录当前读取到的字节数组数据的下标

private int pos;

//用于记录缓冲区中有效的字节数据

private int count;

public MyBufferedInputStream(InputStream is) {

this.is = is;

buf = new byte[DEFAULT_BUF_SIZE];

}

public MyBufferedInputStream(InputStream is,int bufSize) {

this.is = is;

buf = new byte[bufSize];

}

//最核心对外提供的read 方法 读取下一个字节的数据

//从buf 中取一个字节的数据

public int read() throws Exception{

if(count == 0){//缓冲区没有数据了

//一次性从通过is 读取底层数据 到buf 中,并记录读取到了多少有效字节数据。

count = is.read(buf);

//一种是 数据源还有数据,一种是数据源没有数据了,返回-1

if(count == -1)//return -1

return -1;

pos = 0;

//使用int 的低八位 保存 读取到的字节数据。

int value = buf[pos] & 0xff;

pos ++;

count --;

return value;

}else{//缓冲区有数据

int value = buf[pos] & 0xff;

pos ++;

count --;

return value;

}

}

//包装流的关闭问题,关闭的是被包装的流。

public void close() throws Exception{

if(is != null){

is.close();

}

}

}


/**

 * 自定义的带缓冲区的输出流

 *

 */

class MyBufferedOutputStream{

//定义默认的缓冲区大小

public static final int DEFAULT_BUF_SIZE = 8192;

//字节数组缓冲区

private byte[] buf;

//用于读取数据源的字节输入流的引用,可以是任意的字节输入流

private OutputStream os;

//用于记录写入缓冲区的字节数据的个数,和当前待写入数组元素的下标

private int pos;

public MyBufferedOutputStream(OutputStream os) {

this.os = os;

buf = new byte[DEFAULT_BUF_SIZE];

}

public MyBufferedOutputStream(OutputStream os,int bufSize) {

this.os = os;

buf = new byte[bufSize];

}

/**

 * 将value 的后八位写出去

 * @param value

 */

public void write(int value) throws Exception{

//缓冲区满了

if(pos == buf.length){

//将缓冲区的内容全部写出去

os.write(buf);

pos = 0;

//然后再将value 写入下标pos = 0 的位置

buf[pos] = (byte)value;

//pos 永远指向 待写入数据的下标

pos ++;

}else{//缓冲区没有满

//将value 写入pos 位置

buf[pos] = (byte)value;

//pos 永远指向 待写入数据的下标

pos ++;

}

}

public void flush() throws Exception{

if(pos != 0){

//将缓冲区中没有写出去的数据,刷新到目的地

os.write(buf, 0, pos);

pos = 0;

}

}

//

public void close() throws Exception{

if(os != null){

//确保在关闭的时候,可以将缓冲区中的数据刷新出去

flush();

os.close();

}

}

}


包装流的关闭问题:

只关闭包装流即可,因为在关闭包装流的方法中,对被包装的流进行了关闭。

 

三、BufferedReaderBufferedWriter

带缓冲区的字符流。缓冲区8192 个字符。 char[]


import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.FileReader;

import java.io.FileWriter;

import java.io.IOException;


public class BufferedReaderWriterTest {


public static void main(String[] args) {

copyTextFile();

}

static void copyTextFile(){

FileReader fr = null;

BufferedReader br = null;

FileWriter fw = null;

BufferedWriter bw = null;

try {

fr = new FileReader("./res/my_letter.txt");

br = new BufferedReader(fr);

fw = new FileWriter("./res/my_letter_copy.txt");

bw = new BufferedWriter(fw);

//用于读取一行文本数据,如果方法返回null 则表示读取到了文件的末尾

String str = br.readLine();

while(str != null){

bw.write(str);

//向输出流中写出一个当前系统的换行符  

bw.newLine();

str = br.readLine();

}

catch (Exception e) {

e.printStackTrace();

}finally {

if(br != null){

try {

br.close();

catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

if(bw != null){

try {

bw.close();

catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

if(fr != null){

try {

fr.close();

catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

if(fw != null){

try {

fw.close();

catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

}


readLine():用于读取一行文本数据。当读取到\r\n时候方法返回。把读取到的所有的内容返回,返回的内容中不包含 \r\n。


四、LineNumberReader

LineNumberReader:是BufferedReader 的子类。增加了用于记录读取到文本数据的多少行的功能。

import java.io.FileReader;

import java.io.LineNumberReader;


public class LineNumberReaderTest {

//将当前文件的所有的内容,打印到控制台,输出的时候,还有行号输出。

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

LineNumberReader lnr = new LineNumberReader(new FileReader("./src/com/bjsxt/io/LineNumberReaderTest.java"));

//设置起始行号

lnr.setLineNumber(100);

String str = null;

//读取一行,并打印一行

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

//获得行号

int number = lnr.getLineNumber();

System.out.println(number + " "+str);

}

lnr.close();

}

}


五、装饰设计模式

装饰设计模式:带缓冲区的字节流,字符流都使用了该设计模式。


作用:增强扩展指定的类的。

public class DecorateTest {

public static void main(String[] args) {

SuperPeople people = new SuperPeople(new Person());

people.eat();

}

}


class Person{

void eat(){

System.out.println("人要吃饭,为了生存!");

}

}

//继承扩展现有的类

class SuperPerson extends Person{

void eat(){

System.out.println("人吃饭不仅仅是为了生存,还是为了更好的生存!享受健康的生活");

}

}


//使用组合扩展现有类

//组合优于继承:组合既可以扩展指定的类型,还可以是指定类型的子类型。

class SuperPeople {

//被扩展的类作为扩展类的实例成员  组合

private Person person;

public SuperPeople(Person person) {

this.person = person;

}

void eat(){

System.out.println("我喜欢吃鱼!");

System.out.println("我喜欢羊腿+啤酒(不能太凉,怂人乐即可)!");

person.eat();

}

}


六、InputStreamReader 和 OutputStreamWriter

InputStreamReader:转换流:从字节到字符的转换的流。字符流

解码器--所有的字符流都以它为基础进行工作。


public class InputStreamReader extends Reader

InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。


每次调用InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。


InputStreamReader :给它提供一堆字节数据,它可以根据字符集返回给你一堆字符数据。

吃的是字节,挤的是字符。



所有的字符输出流,最终写到磁盘中的是字节数据。

write(String)


OutputStreamWriter: 字符输出流

 

public class OutputStreamWriter extends Writer  

OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。

 

每次调用write() 方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得到的这些字节将在缓冲区中累积。可以指定此缓冲区的大小,不过,默认的缓冲区对多数用途来说已足够大。注意,传递给 write() 方法的字符没有缓冲。

 

为了获得最高效率,可考虑将OutputStreamWriter 包装到 BufferedWriter 中,以避免频繁调用转换器。

 

总结:InputStreamReader 是所有的字符输入流字节到字符转换的基础。解码转换器。是所有的字符输入流的实现都依赖于该类提供的解码的功能。

OutputStreamWriter  是所有的字符输出流字符到字节转换的基础。编码转换器。是所有的字符输出流的实现都依赖于该类提供的编码的功能。


字节数据:密文

字符集:整数和字符对应的一个映射表

字节数据对应的字符序列:明文


编码:字符-->字节

解码:字节-->字符


例1:

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.FileInputStream;

import java.io.FileWriter;

import java.io.InputStreamReader;


public class InputStreamReaderTest {


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

test1();

}

static void test() throws Exception{

//如果不显示指定字符集,使用平台默认的字符集工作的 转换流,给它提供字节数据

//可以显式指定字符集

InputStreamReader isr = new InputStreamReader(new FileInputStream("./res/3.txt"),"utf-8");

BufferedReader br = new BufferedReader(isr);

String str = br.readLine();

while(str != null){

System.out.println(str);

str = br.readLine();

}

br.close();

}

//接收键盘的输入,将输入的内容写入到指定的文件中。如果输入了bye,那么输入终止

static void test1() throws Exception{

//将键盘输入的字节流,转换为字符流

InputStreamReader isr = new InputStreamReader(System.in);

//为了提高效率 使用BufferedReader 包一层

BufferedReader br = new BufferedReader(isr);

BufferedWriter bw = new BufferedWriter(new FileWriter("./res/input.txt"));

//接收键盘的输入了,当回车的时候,该方法返回。

String str = br.readLine();

while(!"bye".equals(str)){

bw.write(str);

bw.newLine();

bw.flush();

str = br.readLine();

}

br.close();

bw.close();

}


}


例2:

import java.io.BufferedWriter;

import java.io.FileOutputStream;

import java.io.OutputStreamWriter;


public class OutputStreamWriterTest {


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

test();

}

static void test() throws Exception{

//使用平台默认的字符集进行编码 成字节,通过out 字节流,将 编码得到的字节写出到底层

// OutputStreamWriter osw = new OutputStreamWriter(out)

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("./res/6.txt"),"UTF-8");

BufferedWriter bw = new BufferedWriter(osw);

//写到bw 中的缓冲区中

bw.write("月上柳梢头,人约黄昏后!");

bw.close();

}

}


七、适配器设计模式

适配器设计模式:

InputStreamReader :吃的是字节,产出的是字符。


适配器:Adapter:

笔记本和手机充电器中的适配器的作用:吃的是生活电压(220V),产出的是我们笔记本,和手机充电需要的电压。


有类适配器设计模式和对象适配器设计模式。


public class AdapterTest {

public static void main(String[] args) {

// MyAdapter adapter = new MyAdapter();

// adapter.run();

MyObjAdapter adapter = new MyObjAdapter(new Adaptee());

adapter.run();

}

}


//底层工作的电压

class Adaptee{

int run(){

System.out.println("我提供了220V的电压");

return 220;

}

}


//类适配器设计模式  使用继承

class MyAdapter extends Adaptee{

//笔记本的工作电压为22V

int run() {

int num = super.run();

System.out.println("220V电压被转换为22V工作电压了!");

return num/10;

}

}


//对象适配器设计模式--使用组合方式,把被适配的对象作为成员存在

class MyObjAdapter{

Adaptee adaptee;

public MyObjAdapter(Adaptee adaptee) {

this.adaptee = adaptee;

}

int run(){

int num = adaptee.run();

System.out.println("220V电压被转换为22V工作电压了!");

return num/10;

}

}


2018-06-06 第三十一天