黑马程序员:字节流的介绍:InputStream、OutputStream

时间:2023-02-16 17:56:14

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

字节流:InputStream(读)、OutputStream(写)


字节流操作的时候没有刷新动作,因为字节是操作最小单位,而字符流需要刷新是
因为有缓冲机制,因为一个汉字两个字节,半个汉字不能输出,所以先进入缓冲区,
再输出,所以需要刷新

但是不管是字节流还是字符流,都要关闭资源 close()

FileInputStream特有方法:
  int available()  读取文件字节流对象中的字节数  特殊注意:\r\n算一个字节
  该方法可以有利于我们定义一个大小刚刚好的缓冲区,不用再循环读取数据了
  但是这种方法使用在数据较小的地方,要是很大的数据,比如一部电影,1.5G。就不适合用,
  JVM默认内存是64M,虽然可以设置更多,但是怎么也装不下1.5G。容易发生内存溢出异常
 
字节流练习题:
复制一个图片
思路:
1.用字节读取流对象和图片关联
2.用字节写入流对象创建一个图片文件,用于存储获取到的图片数据
3.通过循环读写,完成数据的复制存储
4.关闭资源

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/*
 * 复制一个图片(字节流练习题)
 * 复制一个MP3文件
 */
public class StreamPicCopyTest {


	public static void main(String[] args) {
		// TODO Auto-generated method stub
		fileCopy("1.mp3","2.mp3");
	}
	public static void fileCopy(String fromfilename, String tofilename)
	{
		BufferedInputStream bfis = null;
		BufferedOutputStream bfos = null;
		try
		{
			bfis = new BufferedInputStream(new FileInputStream(fromfilename));
			bfos = new BufferedOutputStream(new FileOutputStream(tofilename));
			byte[] chs = new byte[1024];
			int len = 0;
			while((len=bfis.read(chs))!=-1)
			{
				bfos.write(chs,0,len);
			}
		}
		catch(IOException e)
		{
			throw new RuntimeException("文件复制失败");
		}
		 finally
		 {
			 try
			 {
				 if (bfis!=null)
					 bfis.close();
			 }
			 catch (IOException e)
			 {
				 throw new RuntimeException("文件关闭失败");
			 }
			 try
			 {
				 if (bfos!=null)
					 bfos.close();
			 }
			 catch (IOException e)
			 {
				 throw new RuntimeException("文件关闭失败");
			 }
		 }
//		int ch = 0;
//		while((ch=bfis.read())!=-1)
//		{
//			bfos.write((char)ch);
//		}
		
	}
	


}

字节流缓冲区
字节流缓冲区原理:
FileInputStream会在硬盘文件上读取一批数据到BufferedInputStream中,调用者获取一个字节,就从缓冲区中取一个字节,当缓冲区中的数据被取完了的时候,FileInputStream又会从硬盘文件中读取一批数据到缓冲区中,依次进行下去。
read()底层原理和write()底层原理区别:
read()在底层读取的时候返回int是在做了数据类型提升 
若返回的类型是byte的话,那这个1个字节(8位)是 1111 1111 (十进制就是-1),导致程序无法判断文件中是否还有数据(read()==-1则认为数据读取结束),所以就要提升到int,而直接提升int的话值就是 11111111-11111111-11111111-11111111(十进制-1)
,而在用while(buf.read()!=-1)(判断是否还有数据)的时候,因在提升为int的时候还是-1,所以导致循环不进行从到导致循环内部的写入语句不执行从而导致复制失败,所以这个时候,read()在底层的原理是返回的int型数据&上11111111(十进制255),这样既返回了字节原有的数据(8个1),又可以避免-1的出现。这才是我们见到的read()返回值
                            
  11111111 11111111 11111111 11111111
&      11111111
====================================
 00000000 00000000 00000000 11111111
write()在底层写入数据的时候是在做数据强转(byte)data,因为read()返回的数据是经过类型提升为int的数据,并且还做过与运算,如上例所示,read()的结果00000000 00000000 00000000 11111111(255),被write()由int型(占4个8位)转换为byte型(占1个8位)后就成了11111111(-1)


代码说明:


import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;


/*
 * BufferedInputStream原理代码
 * FileInputStream会在硬盘文件上读取一批数据到BufferedInputStream中,
 * 调用者获取一个字节,就从缓冲区中取一个字节,当缓冲区中的数据被取完了的时候,
 * FileInputStream又会从硬盘文件中读取一批数据到缓冲区中,依次进行下去。
 */
public class BufferedInputStreamPrinciple {


	public static void main(String[] args) {
		// TODO Auto-generated method stub
		long start=System.currentTimeMillis();
		copy();
		long end = System.currentTimeMillis();
		System.out.println((end-start)+"毫秒");
		
	}
	public static void copy()
	{
		MyBufferedInputStream mfis = null;
		BufferedOutputStream bfos = null;
		try
		{
			mfis = new MyBufferedInputStream(new FileInputStream("1.mp3"));
			bfos = new BufferedOutputStream(new FileOutputStream("3.mp3"));
			int a = 0;
			while((a=mfis.myRead())!=-1)
			{
				bfos.write(a);
			}
		}
		catch(IOException e)
		{
			throw new RuntimeException("复制失败");
		}
		finally
		{
			try
			{
				if(mfis!=null)
					mfis.myClose();
			}
			catch(IOException i)
			{
				throw new RuntimeException("原文件关闭失败");
			}
			try
			{
				if(bfos!=null)
					bfos.close();
			}
			catch(IOException i)
			{
				throw new RuntimeException("目标文件关闭失败");
			}
		}
	}


}
class MyBufferedInputStream
{
	private InputStream fi;
	private int count=0,pos=0;
	private byte[] bys = new byte[1024*4];
	MyBufferedInputStream(InputStream fi)
	{
		this.fi = fi;
	}
	public int myRead() throws IOException
	{
		
		if (count==0)
		{
			count = fi.read(bys);
			if(count<0)
				return -1;
			pos = 0;
			byte b = bys[pos];
			count--;
			pos++;
			return b&255;
		}
		if(count>0)
		{
			byte b = bys[pos];
			count--;
			pos++;
			return b&0xff; //0xff 255的16进制值
		}
		return -1;
		
		
	}
	public void myClose() throws IOException
	{
		fi.close();
	}
	
}

将异常信息存入到文档中

import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;


/*
 * 将异常信息存入到文档中
 */
public class ExceptionReport {


	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		try
		{
			int[] in = new int[3];
			System.out.println(in[4]);
		}
		catch(Exception e)
		{
			FileOutputStream fos = null;
			try
			{
				Date d = new Date();
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				String time = sdf.format(d);
				fos = new FileOutputStream("exception_log.txt",true);
				fos.write(time.toString().getBytes());
				fos.write(e.toString().getBytes());
				fos.write(13);
			}
			catch(IOException i)
			{
				throw new RuntimeException("异常信息文件创建失败");
			}
			finally
			{
				try
				{
					if(fos!=null)
						fos.close();
				}
				catch(IOException io)
				{
					throw new RuntimeException("异常信息文件关闭失败");
				}
			}
			
		}
	}


}

获取系统信息并保存到文件中

Properties p = System.getProperties();
p.list(new PrintStream("properties.txt"));

键盘录入
InputStream in = System.in;
BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
int ch = 0;

System.out.println((char)ch);

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------详细请查看:http://edu.csdn.net