Java: IO 字符流
FileInputStream和FileOutputStream分别是InputStream和OutputStream的子类,都是字节流。下面例子中有三个方法可以读写字节流:
1.一个一个的
2.一组一组的,可以自定义字节数组的长度
3.使用available方法,可以返回目标文件的长度从而利用该特性建立一个刚刚好长度的字节数组。但该方法有使用风险,例如目标文件过大,一个电影或者一个大数据文件,则会导致超过虚拟机内存的大小,从而出现错误。所以使用该方法要评估风险,如果可以确定目标是小文件,则可以使用;否则,建议使用自定义长度的字节数组。
1 import java.io.*; 2 3 public class FileStream { 4 5 public static void main(String[] args) { 6 // FileOutputStreamDemo(); 7 // FileInputStreamDemo_1(); 8 // FileInputStreamDemo_2(); 9 FileInputStreamDemo_3(); 10 11 12 } 13 public static void FileOutputStreamDemo(){ 14 FileOutputStream fos = null; 15 try{ 16 fos = new FileOutputStream("FileStream.txt"); 17 fos.write("2015 Fighter together!".getBytes()); 18 } 19 catch(IOException e) 20 { 21 e.printStackTrace(); 22 } 23 finally{ 24 try{ 25 if(fos!=null) 26 fos.close(); 27 } 28 catch(IOException e){ 29 throw new RuntimeException("关闭写入失败"); 30 } 31 } 32 } 33 //read one bye one 34 public static void FileInputStreamDemo_1(){ 35 FileInputStream fis = null; 36 try{ 37 fis = new FileInputStream("FileStream.txt"); 38 int num = 0; 39 while((num=fis.read())!=-1){ 40 System.out.print((char)num); 41 } 42 } 43 catch(IOException e) 44 { 45 e.printStackTrace(); 46 } 47 finally{ 48 try{ 49 if(fis!=null) 50 fis.close(); 51 } 52 catch(IOException e){ 53 throw new RuntimeException("关闭读取失败"); 54 } 55 } 56 } 57 58 //read with a byte[] 59 public static void FileInputStreamDemo_2(){ 60 FileInputStream fis = null; 61 try{ 62 fis = new FileInputStream("FileStream.txt"); 63 byte[] buf = new byte[1024]; 64 int len = 0; 65 while((len=fis.read(buf))!=-1){ 66 System.out.println(new String(buf,0,len)); 67 } 68 } 69 catch(IOException e) 70 { 71 e.printStackTrace(); 72 } 73 finally{ 74 try{ 75 if(fis!=null) 76 fis.close(); 77 } 78 catch(IOException e){ 79 throw new RuntimeException("关闭读取失败"); 80 } 81 } 82 } 83 //available()该方法可以返回实际可读字节数,也就是总大小 84 //但如果读取的内容容量过大,超过虚拟机的内存,就会出现错误。所以该方法有风险,如果处理的文件不大时比较合适,如果处理大文件或者未知大小文件还是通过new char[1024]的方法比较折中 85 public static void FileInputStreamDemo_3(){ 86 FileInputStream fis = null; 87 try{ 88 fis = new FileInputStream("FileStream.txt"); 89 byte[] buf = new byte[fis.available()];//利用available确定文件的字节数,指定数组的长度 90 fis.read(buf); 91 System.out.print(new String(buf)); 92 } 93 catch(IOException e){ 94 e.printStackTrace(); 95 } 96 finally{ 97 try{ 98 if(fis != null){ 99 fis.close(); 100 } 101 } 102 catch(IOException e){ 103 throw new RuntimeException("关闭读取失败!"); 104 } 105 } 106 } 107 }
练习,拷贝一张图片。
思考,一个图片是由字节组成的,所以不能使用字符流处理,从而使用字符流
1 import java.io.*; 2 3 public class CopyPictrue { 4 5 public static void main(String[] args) { 6 FileOutputStream fos = null; 7 FileInputStream fis = null; 8 try{ 9 fos = new FileOutputStream("copy.jpg"); 10 fis = new FileInputStream("/home/owen/图片/Wallpapers/1511023217-7.jpg"); 11 12 byte[] buf = new byte[1024]; 13 int len = 0; 14 while((len = fis.read(buf))!=-1){ 15 fos.write(buf); 16 } 17 18 } 19 catch(IOException e){ 20 e.printStackTrace(); 21 } 22 finally{ 23 try{ 24 if(fis!=null) 25 fis.close(); 26 } 27 catch(IOException e){ 28 throw new RuntimeException("关闭读取错误"); 29 } 30 try{ 31 if(fos!=null) 32 fos.close(); 33 } 34 catch(IOException e){ 35 throw new RuntimeException("关闭写入错误"); 36 } 37 } 38 39 } 40 41 }
练习二,使用缓冲技术,拷贝mp3
1 import java.io.*; 2 3 public class BufferedStreamDemo { 4 5 public static void main(String[] args) { 6 BufferedInputStream bis = null; 7 BufferedOutputStream bos = null; 8 try{ 9 bis = new BufferedInputStream(new FileInputStream("/home/owen/音乐/初爱.mp3")); 10 bos = new BufferedOutputStream(new FileOutputStream("初爱_杨宗伟.mp3")); 11 int num = 0; 12 while((num = bis.read())!=-1){ 13 bos.write(num); 14 } 15 } 16 catch(IOException e){ 17 e.printStackTrace(); 18 } 19 finally{ 20 try{ 21 if(bis!=null) 22 bis.close(); 23 } 24 catch(IOException e){ 25 throw new RuntimeException("关闭读取失败"); 26 } 27 try{ 28 if(bos!=null) 29 bos.close(); 30 } 31 catch(IOException e){ 32 throw new RuntimeException("关闭写入失败"); 33 } 34 } 35 36 } 37 38 }
通过构造自定义的缓冲方法,说明为什么read返回的是int类型数据,而write只写了read中的低8位数据的原因。
import java.io.*; public class MyBufferedInputStreamDemo { public static void main(String[] args)throws RuntimeException, FileNotFoundException,IOException{//偷懒了,抛异常给VM MyBufferedInputStream bis = new MyBufferedInputStream(new FileInputStream("/home/owen/音乐/初爱.mp3")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("杨宗伟_初爱.mp3")); int num = 0; while((num = bis.myRead())!=-1){ bos.write(num); /*通过对read方法将byte数据提升为int数据并返回这个过程可以看出,write方法是将指定的字节写入缓冲的输出流, * 例如将8位的byte数据提升为int类型后,write指操作了int的低8位数据,而抛弃了高24位数据(因为这24位是提升类型 * 产生的无效数据,是不需要的)*/ } bis.MyClose();bos.close(); } } class MyBufferedInputStream{ private InputStream in; private byte[] buf = new byte[1024]; private int pos =0, count = 0; MyBufferedInputStream(InputStream in){ this.in = in; } //一次读一个字节,从缓冲区(字节数组)获取 public int myRead()throws IOException{ //通过in对将读取硬盘上的数据,并存储到buf中 if(count==0){//如果count=0,则从硬盘上读取1024个字节, count = in.read(buf); if(count<0) return -1; pos=0;//从新读取1024个字节后需要把指针重置位置 byte b = buf[pos]; count--;pos++; return b&255; /*b是byte类型,而myRead返回值类型为int,从byte提升到int扩展了3个字节的内容, * b&255保证了低8位数据的完整性,即我们想要的内容,而且高的3个字节全部为0, * 保证了byte提升到int过程数据原来的内容不被破坏(比如原来的数据是8个1, * 提升过程可能会变成32个1,前面24个1是我们不想要的,因为破坏了原来的数据内容。)*/ } else if(count>0){//count>0则从缓冲中不断读取数据 byte b = buf[pos]; count--;pos++; return b&0xff;//这个也是b&255只不过用的是16进制形式 } return -1; } public void MyClose()throws IOException{ in.close(); } }
InputStreamReader,将字节输入流转换为字符输入流的桥梁
1 import java.io.*; 2 //System.in:键盘录入 3 //InputStreamReader(InputStream in) 字节流转换为字符流的桥梁 4 public class SystemInDemo { 5 6 public static void main(String[] args){ 7 //从键盘录入获取输入 8 InputStream in = System.in; 9 //将字节流转换为字符流,使用转换流 10 InputStreamReader isr = new InputStreamReader(in); 11 //加入缓冲技术,提高效率 12 BufferedReader bufr = new BufferedReader(isr); 13 //创建写入 14 BufferedWriter bufw = null; 15 16 String line = null; 17 try{ 18 bufw = new BufferedWriter(new FileWriter("MyRecord.txt")); 19 while((line = bufr.readLine()) != null){ 20 bufw.write(line);//读一行,写一行 21 if(line.equals("over"))//如果键盘输入一行的内容等于“over”则跳出循环 22 break; 23 } 24 bufr.close(); 25 bufw.close(); 26 } 27 catch(IOException e){ 28 e.printStackTrace(); 29 } 30 catch(RuntimeException e){ 31 e.printStackTrace(); 32 } 33 } 34 35 }
OuputStreamWriter,将字符输出流转换为字节输出流的桥梁
1 import java.io.*; 2 3 public class SytemOutDemo { 4 5 public static void main(String[] args) { 6 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); 7 //把输入的内容打印到控制台上 8 // BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out)); 9 10 String line = null; 11 try { 12 //把输入的内容保存成文件 13 BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("out.txt"),"UTF-8"));//写出并指定编码表 14 while((line = bufr.readLine())!=null){ 15 if(line.equals("over")) 16 break; 17 bufw.write(line);//读取一行不为over时,加载到写入缓冲流中 18 bufw.newLine();//换行 19 bufw.flush();//将缓冲中的内容写出 20 } 21 bufr.close(); 22 bufw.close(); 23 } catch (IOException e) { 24 e.printStackTrace(); 25 } catch(RuntimeException e){ 26 System.out.println("IO error!==>"+e.getMessage()); 27 } 28 } 29 30 }