IO、FileInputStream、(二十)
1.IO流概述及其分类
* 1.概念(什么是IO?)
* IO流用来处理设备之间的数据传输
* Java对数据的操作是通过流的方式
* Java用于操作流的类都在IO包中
* 流按流向分为两种:输入流,输出流。
* 流按操作类型分为两种:
* 字节流 : 字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的
* 字符流 : 字符流只能操作纯字符数据,比较方便。
* 2.IO流常用父类
* 字节流的抽象父类:
* InputStream
* 1.字节输入流的所有类的超类
* 2.抽象类不能实例化,使用的时候需要创建子类对象。
* FileInputStream------文件输入流
* 从系统中的某个文件中,获得输入字节。
* OutputStream
* 1.输出字节流的所有类的超类。
* FileOutputStream-----文件输出流
* 字符流的抽象父类:
* Reader
* 读取字符流的抽象类。
* Writer
* 写出字符流的抽象类。
* 3.IO程序书写
* 使用前,导入IO包中的类
* 使用时,进行IO异常处理
* 使用后,释放资源
2.FileInputStream
* read(),没有参数时,读取一个字节;也可以有参数,一个字节数组或……
* 1.一次读取一个字节,可以读一个字节数组,从输入流读入一定长度的字节
* 2.文件达到末尾返回-1
* 3.方法的返回值都是int类型
FileInputStream fis = new FileInputStream("xxx.txt"); int x = fis.read();//读入一个字节数, System.out.println(x);
3.FileInputStream返回值为什么是int?
read()方法读取的是一个字节,为什么返回是int,而不是byte??
因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到11111111
那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型。
4.FileOutputStream
* 若没有源文件,则创建一个文件;若有的话,就清空文件中的内容,然后写进去。 * write() 有参数,可以是int类型整数,可以是字节数组,或一定长度的字节数组 * 1.一次写出一个字节,读取最底层的二进制代码 FileOutputStream fos = new FileOutputStream("xxx.txt");//创建输出流对象,直接指定路径 fos.write(97); fos.write(98);
* FileOutputStream的构造方法写出数据如何实现数据的追加写入?? * //源文件中有数据内容,要想在后面追加内容,就得如下所示: FileOutputStream fos = new FileOutputStream("xxx.txt",true); fos.write(97); fos.write(98);
/* 拷贝图片 FileInputStream fis = new FileInputStream("美女.jpg"); FileOutputStream fos = new FileOutputStream("小美女.jpg"); for(int b ; (b = fis.read()) != -1 ; ){ fos.write(b); } FileOutputStream fos = new FileOutputStream("大美女.jpg"); byte[] b = new byte[fis.available()];//文件的大小 fis.read(b); fos.write(b); fis.close(); fis.close(); */
5.字节数组拷贝之available()方法
* int read(byte[] b) * 1.把文件上的字节读取到一个字节数组中去 * 2.返回的是读到字节的个数。 * write(byte[] b) * 1.一次写出一个字节数组 * 2.写出的是字节数组中的所有元素 * available()获取读的文件所有的字节个数 * 弊端:有可能会内存溢出
* write(byte[] b) //每次写出一个字节数组的字节
* write(byte[] b, int off, int len)//写出有效的字节个数
6.BufferedInputStream和BufferOutputStream拷贝
* A:缓冲思想
* 字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,
* 这是加入了数组这样的缓冲区效果,java本身在设计的时候,
* 也考虑到了这样的设计思想(装饰设计模式后面讲解),所以提供了字节缓冲区流
* B:BufferedInputStream和BufferedOutputStream的构造方法
* 如果文件足够大,read()方法执行一次,就会将文件上字节数据一次读取8192个字节存储在,BufferedInputStream的缓冲区中
* 从缓冲区中返给一个字节一个字节返给b
* 如果write一次,先将缓冲区装满,然后一股脑的写到文件上去
* 这么做减少了到硬盘上读和写的操作
package cn.wh.*; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class Demo_Test { /** * @param args * 拷贝音频文件: * 1.一个一个字节的输入 * 2.创建大数组输入 * 3.创建小数组 * 4.BuffeedInputStream、BufferedOutputStream * @throws IOException */ public static void main(String[] args) throws IOException { //1.一个一个字节的输入:效率比较慢,开发不建议使用 /*FileInputStream fis = new FileInputStream("喜欢你.mp3");//创建输入流对象,关联“喜欢你.jpg文件” FileOutputStream fos = new FileOutputStream("likeyou.mp3"); int b ; while((b = fis.read()) != -1 ){ fos.write(b); } fis.close(); fos.close(); */ //2.创建一个大数组 /*FileInputStream fis = new FileInputStream("喜欢你.mp3"); FileOutputStream fos = new FileOutputStream("likeyou1.mp3"); byte[] b = new byte[fis.available()];//available()是求字节长度的,返回值类型为int。 fis.read(b); fos.write(b); fis.close(); fos.close();*/ //3.创建小数组进行接收: /*FileInputStream fis = new FileInputStream("喜欢你.mp3"); FileOutputStream fos = new FileOutputStream("likeyou2.mp3"); byte[] b = new byte[1024*8];(8192) int len ; //len = fis.read();将文件上的数据,读取到字节数组b中 while((len = fis.read(b)) != -1){ fos.write(b,0,len);//从指定的数组中写出指定长度的字节 } fis.close(); //关流 fos.close();*/ //4.BufferedInputStream 、BufferedOutputStream /*BufferedInputStream bis = new BufferedInputStream(new FileInputStream("喜欢你.mp3")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("likeyou3.mp3")); int b ; while((b = bis.read()) != -1){ bos.write(b); } bis.close(); bos.close();*/ } }
7.字节流读写中文
* 字节流读取中文的问题
* 一个中文俩个字节
* 字节流写出中文的问题
* 写出回车换行 (\r\t)
* 字节流只读中文是有弊端的,有可能会读到半个中文,导致乱码产生。
* 解决方法有:
* 1,用字符流读(编码表+字节流)
* 2,将文件上的所有字节一次读到内存中,在内存中将所有字节转换成对应的字符串
* ByteArrayOutputStream
* 字节流写中文
* 在只写中文的时候必须转换成字节数组写出去
* FileOutputStream fos = new FileOutputStream("ccc.txt");
* fos.write("我爱你".getBytes());//String类中的getBytes()方法,将字符串转换成字节数。
* 字节流可以拷贝任意类型的数据,因为所有的数据都是以字节的形式存在的
* 拷贝的四种形式
8.流的标准处理异常代码1.6版本及其以前
* 在try()中创建的流对象必须实现了AutoCloseable这个接口,如果实现了,在try后面的{}(读写代码)执行后就会自动调用流对象的close方法将流关掉 try finally嵌套 //标准的异常处理代码 FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream("aaa.txt"); fos = new FileOutputStream("bbb.txt"); int b; while((b = fis.read()) != -1) { fos.write(b); } } finally { try { if(fis != null) fis.close(); }finally { if(fos != null) fos.close(); } }
9.流的标准处理异常代码1.7版本
try close try( FileInputStream fis = new FileInputStream("aaa.txt"); FileOutputStream fos = new FileOutputStream("bbb.txt"); //MyClose mc = new MyClose(); ){ int b; while((b = fis.read()) != -1) { fos.write(b); } }
给图片加密 package cn.wh; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class Demo_Practure { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { //加密: FileInputStream fis = new FileInputStream("美女.jpg"); FileOutputStream fos = new FileOutputStream("girl.jpg"); int b ; while((b = fis.read()) != -1){ fos.write(b^12306); } //解密: FileInputStream fis1 = new FileInputStream("girl.jpg"); FileOutputStream fos1 = new FileOutputStream("girl1.jpg"); int c ; while((c = fis1.read()) != -1){ fos1.write(c^12306); } } }
* 在控制台录入文件的路径,将文件拷贝到当前项目下 package cn.wh; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Scanner; public class Test_03 { /** * @param args * 在控制台录入文件的路径,将文件拷贝到当前项目下 * @throws IOException */ public static void main(String[] args) throws IOException { Scanner sc = new Scanner(System.in); System.out.println("请输入:"); String str = sc.nextLine(); File file = new File(str);//把字符串转换成文件对象,方便利用文件对象的方法。即封装成File对象。 FileInputStream fis = new FileInputStream(file);//相当于拿到了文件的路径。 FileOutputStream fos = new FileOutputStream(file.getName());//File对象中的只得到名字的方法。 //就相当于相对路径 byte[] b = new byte[8192]; int len ; while((len = fis.read(b)) != -1 ){ fos.write(b,0,len); } fis.close(); fos.close(); } }
* 将键盘录入的数据拷贝到当前项目下的text.txt文件中,键盘录入数据当遇到quit时就退出 package cn.itcast.day20; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Scanner; public class Demo_IO_Test_1 { /** * @param args * 将键盘录入的数据拷贝到当前项目下的text.txt文件中,键盘录入数据当遇到quit时就退出 * @throws IOException */ public static void main(String[] args) throws IOException { Scanner sc = new Scanner(System.in); FileOutputStream fos = new FileOutputStream("text.txt"); System.out.println("请输入:"); while(true){ String str = sc.nextLine(); if("quit".equals(str)){ break; } fos.write(str.getBytes()); fos.write("\r\n".getBytes()); } } }
flush和close的区别?
* flush刷新之后还可以继续写。
* close在关闭之前会刷新一次,把缓冲区剩余的字节刷到文件上去,但是调用之后不能再写。