BIO详解,练习实例理解

BIO

同步阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理

字节流

InputStream和OutputStream,都实现了Coloseable接口,都支持try-resource来抛出异常

  • read():返回值为int,每次读取一个字节,0-255之间,-1表示流结束
  • read(byte[]):返回值为int,表示读取具体的字节个数,-1表示流结束
  • close():返回值void,用来关闭流

练习:读取一个英文文本文件,并在控制台上输出显示

//一次一字节的读取方式
public static void main(String[] args){
	InputStream is = null;//构建流对象
	try{
		is = new FileInputStream("cc.txt");
		int len = 0;
		while((len = is.read()) > 0){
			System.out.print((char)len);//将其强制转换为字符
		}
	}catch(IOException e){
		e.printStackTrace();
	}finally{
		try{
			is.close();
		}catch(IOException e){
			e.printStackTrace();
		}
	}
}

//缓冲数组方式进行读取
public static void main(String[] args){
	InputStream is = null;
	try{
		is = new FileInputStream("cc.txt");
		int len = 0;
		byte[] buffer = new byte[8192];
		while((len = is.read(buffer)) > 0){
			String str = new String(buffer,0,len);
			System.out.print(str);
		}
	}catch (IOException e){
		e.printStackTrace();
	}finally{
		try{
			is.close();	
		}catch(IOException e){
			e.printStackTrace();
		}
	}
}

OutputStream

  • write():返回值为int,每次读取一个字节,0-255之间,-1表示流结束
  • write(byte[], int 起始下标, int 长度):返回值void,表示具体的字节个数,-1表示流结束
  • close():返回值为void,用来关闭流

练习:使用字节流进行文件拷贝

public static void main(String[] args){
	InputStream is = null;
	OutputStream os = null;
	try{
		is = new FileInputStream("a.txt");
		os = new FileOutputStream("b.txt");
		byte[] buffer = new byte[8192];
		int len = 0;
		while((len = is.read(buffer))>0){
			os.writer(buffer,0,len);	
		}
	}catch (IOException e){
		e.printStackTrace();
	}finally{
		try{
			if(is!=null && os!=null){
				is.close();
				os.close();
			}
		}catch (IOException e){
			e.printStackTrace();
		}	
	}
}

字符流

一次一个字符的进行传输,如果涉及了中文信息,则需要考虑编码字符集
Reader

  • read():返回值为int,返回读取到的字符数据,范围为0-65535,-1表示流末尾
  • read(char[]):返回值int,返回读取的字符个数,流结束返回-1
  • close():返回值为void,用来关闭流

练习:从一个txt文件中读取数据,并在控制台上显示输出,并写入到指定文件

public static void main(String[] args) throws IOException {
	try(
		Reader reader = new FileReader("a.txt");
		Writer writer = new FileWriter("b.txt");
		){
		char[] buffer = new char[8192];
		int len = 0;
		while((len = reader.read(buffer))>0){
			String str = new String(buffer,0,len);
			System.out.print(str);
			writer.wite(str);
			reader.close();
			writer.close();
		}
	}
}

节点流

文件流

  • FIleInputStream和FileReader用于从一个文件中读取数据,FileInputStream文件输入字节流,FileReader文件输出字符流
  • FIleOutputStream和FileWrite用于向一个文件写入数据
    • FileOutputStream(“文件名称”),如果文件不存在,则自动创建,如果文件存在,则覆盖原文件的内容
    • FileOutStream(“文件名称”, boolean 是否追加方式),如果文件不存在,则自动创建,如果文件存在并且博哦了安值为true,则表示采用追加的方式进行写入内容

练习:从控制台向一个文件内写入内容

public static void main(String[] args) throws IOException{
	InputStream is = System.in;
	byte[] buffer = new byte[8192];
	int len = is.read(buffer);
	for(len > 0){
		OutputStream os = new FileOutputStream("File.txt",true);
		os.write(buffer,0,len);
		os.close();
	}
}

文件流输入节点流,输入流的源端和输出断点的目标都是磁盘文件,沟通方法允许通过文件的路径或者文件对象的方式进行构建

练习:拷贝Data目录到D:/bbb目录下

public class Test {
    private static String source = "Data";
    private static String target = "D:/bbb";

    public static void main(String[] args) {
        File file = new File(source);
        copy(file);
        System.out.println("拷贝完毕");
    }

    public static void copy(File file){
        if (file != null){
            if (file.isFile()){
                String oldPath = file.getAbsolutePath();
                int pos = oldPath.indexOf(source);
                String substring = target + oldPath.substring(pos+source.length());
                byte[] buffer = new byte[1024];
                int len = 0;
                try(
                        InputStream is = new FileInputStream(file);
                        OutputStream os = new FileOutputStream(substring);
                        ){
                    while ((len = is.read(buffer))>0){
                        os.write(buffer,0,len);
                    }
                }catch (IOException e){
                    e.printStackTrace();
                }
            }else if (file.isDirectory()){
                //将原路径转换为新路径
                String path = file.getAbsolutePath();
                int pos = path.indexOf(source);
                String substring = target + path.substring(pos + source.length());
                File tmp = new File(substring);
                if (!tmp.exists())
                    tmp.mkdirs();
                File[] files = file.listFiles();
                for (File tmp1:files) {
                    copy(tmp1);
                }
            }
        }
    }
}

内存数组节点流

如果是文本字符则使用char[],如果是二进制数据则使用byte[]
输入流

  • CharArrayReader(char[]):其中char[]就是数据的来源
  • CharArrayReader(char[] 数据, int 起始下标, int 最大长度)

练习

public static void main(String[] args){
	String str = "我是李明";
	char[] chars = str.toCharArray();//将字符串转换为数组,实际上Java提供字符串流
	Reader reader = new CharArrayReader(arr);
	int date = 0;
	while((data = reader.read())>0){
		System.out.println((char)data);
	}
	reader.close();
}

输出流
CharArrayWriter用于向一个字符数组中写入数据,这个数组的大小可以自动调整

  • CharArrayWriter():自动创建一个关联char[]的输出流
  • CharArrayWriter(int):自动创建一个管理char[]的输出流,参数代表char[]的初始化大小
public static void main(Stirng[] args) throws IOException {
	Writer writer = new CHarArrayWriter();
	//从键盘读取数据,并写入char[]中
	Scanner sc = new Scanner(System.in);
	String line = Scanner.nextLine();//读取一行数据
	while(!"exit".equals(line)){
		writer.write(line);
		line = scanner.nextLine()+"\n;
	}
	sc.close();
	CharArrayWriter caw = (CharArrayWriter)writer;
	String str = new String(caw.toCharArray());//获取关联的char[]
	System.out.println(str);
}

内存字符流

StringReader用于从一个String中读取数据

public static void main(String[] args){
	String str = "我是彭于晏";
	Reader reader = new StringReader(str);
	int len = 0;
	while((len = reader.read())>0){
		System.out.println((char)len);
	}
	reader.close();
}

StringWriter用于向一个StringBuffer中写入数据,实现了一个可变长度的字符串

public static void main(String[] agrs) throws Exception{
	Scanner sc = new Scanner(System.in);
	try(
		StringWriter sw = new StringWriter();
		Writer writer = new FileWirter("String.txt");
	){
		String str = sx.nextLine();
		while(!"quit".equals(str)){
			if(str!=null && str.trim().length()>0)
			sw.write(str+"\n");
			str = sc.nextLine();
		}
		System.out.println(sw.toString());
		writer.write(sw.toString());
	}
	sc.close();
}

过滤流

过滤流就是节点流的基础上附加功能
实例:循环13加密(以输入方式进行加密)

public class MyFilterReader extends FilterReader{
	protected MyFilterReader(Reader in){
		super(in);
	}
	 public int read() throws IOException {
        int num = super.read();
        if (num >= 'a' && num <= 'z') {
            num = (num - 'a' + 13) % 26 + 'a';
        } else if (num >= 'A' && num <= 'Z') {
            num = (num - 'A' + 13) % 26 + 'A';
        } else if (num >= '0' && num <= '9') {
            num = (num - '0' + 5) % 10 + '0';
        }
        return num;
    }
    public static void main(String[] args){
        MyFilterReader mfr = new MyFilterReader(new FileReader("Data/Test.java"));
        int kk;
        while ((kk = mfr.read()) != -1) {
            System.out.print((char) kk);
        }
        sr.close();
    }
}

实例:循环13加密(以输出方式进行加密)

class MyFilter extends FilterWriter {
	protected MyFilterWriter(Writer out){
		super(out);
	}
	public void write(int c) throws IOException {
		if (c >= 'a' && c <= 'z') {
            c = (c - 'a' + 13) % 26 + 'a';
        } else if (c >= 'A' && c <= 'Z') {
            c = (c - 'A' + 13) % 26 + 'A';
        } else if (c >= '0' && c <= '9') {
            c = (c - '0' + 5) % 10 + '0';
        }
        super.write(c);
	}
	public static void main(String[] args){
		try(
			Reader r = new FileReader("a.txt");
			MyFilterWriter w = new MyFilterWriter(new FileWriter("b.txt"));
		){
			int len = 0;
			while((len=r.read()>0)){
				w.write(len);
			}
			r.close();
			w.close();
		}
	}
}

桥接流

实现字节记录和字符流之间的自动转换,从字节输入流读取字节数据,并按照编码规范转换为字符;向字节输出流写出数据是,先将字符按照编码规范转换为字节,然后再进行输出。使用桥接流时应该指定编码字符集名称,以便实现流的转换,如果不指定,则使用当前默认的编码字符集。

  • InputStreamReader用于将一个InputStream自动转换为Reader
  • OutputStreamWriter用于将一个Writer自动转换为OutPutStream

InputStreamReader

  • InputStreamReader(InputStream)
  • InputStreamReader(InputStream in,String charsetName)
  • InputStreamReader(InputStream in,Charset cs),直接使用charsetName编码字符集名称的方式进行设定编码字符集可能会出错,所以可以使用Charset指定编码字符集名称
public static void main(String[] args){
	Reader r = new InputStreamReader(System.in);
	int len = r.read();
	System.out.println((char)len);//只读取一个字符

	//使用UTF-8编码字符集
	Reader r = new InputStreamReader(System.in,"UTF-8");
	int len = r.read;
	System.out.println((char)len);
}

缓冲流

缓冲流时套装在相应的节点流之上,对读写操作提供缓冲作用,提高的效率,并引入一个新方法BufferedInlutStream()

public static void main(String[] args){
	//没有缓冲流的时间统计
	long start = System.currentTimeMillis();
	InputStream is = new FileInputStream("a.txt");
	int len = 0;
	while((len=is.read())>0){
		System.out.print((char)len);
	}
	is.close();
	long end = System.currentTimeMillis();
	System.out.println("执行时间为:"+(end-start)+"ms");

	//有缓冲流的时间统计
	long start1 = 	System.currentTimeMills();
	InputStream is1 = new 	BufferedInputStream(new FileInputStream("a.txt"));
	int len1 = 0;
	while((len1 = is1.read())>0){
		System.out.print((char)len1);
	}
	is.close();
	long end1 = System.currentTimeMillis();
	System.out.println("执行时间为:"+(end1-start1)+"ms");
}
  • 读写文件使用文件流,如果操作文本文件建议使用FileReader和FileWriter,如果是操作二进制文件,则建议使用FileInputStreamhe FileOutputStream。
  • 需要建立缓冲区,可以考虑建立临时文件,但是这种方式效率低下,所以一般建议考虑使用CharArrayReader/CharArrayWriter和ByteArrayInputStream/ByteArrayOutputStream或者StringReader/StringWriter充当内存缓冲区
  • 如果需要二进制缓冲可以ByteArrayInputStream/ByteArrayOutputStream,如果需要一个字符缓冲区,可以使用CharArrayReader/CharArrayWriter、StringReader/StringWriter
  • 如果数据量不是特别大,则使用CharArrayReader/CharArrayWriter更为方便一些,如果数据量大,可能需要直接操作缓冲区,则可以使用StringReader/StringWriter
  • StringWriter中提供了一个getBuffer()方法,可以获取到StringBuffer
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值