Java学习之路(十二):IO流
IO流的概述及其分类
- IO流用来处理设备之间的数据传输,Java对数据的操作是通过流的方式
- Java用于操作流的类都在IO包中
流按流向分为两种:输入流(读写数据) 输出流(写数据)
流按操作类型分为两种:
- 字节流:字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的
- 字符流:字符流只能操作纯字符数据,比较方便
常用的IO流的类
字节流的抽象父类:InputStream OutputStream
字符流的抽象方法:Reader Writer
InputStream实现类FileInputStream
InputStream是抽象类,表示字节输入流
FileInputStream从文件系统中的某个文件中获得输入字节。FileInputStream用于读取图像数据之类的原始字节流。要读取字符流,就要用FileReader
构造方法:
- FileInputStream(File file)
- FileInputStream(String name)
FileInputStream的构造方法可以传一个File对象,也可以传一个字符串路径
成员方法:
- int read() 从此输入流中读取到一个数据字节
案例:读取一个txt文件数据
package null08031628; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; public class Demo01 { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub File file = new File("C:/Users/Administrator/Desktop/baiduyunpan.txt"); FileInputStream fis = new FileInputStream(file); int i = 0; while((i = fis.read()) != -1){ System.out.println(i); }
fis.close();
} }
OutputStream实现类FileOutputStream文件输出流
文件输出流就是用于将数据写入File的输出流
案例:从一个文件读入数据写入另一个文件package null08031638;import java.io.File;
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class Demo01 { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub File filein = new File("C:/Users/Administrator/Desktop/baiduyunpan.txt"); InputStream fis = new FileInputStream(filein); //创建一个输入流 File fileout = new File("C:/Users/Administrator/Desktop/baiduyunpan-2.txt"); OutputStream fos = new FileOutputStream(fileout); //创建一个输出流 int i = 0; while((i=fis.read())!=-1){ fos.write(i); }
fos.close();
fis.close();
} }
通过available()方法,进行字节数组拷贝(错误的,不推荐的,如果文件超级大怎么办?)
package null08031700; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class Demo01 { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub FileInputStream input = new FileInputStream("C:/Users/Administrator/Desktop/baiduyunpan.txt"); FileOutputStream out = new FileOutputStream("C:/Users/Administrator/Desktop/baiduyunpan-3.txt"); byte[] bs = new byte[input.available()];//定义一个文件输入流那么大的字节数组 input.read(bs); //一次性将数据写入到字节数组中 out.write(bs); //一次性将文件写入 input.close(); out.close(); } }
自定义一个大小的数组,进行一个流的读写(正确的方法)
package null08031707; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class Demo01 { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub FileInputStream input = new FileInputStream("C:/Users/Administrator/Desktop/baiduyunpan.txt"); FileOutputStream out = new FileOutputStream("C:/Users/Administrator/Desktop/baiduyunpan-3.txt"); byte[] bs = new byte[8*1024]; int i = 0; while((i=input.read(bs))!=-1){ out.write(i); } out.close(); input.close(); } }
通过字节数组的方法操作流,其实就是相当于是创建了一个缓冲区
自带缓冲区的实现类BufferedInputStream和BufferedOutputStream
BufferedInputStream
- 内置了一个缓冲区(就是之前定义的那个数组)
- 从BufferedInputStream中读取一个字节时,BufferedInputStream会一次性的读入8192个,放在缓冲区,在返回给程序
- 程序再次读取时,就不会再从文件中取了,直接从缓冲区获取
- 知道缓冲区中的所有都被用过了,BufferedInputStream才重新从文件中读取8192个
BufferedOutputStream
- 内置了一个缓冲区(数组)
- 程序向流中写入字节时,不会直接写到文件,而是先写入缓冲区当中
- 知道缓冲区写满,BufferedOutputStream才会把缓冲区中的数据一次性写入文件
一个小小的例子:
package null08031732; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class Demo01 { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub FileInputStream fis = new FileInputStream("C:/Users/Administrator/Desktop/baiduyunpan.txt"); BufferedInputStream bis = new BufferedInputStream(fis); FileOutputStream fos = new FileOutputStream("C:/Users/Administrator/Desktop/baiduyunpan-4.txt"); BufferedOutputStream bos = new BufferedOutputStream(fos); int i; while((i=bis.read())!=-1){ bos.write(i); } bis.close(); bos.close(); } }
带Buffered的流和自己写的字节数组缓冲对比
- 字节写的数组在速度上回略胜一筹,因为自己写的读和写的操作都是在同一个数组之中
- 而Buffered操作的是两个数组,所以效率低于一个的
BufferedOutputStream中的一些方法
- flush()方法:用来刷新缓冲区,刷新后就可以再次写入了
- close()方法:关闭流,而且在关闭前后会刷新一次缓冲区
补充
字节流读写中文时乱码的问题
字节流读取中文:
- 字节流读取中文的问题
- 字节流在读取中文的时候有可能会读到半个中文,造成乱码
字节流写入中文的问题:
- 字节流直接操作的字节,所以写入中文的时候必须将字符串转换成字节数组
- 写出回车换行write("\r\n".getBytes())
流的标准处理异常代码1.6版本前
package null08041019; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class Demo01 { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub FileInputStream fis = null; FileOutputStream fos = null; try{ fis = new FileInputStream(""); fos = new FileOutputStream(""); int b; while((b=fis.read())!=-1){ fos.write(b); } }finally{ try{ fis.close(); }finally{ fos.close(); } } } }
流的处理1.7版本
package null08041024; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class Demo01 { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub try( //写在括号中的代码,执行完成后,会自动调用对象的close方法 //能写在括号中的代码的类一定是要继承AutoCloseable接口的类 FileInputStream fis = new FileInputStream(""); FileOutputStream fos = new FileOutputStream(""); ){ int i; while((i=fis.read())!=-1){ fos.write(i); } } } }
一个图片加密的例子:
package null08041031; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Scanner; public class Demo01 { public static void main(String[] args) throws IOException { Scanner sc = new Scanner(System.in); System.out.println("请将图片放到和此文件的同级目录下"); System.out.println("请输入要加密的文件名:"); String fileName = sc.nextLine(); System.out.println("请输入加密后的文件名:"); String endFileName = sc.nextLine(); System.out.println("请输入密码:"); String pwd = sc.nextLine(); int pwdInt = Integer.parseInt(pwd); try( FileInputStream fis = new FileInputStream(fileName); FileOutputStream fos = new FileOutputStream(endFileName); ){ int i; while((i=fis.read())!=-1){ fos.write(i^pwdInt); } }finally{ System.out.println("加密结束"); } } }