黑马程序员——Java基础—IO流(二)
2015-04-11 19:48
501 查看
———Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ———
一OutputStream类
二InputStream类
三字节流练习
四字节流缓冲区
五键盘录入
六转换流
IO流(二)
字节流
2.FileOutputStream类
示例代码:
该程序在指定目录创建
注意:
字节输出流在直接使用的时候不需要调用flush()方法,与字符流不用。由于字符流底层操作的也是字节,同时用的是字节流的缓冲区;该缓冲区中有个数组,用于临时存储数据。要将数组中的数据写入目的地文件,字符流就需要调用flush()方法进行刷新。而字节输出流是对最小单位字节直接进行操作,没有使用具体缓冲区,所以不需要刷新,直接往目的地文件写入数据。
2.FileInputStream类
示例代码:
程序输出结果:
注意:
如果使用字节输入流读取的文件较大,建议使用1024字节整数倍方法读入数据,而不要使用创建available()方法返回值大小的数组;后者可能造成内存溢出
示例代码:
字节流缓冲区对应
2.缓冲区应用
1)用缓冲区拷贝一个Mp3文件
示例代码:
程序输出结果:
2)自定义缓冲区
假设内存中字节数组的大小定义为
要自定义缓冲区,需要定义一个字节数组,两个变量(指针和计数器)。
示例代码:
问题:
上面的代码运行结果只拷贝了
原因:
是因为媒体文件在硬盘上的数据以二进制形式存在;
理解BufferedInputStream的read()方法:
细看BufferedInputStream类的read()方法,其返回的是int类型。而方法中读到的字节都是byte类型;这样做的原因,就是为了解决读取字节读到8个1的情况。read()方法在返回byte类型字节数据的时候,将byte类型提升为int类型,存储位数由1个8位,变为4个8位。为了确保返回的数据与原数据相同而不产生-1的情况,read()方法在类型提升之后,补了3个8位的0在原byte数据前面。过程如下图:
在自定义缓冲区中,虽然方法返回了
将每个return ch;语句改为return ch & 255;即可。
System.out-标准输出流
System.in-标准输入流
2.接收键盘录入
从键盘接收输入,并打印在控制台。
示例代码:
程序输出结果:
3.练习
接收键盘录入,当回车时打印整行内容;当输入
示例代码:
利用转换流修改键盘录入并打印的代码:
将字节流转换为字符流,相当于在字节流上套了两根管子;一根使字节流变成字符流;另一根使字节流可以使用字符流的缓冲技术。
2.OutputStreamWriter类
用OutputStreamWriter类修改上面的代码:
可以将字节流转字符流的三个步骤简化为一行代码:
3.转换流的作用
转换流可以指定读写时使用的字符编码集;如不指定,将使用系统默认的编码集,本机默认使用
示例代码:
程序输出结果:
为了正常显示,用InputStreamReader指定读取时编码集为UTF-8即可
程序输出结果:
小扩展
使用System类的方法setIn()和setOut()改变标准输入输出。
示例代码:
———Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ———
一OutputStream类
二InputStream类
三字节流练习
四字节流缓冲区
五键盘录入
六转换流
IO流(二)
字节流
一、OutputStream类
1.概述OutputStream类可以在硬盘上创建一个文件,并写入或添加数据。该类的子类还能实现写入过程中的不同功能。
2.FileOutputStream类
FileOutputStream类用于在硬盘上创建文件,并以字节的形式写入数据。其使用方式和
FileWriter类相似,只是以字节的形式操作数据。下面的代码在指定目录创建一个文件并写入自定义数据。
示例代码:
package com.heisejiuhuche.io; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class FileOutputStreamDemo { public static void main(String[] args) { FileOutputStream fos = null; try { /* 创建FileOutputStream对象并关联文件 */ fos = new FileOutputStream("C:/Users/jeremy/Documents/javaTmp/fos.txt"); /* 写入数据,通过String类的getBytes方法将字符串转换为字节数组 */ fos.write("abcdefg".getBytes()); } catch(FileNotFoundException e) { throw new RuntimeException("文件不存在"); } catch(IOException e) { throw new RuntimeException("操作失败"); } finally { try { if(fos != null) fos.close(); } catch(IOException e) { throw new RuntimeException("输出流关闭失败"); } } } }
该程序在指定目录创建
fos.txt并写入
abcdefg
注意:
字节输出流在直接使用的时候不需要调用flush()方法,与字符流不用。由于字符流底层操作的也是字节,同时用的是字节流的缓冲区;该缓冲区中有个数组,用于临时存储数据。要将数组中的数据写入目的地文件,字符流就需要调用flush()方法进行刷新。而字节输出流是对最小单位字节直接进行操作,没有使用具体缓冲区,所以不需要刷新,直接往目的地文件写入数据。
二、InputStream类
1.概述InputStream类以字节形式读取硬盘上的文件数据。该类的子类还能实现读取过程中的不同功能。
2.FileInputStream类
FileInputStream类用于以字节形式读取文件数据。其特有的方法使创建字节数组有了明确的大小。该类的使用方式和
FileReader相似。下面的代码读取文件中的数据。
示例代码:
package com.heisejiuhuche.io; import java.io.FileInputStream; import java.io.IOException; public class FileInputStreamDemo { public static void main(String[] args) throws IOException { read_1(); System.out.println(); read_2(); read_3(); } private static void read_3() throws IOException { FileInputStream fis = new FileInputStream("C:/Users/jeremy/Documents/javaTmp/fos.txt"); /* available方法返回文件的大小 */ byte[] buf = new byte[fis.available()]; fis.read(buf); System.out.println("read_3: " + new String(buf)); } private static void read_2() throws IOException { FileInputStream fis = new FileInputStream("C:/Users/jeremy/Documents/javaTmp/fos.txt"); byte[] buf = new byte[1024]; int len = 0; while((len = fis.read(buf)) != -1) { System.out.println("read_2: " + new String(buf, 0, len)); } } private static void read_1() throws IOException { FileInputStream fis = new FileInputStream("C:/Users/jeremy/Documents/javaTmp/fos.txt"); int ch = 0; System.out.print("read_1: "); while((ch = fis.read()) != -1) { System.out.print((char)ch); } } }
程序输出结果:
read_1: abcdefg read_2: abcdefg read_3: abcdefg
注意:
如果使用字节输入流读取的文件较大,建议使用1024字节整数倍方法读入数据,而不要使用创建available()方法返回值大小的数组;后者可能造成内存溢出
三、字节流练习
1.拷贝图片到指定目录示例代码:
package com.heisejiuhuche.io; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class PicCopy { public static void main(String[] args) { picCopy(); } private static void picCopy() { FileInputStream fis = null; FileOutputStream fos = null; try { /* 创建输入输出流并关联文件 */ fos = new FileOutputStream("C:/Users/jeremy/Documents/me.jpg"); fis = new FileInputStream("C:/Users/jeremy/Documents/javaTmp/me.jpg"); /* 创建缓冲区 */ byte[] buf = new byte[1024]; int len = 0; /* 复制文件 */ while((len = fis.read(buf)) != -1) { fos.write(buf, 0, len); } } catch(FileNotFoundException e) { throw new RuntimeException("文件不存在"); } catch(IOException e) { throw new RuntimeException("复制失败"); } finally { try { if(fis != null) fis.close(); } catch(IOException e) { throw new RuntimeException("输入流关闭失败"); } try { if(fos != null) fos.close(); } catch(IOException e) { throw new RuntimeException("输出流关闭失败"); } } } }
四、字节流缓冲区
1.缓冲区对应的类字节流缓冲区对应
BufferedOuputStream类和
BufferedInputStream类。
2.缓冲区应用
1)用缓冲区拷贝一个Mp3文件
示例代码:
package com.heisejiuhuche.io; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class CopyMp3Demo { public static void main(String[] args) throws IOException { long start = System.currentTimeMillis(); copy(); long end = System.currentTimeMillis(); System.out.println((end - start) + "毫秒"); } private static void copy() throws IOException { /* 创建Buffered缓冲区对象并关联文件 */ BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream( "C:/Users/jeremy/Documents/javaTmp/back.mp3")); BufferedInputStream bufis = new BufferedInputStream(new FileInputStream( "C:\\Users\\jeremy\\Music\\BaiduMusic\\Songs\\Backseat Serenade - All Time Low,Cassadee Pope.mp3")); int ch = 0; /* 复制文件 */ while((ch = bufis.read()) != -1) { bufos.write(ch); } } }
程序输出结果:
136毫秒
2)自定义缓冲区
假设内存中字节数组的大小定义为
1024字节;那么字节流缓冲区在工作时,首先由
FileInputStream从硬盘抓取
1024字节的数据存入字节数组,然后由
BufferedInputStream的
read()方法依次一个字节一个字节读取。缓冲区中有两个控制读取过程的变量,分别是数组的索引指针,和一个计数器。下标用于控制不断读取下一个字节,计数器用于控制下一次从硬盘抓数据存入缓冲区数组的时间。
read()方法每读取一个字节,指针右移一位,计数器自减
1;当计数器减至0的时候,意味着数组中已经没有字节可读,这时再由
FileInputStream从硬盘抓取
1024个字节存入数组,指针归零,计数器回到
1024,再次进行以上步骤的循环,直至硬盘数据全部被抓取。
要自定义缓冲区,需要定义一个字节数组,两个变量(指针和计数器)。
示例代码:
package com.heisejiuhuche.io; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class MyBufferedInputStreamDemo { public static void main(String[] args) throws IOException { long start = System.currentTimeMillis(); copy(); long end = System.currentTimeMillis(); System.out.println((end - start) + "毫秒"); } private static void copy() throws IOException { /* 创建Buffered缓冲区对象并关联文件 */ BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream( "C:/Users/jeremy/Documents/javaTmp/back.mp3")); MyBufferedInputStream bufis = new MyBufferedInputStream(new FileInputStream( "C:\\Users\\jeremy\\Music\\BaiduMusic\\Songs\\Backseat Serenade - All Time Low,Cassadee Pope.mp3")); int ch = 0; /* 复制文件 */ while((ch = bufis.read()) != -1) { bufos.write(ch); } bufos.close(); bufis.close(); } } class MyBufferedInputStream { private FileInputStream fis; private int pos; private int count; private byte ch; private byte[] buf = new byte[1024]; MyBufferedInputStream(FileInputStream fis) { this.fis = fis; } public int read() throws IOException { /* 如果count=0了,继续抓取数据到缓冲区数组 */ if(count == 0) { /* 抓取数据后,count回到1024 */ count = fis.read(buf); /* 读到文件末尾,fis的read()方法返回-1,必须判断如果count < 0,说明读到了最后 */ if(count < 0) { return -1; } /* 抓取数据后指针归0 */ pos = 0; /* 取出第一个字节 */ ch = buf[pos]; /* 每取一个数据,指针+1,右移 */ pos++; /* 每取一个数据,count-1 */ count--; /* 返回第一个字节 */ return ch; } else if(count > 0) { ch = buf[pos]; pos++; count--; /* 返回第一个字节后的每一个字节 */ return ch; } /* 读完文件,返回-1 */ return -1; } public void close() throws IOException { fis.close(); } }
问题:
上面的代码运行结果只拷贝了
8K到目的文件。
原因:
是因为媒体文件在硬盘上的数据以二进制形式存在;
read()方法在读取第一个字节的时候,有可能会读到:
11111111;这样8个1的情况;而8个1的的二进制就是十进制的
-1;程序中
while循环的跳进等于
-1时,循环停止;因此只复制了8K大小。
理解BufferedInputStream的read()方法:
细看BufferedInputStream类的read()方法,其返回的是int类型。而方法中读到的字节都是byte类型;这样做的原因,就是为了解决读取字节读到8个1的情况。read()方法在返回byte类型字节数据的时候,将byte类型提升为int类型,存储位数由1个8位,变为4个8位。为了确保返回的数据与原数据相同而不产生-1的情况,read()方法在类型提升之后,补了3个8位的0在原byte数据前面。过程如下图:
在自定义缓冲区中,虽然方法返回了
int类型,进行了数据类型提升,但是没有进行补
0的操作,意味着当读到8个1组成的
byte数据时,返回了一个由32个1组成的
int类型数据,结果还是
-1。那么,如果要完成相同功能,只需取32个1的最后
8位即可。取最后8位,将原数据与上
255。
将每个return ch;语句改为return ch & 255;即可。
五、键盘录入
1.System标准输出输入System类中对应的成员
out和
in分别是:
System.out-标准输出流
System.in-标准输入流
System.in用于读取键盘录入。
2.接收键盘录入
从键盘接收输入,并打印在控制台。
示例代码:
package com.heisejiuhuche.io; import java.io.IOException; import java.io.InputStream; public class SysteminDemo { public static void main(String[] args) { /* 创建标准输入对象 */ InputStream in = System.in; try { /* 录入一个字符 */ int ch = in.read(); /* 打印该字符的ASCII码 */ System.out.println(in.read()); } catch(IOException e) { throw new RuntimeException("运行出错~"); } } }
程序输出结果:
a 97
3.练习
接收键盘录入,当回车时打印整行内容;当输入
over回车时,结束输入。
示例代码:
package com.heisejiuhuche.io; import java.io.IOException; import java.io.InputStream; public class SysteminDemo { public static void main(String[] args) { InputStream in = System.in; StringBuilder sb = new StringBuilder(); int ch = 0; try { /* 一直读入字符,每输入一个字符,就往StringBuilder添加一个; * 如果读到回车符,继续读入; * 如果读到换行符,将StringBuilder中的字符组成字符串 * 判断该字符串是否等于over,如果是,结束程序; * 如果不是,就打印该字符串,并将StringBuilder容器清空 */ while(true) { ch = in.read(); if(ch == 13) continue; if(ch == 10) { String str = sb.toString(); if(str.equals("over")) { break; } System.out.println(str); sb.delete(0, sb.length()); } else sb.append((char)ch); } } catch(IOException e) { throw new RuntimeException("运行出错~"); } } }
六、转换流
1.InputStreamReader类InputStreamReader类用于将字节流转换为字符流。该类可以将读取到的字节数据转换为字符数据。其使用的编码表可以由开发者指定,也可以使用系统默认。利用转换流将字节流转换为字符流,就意味着该字节流可以使用字符流的缓冲区技术,调用其
readLine()方法,使键盘录入的读取过程更加高效便捷。
利用转换流修改键盘录入并打印的代码:
package com.heisejiuhuche.io; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; public class InputStreamReaderDemo { public static void main(String[] args) { /* 创建标准输入对象 */ InputStream in = System.in; /* 利用转换流将字节流转换为字符流 */ InputStreamReader isr = new InputStreamReader(in); /* 转换后的字节流,就可以像字符流一样使用字符流的缓冲技术 */ BufferedReader bufr = new BufferedReader(isr); /* 调用BufferedReader的readLine()方法整行获取键盘录入 */ String line = null; try { while((line = bufr.readLine()) != null) { /* 如果输入over 结束键盘录入 */ if(line.equals("over")) break; System.out.println(line.toUpperCase()); } } catch(IOException e) { throw new RuntimeException("Exception occured..."); } } }
将字节流转换为字符流,相当于在字节流上套了两根管子;一根使字节流变成字符流;另一根使字节流可以使用字符流的缓冲技术。
2.OutputStreamWriter类
OutputStreamWriter类用于将字符流转换为字节流。该类的编码表同样可以指定或使用系统默认。
用OutputStreamWriter类修改上面的代码:
package com.heisejiuhuche.io; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; public class InputStreamReaderDemo { public static void main(String[] args) { InputStream in = System.in; InputStreamReader isr = new InputStreamReader(in); BufferedReader bufr = new BufferedReader(isr); /* 创建标准输出对象 */ OutputStream out = System.out; /* 用转换流将字符流转换为字节流 */ OutputStreamWriter osw = new OutputStreamWriter(out); /* 使用缓冲字符输出流增强字符输出流 */ BufferedWriter bufw = new BufferedWriter(osw); String line = null; try { while((line = bufr.readLine()) != null) { /* 如果输入over 结束键盘录入 */ if(line.equals("over")) break; bufw.write(line.toUpperCase()); bufw.newLine(); bufw.flush(); } } catch(IOException e) { throw new RuntimeException("Exception occured..."); } finally { try { if(bufw != null) bufw.close(); } catch(IOException e) { throw new RuntimeException("资源关闭失败"); } } } }
可以将字节流转字符流的三个步骤简化为一行代码:
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
3.转换流的作用
转换流可以指定读写时使用的字符编码集;如不指定,将使用系统默认的编码集,本机默认使用
GBK。下面的代码演示了用
UTF-8写入,用
GBK读取会发生乱码的情况。
示例代码:
package com.heisejiuhuche.io; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; public class CharSetDemo { public static void main(String[] args) { write(); } private static void read() { BufferedReader bufr = null; try { /* 使用默认GBK字符集读取数据,结果会出现乱码 */ bufr = new BufferedReader(new FileReader("C:/Users/jeremy/Documents/javaTmp/demo.txt")); System.out.println(bufr.readLine()); } catch(FileNotFoundException e) { e.printStackTrace(); } catch(IOException e) { e.printStackTrace(); } finally { try { if(bufr != null) bufr.close(); } catch(IOException e) { e.printStackTrace(); } } } private static void write() { InputStreamReader isr = null; OutputStreamWriter osw = null; BufferedReader bufr = null; BufferedWriter bufw = null; String line = null; try { bufr = new BufferedReader(new InputStreamReader(System.in)); /* 指定使用UTF-8字符集写入数据 */ bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream( "C:/Users/jeremy/Documents/javaTmp/demo.txt"),"UTF-8")); while((line = bufr.readLine()) != null) { if(line.equals("over")) { break; } bufw.write(line); bufw.newLine(); bufw.flush(); } /* 将写入的数据读取打印在控制台 */ read(); } catch(FileNotFoundException e) { e.printStackTrace(); } catch(IOException e) { e.printStackTrace(); } finally { try { if(bufr != null) bufr.close(); } catch(IOException e) { e.printStackTrace(); } try { if(bufw != null) bufw.close(); } catch(IOException e) { e.printStackTrace(); } } } }
程序输出结果:
你好,这里是虹桥镇~ over 浣犲ソ锛岃繖閲屾槸铏规ˉ闀噡
为了正常显示,用InputStreamReader指定读取时编码集为UTF-8即可
bufr = new BufferedReader(new InputStreamReader(new FileInputStream( "C:/Users/jeremy/Documents/javaTmp/demo.txt"),"UTF-8"));
程序输出结果:
你好,这里是虹桥镇~ over 你好,这里是虹桥镇~
小扩展
使用System类的方法setIn()和setOut()改变标准输入输出。
示例代码:
package com.heisejiuhuche.io; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; public class SystemSetDemo { public static void main(String[] args) throws IOException { BufferedReader bufr = null; BufferedWriter bufw = null; /* 改变标准输入源,从键盘变为指定目录的文件 */ System.setIn(new FileInputStream("C:/Users/jeremy/Documents/javaTmp/fos.txt")); /* 改变标准输出目的地,从控制台变为指定目录的文件 */ System.setOut(new PrintStream("C:/Users/jeremy/Documents/javaTmp/fos1.txt")); bufr = new BufferedReader(new InputStreamReader(System.in)); bufw = new BufferedWriter(new OutputStreamWriter(System.out)); String line = bufr.readLine(); bufw.write(line); bufw.flush(); bufr.close(); bufw.close(); } }
———Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ———
相关文章推荐
- 黑马程序员---Java基础--19天(IO流之二)
- 黑马程序员-Java语言基础 – IO流 第20-21天
- 黑马程序员 java基础<四>--IO流(2)
- 黑马程序员-JAVA基础-IO流之File 类
- 黑马程序员-JAVA基础-IO流之字符流和字符流缓冲区
- 黑马程序员---Java基础--20天(IO流之三)
- 黑马程序员_java基础视频第18天_与系统交互的类及IO流
- 黑马程序员 java基础<三>--IO流(1)
- 黑马程序员-JAVA基础-IO流之字节流和字节流缓冲区
- 黑马程序员--JAVA基础教程第18天(下)IO流
- 黑马程序员-Java语言基础– IO流 第18天
- 黑马程序员-java基础8--IO流(一)
- 黑马程序员_Java基础_其它对象和IO流(字符流)
- 黑马程序员 java基础<五>--IO流(3)
- 黑马程序员—10、Java基础&IO流
- 黑马程序员-Java语言基础– IO流 第19天
- 黑马程序员_Java基础_IO流(File类和properties类相关操作)
- 黑马程序员_Java基础_IO流(对象序列化和字符编码)
- 黑马程序员-JAVA基础-IO流之流操作规律及读写转换流
- 黑马程序员 java基础<六>--IO流(4)