黑马程序员_基础_IO流学习笔记_字节流的学习

-------android培训java培训、期待与您交流!----------

1、字节流File读写操作

所有文件的储存是都是字节(byte)的储存,在磁盘上保留的并不是文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。在读取文件(特别是文本文件)时,也是一个字节一个字节地读取以形成字节序列。字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串。

下面是运用字节流读取数据的简单练习:

public class IO_05_ByteStream {
	
	public static void main(String[] args) throws IOException{
		readFileUseAvailable();
	}
	
	public static void readFileUseAvailable() throws IOException{
		
		//使用available()方法获取字节个数
		FileInputStream fis = new FileInputStream("G:\\TestFolder\\byte.txt");
		int len = fis.available();
		byte[] bs = new byte[len];		//此种方法慎用,数据太大会使数组太大,从而有可能导致内存溢出
		fis.read(bs);
		P.rintln(new String(bs));
		fis.close();
	}
	
	public static void readFile() throws IOException{
		
		FileInputStream fis = new FileInputStream("G:\\TestFolder\\byte.txt");
		int c;
		while((c = fis.read()) != -1){
			P.rinttab((char)c);				//P.rinttab方法封装了系统的输出方法并且额外输出4个空格
		}
		fis.close();
		P.rintln();
		
		FileInputStream fis2 = new FileInputStream("G:\\TestFolder\\byte.txt");	
		byte[] bs = new byte[1024];		//使用数组批量输出
		int len;
		while((len = fis2.read(bs)) != -1){
			P.rintln(new String(bs, 0, len));
		}
		fis2.close();
	}
	
	public static void writeFile() throws IOException{
		
		 FileOutputStream  fos = new FileOutputStream("G:\\TestFolder\\byte.txt");
		 fos.write("abcde".getBytes());
		 fos.close();	//字节流写入数据不需要刷新
	}
}
2、copy图片,下面是本机测试的源代码

public static void copyImage(){		//copy图片小测试
		
		FileInputStream fis = null;
		FileOutputStream fos = null;
		byte[] bs = new byte[1024];
		int len;
		
		try {
			fis = new FileInputStream("G:\\TestFolder\\image.gif");
			fos = new FileOutputStream("G:\\TestFolder\\image_copy.gif");
			while((len = fis.read(bs)) != -1){
				fos.write(bs, 0, len);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if(fis != null){
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(fos != null){
				try {
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
	}
3、字节流的缓冲区

缓冲区的原理是预先将一批数据比如1024字节存放到内存中,然后将内存中的数据一个字节一个字节写入到硬盘上,取完这批数据之后,再从硬盘抓取1024字节数据存放到内存中,如此一直到返回-1,即数据全部取完了。

下面是一个使用字节流缓冲区copy Mp3的例子:

public static void copyMp3() throws IOException{	//使用字节流的缓冲区copy Mp3
		
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream("G:\\TestFolder\\mp3.mp3"));
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("G:\\TestFolder\\mp3_copy.mp3"));
		int bt = 0;
		
		while((bt = bis.read()) != -1){
			bos.write(bt);
		}
		
		bis.close();
		bos.close();
	}
自定义字节流的缓冲区,以及要点说明:

//自定义一个字节流的缓冲区
class MyBufferedInputStream{
	
	private InputStream is;
	private byte[] bs = new byte[1024];
	private int pos = 0, count = 0;
	
	public MyBufferedInputStream(InputStream is){
		this.is = is;
	}
	
	public int myRead() throws IOException{
		
		if(count == 0){
			count = is.read(bs);
			if(count < 0){
				return -1;
			}
			pos = 0;
			byte b = bs[pos];
			pos++;
			count--;
			//返回的是int,如果byte类型恰好是11111111,则在8个1前面补1导致返回的是int的-1
			//所以需要将byte与0xff(十进制即255)进行&操作,即相当于在byte前面补0,返回的是int的255
			//这样子可以保留原数据不变,又可以避免-1的出现
			return b&255;
		}
		else if(count > 0){
			byte b = bs[pos];
			count--;
			pos++;
			return b&0xff;	//0xff即是255的十六进制表现形式
		}
		return -1;
	}
	//关闭流
	public void myClose() throws IOException{
		is.close();
	}
}

//使用自定义的缓冲区copy Mp3
	public static void myCopyMp3() throws IOException{
		
		MyBufferedInputStream mbis = new MyBufferedInputStream(new FileInputStream("G:\\TestFolder\\mp3.mp3"));
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("G:\\TestFolder\\mp3_copy.mp3"));
		
		int bt = 0;
		//read方法在提升,write方法在截取
		while((bt = mbis.myRead()) != -1){
			//write只将最低8位写入硬盘,所以虽然myRead方法提升为4个字节,但最终写入的数据与原来的数据一致
			bos.write(bt);
		}
		
		bos.close();
		mbis.myClose();
	}

4、读取键盘录入

System.out:对应的是标准输出设备,控制台。System.in:对应的是标准输入设备,键盘。下面是一个读取键盘录入的例子:

//通过键盘录入一行数据并打印,其实就是读一行数据的原理
	public static void readKeyBoard() throws IOException{
		
		InputStream in = System.in;
		StringBuffer sb = new StringBuffer();
		while(true){
			int ch = in.read();
			if(ch == '\r')
				continue;
			if(ch == '\n'){
				String s = sb.toString();
				if(s.equals("end"))
					break;
				P.rintln(s.toUpperCase());
				sb.delete(0, sb.length());	//清空缓冲区
			}
			else{
				sb.append((char)ch);
			}
		}
	}
5、使用转换流

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

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

下面是一个使用InputStreamReader和OutputStreamWriter 2个转换流的例子,以及一些要点说明:

//readLine方法是字符流BufferedReader类中的方法。
	//而键盘录入的read方法是字节流InputStream的方法
	//下面是将字节流转换成字符流再使用字符流缓冲区的readLine方法
	public static void useTransformStream() throws IOException{
		
		//获取键盘录入对象
//		InputStream in = System.in;
//		//将字节流对象转换为字符流对象,使用转换流:InputStreamReader
//		InputStreamReader isr = new InputStreamReader(in);
//		//为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader
//		BufferedReader br = new BufferedReader(isr);
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));	//简写
		
//		OutputStream out = System.out;
//		OutputStreamWriter osw = new OutputStreamWriter(out);
//		BufferedWriter bw = new BufferedWriter(osw);
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));		//简写
		
		String str = null;
		while((str = br.readLine()) != null){
			if("end".equals(str))
				break;
//			P.rintln(str.toUpperCase);
			bw.write(str.toUpperCase());
			bw.newLine();
			bw.flush();
		}
		
		br.close();
		
	}
转换流是字符和字节之间的桥梁,通常,涉及到字符编码转换时,需要用到转换流。

public static void assignCode() throws IOException{		//指定文本的输出格式
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		//指定输出文本的编码格式
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("G:\\TestFolder\\a.txt"), "UTF-8"));
		//FileWriter是OutputStreamWriter的子类,其中已经封装了字符的编码格式
		BufferedWriter bw2 = new BufferedWriter(new FileWriter("G:\\TestFolder\\b.txt"));
		
		String line = null;
		while((line = br.readLine()) != null){
			if("end".equals(line))
				break;
			bw.write(line);
			bw2.write(line);
			bw.newLine();
			bw2.newLine();
			bw.flush();
			bw2.flush();
		}
		
		br.close();
		bw.close();
		bw2.close();
	}

流操作的基本规律:通过三个明确来完成
1:明确源和目的
源:输入流 InputStream Reader
目的:输出流 OutputStream Writer
2:操作的数据是否是纯文本
是:字符流
不是:字节流
3:当体系明确后,在明确要使用哪个具体对象。
通过设备来进行区分:
原设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台

6、自定义标准输入输出流

可以使用System类提供的setIn()和setOut()方法自定义标准输入输出流,以下为一个简单测试

public static void changeInOut() throws IOException{
		
		System.setIn(new FileInputStream("G:\\TestFolder\\InOutStuInfo.java"));		//自定义标准输入流
		System.setOut(new PrintStream("G:\\TestFolder\\Demo.java"));			//自定义标准输出流
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		
		String line = null;
		while((line = br.readLine()) != null){
			bw.write(line);
			bw.newLine();
			bw.flush();
		}
		
		br.close();
		bw.close();
	}
------- android培训java培训、期待与您交流! ----------详细请查看: www.itheima.com
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值