标签:
------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
字节流
一、概述
1、字节流和字符流的基本操作是相同的,但字节流还可以操作其他媒体文件。
2、由于媒体文件数据中都是以字节存储的,所以,字节流对象可直接对媒体文件的数据写入到文件中,而可以不用再进行刷流动作。
3、读写字节流:InputStream 输入流(读)
OutputStream 输出流(写)
4、为何不用进行刷流动作:
因为字节流操作的是字节,即数据的最小单位,不需要像字符流一样要进行转换为字节。所以可直接将字节数据写入到指定文件中。
5、InputStream特有方法:
int available();//返回文件中的字节个数
注:可以利用此方法来指定读取方式中传入数组的长度,从而省去循环判断。但是如果文件较大,而虚拟机启动分配的默认内存一般为64M。当文件过大时,此数组长度所占内存空间就会溢出。所以,此方法慎用,当文件不大时,可以使用。
示例
1 /* 2 复制一个图片 3 思路: 4 1,用字节读取流对象和图片关联。 5 2,用字节写入流对象创建一个图片文件。用于存储获取到的图片数据。 6 3,通过循环读写,完成数据的存储。 7 4,关闭资源。 8 9 */ 10 11 import java.io.*; 12 class CopyPic 13 { 14 public static void main(String[] args) 15 { 16 FileOutputStream fos = null;//建立字节文件写入流 17 FileInputStream fis = null;//建立字节文件读取流 18 try 19 { 20 fos = new FileOutputStream("c:\\1.jpg");//关联文件 21 fis = new FileInputStream("1.jpg");//关联文件 22 23 byte[] buf = new byte[1024]; 24 25 int len = 0; 26 27 while((len=fis.read(buf))!=-1)//缓冲区提供的 一次读一行的方法,只要不读到末尾 28 { 29 //fos.write(buf[0]); 30 fos.write(buf,0,len); 31 } 32 } 33 catch (IOException e) 34 { 35 throw new RuntimeException("复制文件失败"); 36 } 37 finally 38 { 39 try 40 { 41 if(fis!=null) 42 fis.close();//读取流不为空,则关闭 读取流 43 } 44 catch (IOException e) 45 { 46 throw new RuntimeException("读取关闭失败"); 47 } 48 try 49 { 50 if(fos!=null) 51 fos.close();//写入流不为空,则关闭写入流 52 } 53 catch (IOException e) 54 { 55 throw new RuntimeException("写入关闭失败"); 56 } 57 } 58 } 59 }
二、字节流缓冲区
同样是提高了字节流的读写效率。
1、读写特点:
read():会将字节byte型值提升为int型值
write():会将int型强转为byte型,即保留二进制数的最后八位。
2、原理:将数据拷贝一部分,读取一部分,循环,直到数据全部读取完毕。
1)先从数据中抓取固定数组长度的字节,存入定义的数组中,再通过然后再通过read()方法读取数组中的元素,存入缓冲区。
2)循环这个动作,直到最后取出一组数据存入数组,可能数组并未填满,同样也取出包含的元素。
3)每次取出的时候,都有一个指针在移动,取到数组结尾就自动回到数组头部,这样指针在自增。
4)取出的时候,数组中的元素在减少,取出一个,就减少一个,直到减到0即元素取完。
5)当文件中的全部数据都被读取出时,read()方法就返回-1。
3、自定义读取字节流缓冲区
需求:根据字节流缓冲区的原理,自定义一个字节流缓冲区。
注意:
1、字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。
因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1.那么就会数据还没有读完,就结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。
所以,为了避免这种情况将读到的字节进行int类型的提升。并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值。而在写入数据时,只写该int类型数据的最低8位。
2、byte类型的-1提升为int类型时还是-1。原因:因为在bit8个1前面补的全是1导致的。如果在bit8个1前面补0,即可以保留原字节数据不变,又可以避免-1的出现。这时将byte型数据&0xff即255即可。
代码:
1 /* 2 演示MP3的复制,通过缓冲区 3 BufferedOutputStream 4 BufferedInputStream 5 */ 6 import java.io.*; 7 class MyBufferedInputStream 8 { 9 private InputStream in; 10 11 private byte[] buf = new byte[1024*4];//自定义缓冲区 为字节数组 12 13 private int pos = 0,count = 0; //pos 确认数组的位置,方便存储,count确认输入的个数, 14 15 MyBufferedInputStream(InputStream in) 16 { 17 this.in = in; 18 } 19 20 //一次读一个字节,从缓冲区(字节数组)获取。 21 public int myRead()throws IOException//字节流返回值类型为int,一次读一个的方法读取硬盘上数据,并存储buf中。 22 { 23 24 if(count==0) 25 { 26 count = in.read(buf);//计数 键盘录入的个数 27 if(count<0) //当count为零时, 说明已存储完成 28 return -1; 29 pos = 0; 30 byte b = buf[pos]; // 31 32 count--; 33 pos++; 34 return b&255;//返回的byte类型提升为int类型,字节数增加,且高24位被补1,原字节数据改变。 35 //通过与上255,主动将byte类型提升为int类型,将高24位补0,原字节数据不变。 36 //而在输出字节流写入数据时,只写该int类型数据的最低8位。 37 } 38 else if(count>0) 39 { 40 byte b = buf[pos]; 41 42 count--; 43 pos++; 44 return b&0xff;// 45 } 46 return -1; 47 48 } 49 public void myClose()throws IOException 50 { 51 in.close(); 52 } 53 } 54 class CopyMp3 55 { 56 public static void main(String[] args)throws IOException 57 { 58 long start =System.currentTimeMillis();//获取时间的毫秒数 59 copy_2(); 60 long end=System.currentTimeMillis(); 61 System.out.println((end-start)+"毫秒");//通过相减可以得出 用时 62 } 63 64 65 public static void copy_2()throws IOException //自定义缓冲区完成复制 66 { 67 MyBufferedInputStream bufis = new MyBufferedInputStream(new FileInputStream("1.mp3")); 68 BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\1.mp3")); 69 70 int by = 0; 71 72 //System.out.println("第一个字节:"+bufis.myRead()); 73 74 while((by=bufis.myRead())!=-1) 75 { 76 bufos.write(by); 77 } 78 79 bufos.close(); 80 bufis.myClose(); 81 } 82 83 public static void copy_1()throws IOException//通过字节流的缓冲区完成复制 84 { 85 BufferedInputStream bufis=new BufferedInputStream(new FileInputStream("1.mp3")); 86 BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("2.mp3")); 87 88 int by=0; 89 90 while((by=bufis.read())!=-1) 91 { 92 bufos.write(by); 93 } 94 bufos.close(); 95 bufis.close(); 96 97 } 98 }
流操作规律
一、键盘录入以及
1、标准输入输出流
System.in:对应的标准输入设备,键盘。
Ssytem.out:对应的是标准的输出设备,控制台。
System.in的类型是InputStream.
System.out的类型是PrintStream是OutputStream的子类FilterOutputStream的子类。
2、整行录入
当使用输入流进行键盘录入时,只能一个字节一个字节进行录入。为了提高效率,可以自定义一个数组将一行字节进行存储。当一行录入完毕,再将一行数据进行显示。这种正行录入的方式,和字符流读一行数据的原理是一样的。也就是readLine方法。
那么能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?readLine方法是字符流BufferedReader类中方法。而键盘录入的read方法是字节流InputStream的方法。
那么能不能将字节流转成字符流再使用字符流缓冲区的readLine方法呢?这就需要用到转换流了。
3、转换流
3.1 转换流的由来:
a、字符流与字节流之间的桥梁
b、方便了字符流与字节流之间的操作
转换流的应用:
字节流中的数据都是字符时,转成字符流操作更高效。
3.2 InputStreamReader将字节流通向字符流
a、获取键盘录入对象。
InputStream in=System.in;
b、将字节流对象转成字符流对象,使用转换流。
InputStreamReaderisr=new InputStreamReader(in);
c、为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader
BufferedReaderbr=new BufferedReader(isr);
//键盘录入最常见写法
BufferedReaderin=new BufferedReader(new InputStreamReader(System.in));
3.3 OutputStreamWriter字符流通向字节流
字符通向字节:录入的是字符,存到硬盘上的是字节。步骤和InputStreamReader转换流一样。
示例:
1 import java.io.*; 2 3 /* 4 1 5 源:键盘录入 6 目的:控制台 7 8 2 需求:想把键盘录入的数据存储到一个文件中 9 10 源: 键盘 11 目的: 文件 12 13 3 需求: 想要将一个文件的数据打印在控制台上 14 源: 文件 15 目的: 控制台 16 17 流操作的基本规律: 18 最痛苦的就是流对象有很多,不知道该用哪一个。 19 20 通过三个明确来完成。 21 1 明确源和目的、 22 源: 输入流。 InputStream Reader 23 目的: 输出流。 OutputStream Writer 24 2 操作的数据是否是纯文本。 25 是:字符流 26 不是: 字节流。 27 3 当体系明确后,在明确要使用哪个具体的对象。 28 通过设备来进行区分: 29 源设备: 内存,硬盘,键盘 30 目的设备: 内存,硬盘,控制台 31 32 1 将一个文本文件中数据存储到另一个文件中,复制文件。 33 源:因为是源,所以使用读取流。 InputStream Reader 34 是不是操作文本文件、 35 是! 这时 可以选择Reader 36 接下来明确使用该体系中的哪个对象 37 明确设备:硬盘。上的一个文件。 38 Reader 体系中可以操作文件的对象是 FileReader 39 是否需要高效: 是! 加入Reader体系中 缓冲区 BufferedReader 。 40 41 42 FileReader fr=new FileReader("a.txt"); 43 BufferedReader bufr=new BufferedReader(fr); 44 45 46 目的: OutputStream Writer 47 是不是纯文本。 48 是: Writer 49 设备: 硬盘,一个文件夹、 50 Writer体系中可以操作文件的对象 FileWriter 。 51 是否需要提高效率: 是! 加入Writer体系中缓冲区 BufferedWriter 。 52 53 FileWriter fw= new FileWriter("b.txt"); 54 BufferedWriter bufw=new BufferedWriter(fw); 55 56 练习: 将一个图片文件中数据存储到另一个文件中。复制文件。要按照以上格式自己完成三个明确 57 58 -------------------------------------------------------------------- 59 2 需求:将键盘录入的数据保存到一个文件中。 60 这个需求中有源和目的都存在 61 那么分别分析: 62 源: InputStream Reader 63 是不是纯文本? 是 Reader 64 65 设备: 键盘。对应的对象是 System.in 66 不是选择Reader么? System.in对应的不是字节流么? 67 68 为了操作键盘的文本数据方便。转成字符流按照字符串操作是最方便的。 69 所以既然明确了Reader,那么久将System.in转换成Reader。 70 用了Reader体系中转换流 InputStreamReader 71 InputStreamReader isr=new InputStreamReader(System.in); 72 73 需要提高效率么? 是 : BufferedReader 74 BufferedReader bufr=new BufferedReader(isr); 75 76 目的: OutputStream Writer 77 是否是纯文本? 是 ; Writer 78 设备:硬盘。 中的一个文件。 使用 FileWriter 79 80 FileWriter fw=new FileWriter("c.txt"); 81 需要提高效率么? 需要 82 BufferedWriter bufw=new BufferedWriter(fw); 83 84 85 86 ********************************* 87 扩展一下,想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。 88 89 目的: OutputStream Writer 90 是不是纯文本: 是 : Writer 91 设备:硬盘 中的一个文件 FileWriter 92 但是FileWriter是使用的默认编码表。 GBK 93 94 但是存储时,需要加入指定编码表utf-8.而指定的编码表只有转换流可以指定 95 96 所以要使用的对象是OutputStreamWriter。、 97 而该转换流要接收一个字节输出流。而且还可以操作文本的字节输出流。 FileOutputStream 98 99 OutputStreamWriter osw =new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8"); 100 101 需要高效么? 需要 102 BufferedWriter bufw =new BufferedWriter(osw); 103 所以,记住,转换流什么时候使用。字符和字节 之间的桥梁,通常,设计到字符编码转换时。 104 105 需要用到转换流。 106 107 108 练习: 将一个文本数据打印在控制台上。要按照以上格式自己完成三个明确。 109 110 */ 111 112 class TranStreamDemo2 113 { 114 public static void main(String[] args)throws IOException 115 { 116 System.setIn(new FileInputStream("PersonDemo.java")); 117 System.setOut(new PrintStream("zzz.txt")); 118 119 //获取键盘录入对象。 120 //InputStream in=System.in; 121 //将字节流对象转成字符流对象,使用转换流。 122 //InputStreamReader isr=new InputStreamReader(in); 123 //为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader 124 //BufferedReader br=new BufferedReader(isr); 125 126 //键盘录入最常见写法 127 BufferedReader in=new BufferedReader(new InputStreamReader(System.in)); 128 129 //字符流通向字节流 130 BufferedWriter bw =new BufferedWriter(new OutputStreamWriter(System.out)); 131 132 String s=null; 133 while((s=in.readLine())!=null) 134 { 135 if("over".equals(s)) 136 break; 137 bw.write(s.toUpperCase());//写入数据 138 bw.newLine();//换行 139 bw.flush();//刷新 140 141 } 142 bw.close();//关闭流资源 143 in.close(); 144 } 145 } 146 }
小知识:
1、异常的日志信息:
当程序在执行的时候,出现的问题是不希望直接打印给用户看的,是需要作为文件存储起来,方便程序员查看,并及时调整的。
示例:
1 import java.io.*; 2 import java.text.*; 3 import java.util.*; 4 class ExceptionInfo 5 { 6 public static void main(String[] args) 7 { 8 try 9 { 10 int[] arr =new int[2]; 11 System.out.println(arr[3]); 12 13 } 14 catch (Exception e) 15 { 16 try 17 { 18 Date d=new Date();//创建时间对象 19 //时间模块格式对象 20 SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); 21 String s=sdf.format(d); 22 23 PrintStream ps=new PrintStream("info.log");//打印流对象 24 System.setOut(ps);//修改输出流设备 25 ps.println(s);//输出时间 26 27 } 28 catch (IOException ex) 29 { 30 throw new RuntimeException("文件创建失败"); 31 } 32 e.printStackTrace(System.out);//将异常信息输出指定输出流 33 } 34 } 35 }
2、系统属性信息存入文本
获取系统信息:
Properties getProperties()
将信息输出到指定输出流中
void list(PrintStream out)
将输出流中数据存入指定文件中
new PrintStream("systeminfo.txt")
示例:
import java.util.*; import java.io.*; class SystemInfo { public static void main(String[] args) { PrintStream ps = null; try { //获取系统信息: Properties pop = System.getProperties(); //创建输出流对象,将输出流中数据存入指定文件中 ps = new PrintStream("systeminfo.txt"); //将属性列表输出到指定的输出流 pop.list(ps); } catch (Exception e) { throw new RuntimeException("获取系统信息失败。"); } } }
3、通过System类的setIn,setOut方法可以对默认设备进行改变
System.setIn(newFileInputStream(“1.txt”));//将源改成文件1.txt。
System.setOut(newFileOutputStream(“2.txt”));//将目的改成文件2.txt
流的基本应用小结:
1 流是用来处理数据的。
2 处理数据时,一定要先明确数据源,与数据目的地(数据汇)。
3 数据源可以是文件,可以是键盘。
4 数据目的地可以是文件、显示器或者其他设备。
5 流只是在帮助数据进行传输,并对传输的数据进行处理,比如过滤处理.转换处理等。、
自我总结:
流是用来操作数据的,并不能操作文件文件夹(例如修改只读模式等),而操作数据必定需要关联数据源,或者关联数据目的。数据源可以是内存,硬盘,键盘,目的源可以是控制台,内存,硬盘。而流的操作需要中转站,可以是自定义的缓冲区,也可以是数据流里的缓冲区,其中IO流的缓冲区定义了一些方便我们操作的方法。字节流的操作范围较字符流会更广一些,它可以操作音乐图片等字节流数据。而字符流操作的是我们看的懂的字符。通过IO流我们可以实现,复制,也可以把流切成n段,还可以将n段整合成完整的文件。因此总的来说IO流的作用很大,实现了信息的传递。
黑马程序员——Java基础---IO(二)---IO字节流、流操作规律
标签:
原文地址:http://www.cnblogs.com/ktlshy/p/4713934.html