1.IO的引入
2.IO流的分类
流向:
输入流 读取数据
输出流 写出数据
数据类型:
字节流
字节输入流 读取数据 InputStream
字节输出流 写出数据 OutputStream
字符流
字符输入流 读取数据 Reader
字符输出流 写出数据 Writer
我们一般在探讨IO流的时候,如果没有明确说明按照那种分类来说,默认情况下是按照数据类型来分的。
3.写入数据
package com; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; /** * 字节输出流操作步骤: * 1.创建字节输出流对象 * 2.写数据 * 3.释放资源 */ public class FileOutputStreamDemo { @SuppressWarnings("resource") public static void main(String[] args) throws Exception { File file = new File("hello.txt"); OutputStream os = new FileOutputStream(file,true); /** * 创建字节流输出对象做了以下几件事 * 调用系统功能去创建文件 * 创建os对象 * 把os对象指向这个文件 */ os.write("你好,世界".getBytes()); os.close();//释放资源 /** * 为什么一定要close()呢? * 1.让流对象变成垃圾,这样就可以被垃圾回收器回收了 * 2.通知系统去释放和该文件相关的资源 */ } }
package com; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; /** * 字节输出流操作步骤: * 1.创建字节输出流对象 * 2.调用write()方法 * 3.释放资源 * * public void write(int b)写一个字节 * public void write(byte[] b)写一个字节数组 * public void write(byte[] b,int offset,int len)写一个字节数组的一部分 * */ public class FileOutputStreamDemo2 { public static void main(String[] args) throws IOException { OutputStream os = new FileOutputStream("fos.txt"); os.write(97); os.write("helloworld".getBytes()); os.write(new byte[]{97,98, 99,100},1,3); os.close(); } }
4.实现数据的追加写入
package cn; import java.io.FileOutputStream; import java.io.OutputStream; /** * 如何实现数据的换行? * 写入换行符号即可。 * 不同的系统针对不同的换行符号识别是不一样的。 * windows:\r\n * Linux:\n * Mac:\r * 一些常见的高级记事本软件,是可以识别任意换行符号。 * * 如何实现数据的追加写入? * public FileOutputStream(String name,boolean append) * */ public class FileOutputStreamDemo { public static void main(String[] args) throws Exception{ //创建字节输出流对象 OutputStream os = new FileOutputStream("fos.txt",true); //写数据 for (int i = 0; i < 10; i++) { os.write(("hello"+i).getBytes()); os.write("\n".getBytes()); } //释放资源 os.close(); } }
5.加入异常处理的字节输出流操作
package cn; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; /** * 加入异常处理的字节输出流操作 */ public class FileOutputStreamDemo1 { public static void main(String[] args) { OutputStream os = null; try { /** * 为什么os要赋值为null? * 因为try{到os = new FileOutputStream("fos.txt")之间一旦出现异常, * 那么os就没有默认值,但是os是局部变量啊,怎么可能没有默认值呢? */ os = new FileOutputStream("fos.txt"); os.write("java".getBytes()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ //如果os不为null,就为close //为什么要加入此判断呢,倘若os = new FileOutputStream("z://fos.txt"),文件不存在,那么此时会抛出异常 //当然cath()会捕获到,但是一般程序运行到finally的时候,如果没有if判断,就是os.close(),而os此时是null啊, //null.close()当然报NullPointerException了 if(os != null){ //为了保障close()一定会执行,就放到finally里面了 try { os.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
6.读取数据
package cn; import java.io.FileInputStream; import java.io.InputStream; /** * 字节输入流的操作步骤: * 1.创建字节输入流对象 * 2.调用read()方法读取数据,并把数据显示在控制台 * 3.释放资源 * * read()方法 * public int read() throws IOExcepiton:从输入流中读取一个字节数据,如果到达文件末尾,则返回-1 */ public class FileInputStreamDemo { public static void main(String[] args) throws Exception { //创建字节输入流对象 InputStream is = new FileInputStream("fos.txt"); //调用read()方法读取数据,并把数据显示在控制台 int a = is.read(); while(-1 != a){ System.out.print((char)a); a = is.read(); } //释放资源 is.close(); } }
改进版
package cn; import java.io.FileInputStream; import java.io.InputStream; /** * 字节输入流的操作步骤: * 1.创建字节输入流对象 * 2.调用read()方法读取数据,并把数据显示在控制台 * 3.释放资源 * * read()方法 * public int read() throws IOExcepiton:从输入流中读取一个字节数据,如果到达文件末尾,则返回-1 */ public class FileInputStreamDemo { public static void main(String[] args) throws Exception { //创建字节输入流对象 InputStream is = new FileInputStream("fos.txt"); //调用read()方法读取数据,并把数据显示在控制台 int a = 0; while((a = is.read()) != -1){ System.out.print((char)a); } //释放资源 is.close(); } }
7.复制文件
package cn; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * 复制文本文件 * * 数据源:从哪里来 a.txt 读取数据 --FileInputStream * 目的地: 到哪里去 b.txt 写入数据 --FileOutputStream */ public class FileCopyDemo { public static void main(String[] args) throws IOException{ //数据源 InputStream is = new FileInputStream("a.txt"); //目的地 OutputStream os = new FileOutputStream("b.txt"); int temp = 0; while((temp = is.read()) != -1){ os.write(temp); } //释放资源 is.close(); os.close(); } }
不过这种方式每次都是读取一个字节,效率太慢了,如果读取大的文件,这种方式就不适合。
package cn; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; /** * 复制文件 * 一次读取一个字符数组:public int read(byte[] b) * 返回值其实是实际读取的字节个数 如果因为已经到达文件末尾而没有更多的数据,则返回-1 */ public class FileCopy2 { public static void main(String[] args) throws Exception{ //创建字节输入流对象 InputStream is = new FileInputStream("a.txt"); //创建字符流输出对象 OutputStream os = new FileOutputStream("b.txt"); //定义一个字节数组 byte[] b = new byte[1024]; int temp = 0; while((temp = is.read(b)) != -1){ os.write(b,0,temp); } //释放资源 is.close(); os.close(); } }
看到这里很多人都崩溃了,为什么这么写呢?哈哈,且听老夫来分解代码?
如果我a.txt文件中的内容是
hello
world
java
那么我们按照下面的代码来执行
byte[] c = new byte[5]; //第一次 int len = is.read(c); System.out.print(new String(c)); System.out.println(len); System.out.println("--------------"); //第二次 len = is.read(c); System.out.print(new String(c)); System.out.println(len); System.out.println("--------------"); //第三次 len = is.read(c); System.out.print(new String(c)); System.out.println(len); System.out.println("--------------"); //第四次 len = is.read(c); System.out.print(new String(c)); System.out.println(len);
结果是这样的
hello5
--------------
wor5
--------------
ld
j5
--------------
ava
j3
why?
其实a.txt的内容是下面这样的啊
hello\r\n
world\r\n
java\r
我们是不是定义byte[] b = new byte[5];
第一次
hello 长度是5
第二次
\r\nwor 长度也是5
其实第二次相当于
b[0]=\r
b[1]=\n
b[2]=w
b[3]=o
b[4]=r
当然这些字符的底层会转换为byte的,不用担心啊,我这样写只是为了让各位理解
第三次
ld\r\nj 长度也是5
b[0]=l
b[1]=d
b[2]=\r
b[3]=\n
b[4]=j
当然这些字符的底层会转换为byte的,不用担心啊,我这样写只是为了让各位理解
第四次
ava\rj 长度也是5 是不是不理解啦
第三次的是不是这样的
b[0]=l
b[1]=d
b[2]=\r
b[3]=\n
b[4]=j
但是这次其实只有ava,那么数组中是不是这样排列?
b[0]=a
b[1]=v
b[2]=a
那么第4,第5个元素呢,当然是第三次的,因为这一次是没有字符去赋值的。
b[3]=\n
b[4]=j
懂了没?
但是我们如何避免这种情况呢?
看上面的len,就是每次读取的字节长度。5,5,5,3
那么,我们的代码改成下面的样子,是不是可以避免上面的问题呢?
byte[] c = new byte[5]; //第一次 int len = is.read(c); System.out.print(new String(c,0,len)); System.out.println(len); System.out.println("--------------"); //第二次 len = is.read(c); System.out.print(new String(c,0,len)); System.out.println(len); System.out.println("--------------"); //第三次 len = is.read(c); System.out.print(new String(c,0,len)); System.out.println(len); System.out.println("--------------"); //第四次 len = is.read(c); System.out.print(new String(c,0,len)); System.out.println(len);
hello5
--------------
wor5
--------------
ld
j5
--------------
ava3
此时,输出的就是我们想要的啦。
那么现在看懂下面的代码吗?
package cn; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; /** * 复制文件 * 一次读取一个字符数组:public int read(byte[] b) * 返回值其实是实际读取的字节个数 如果因为已经到达文件末尾而没有更多的数据,则返回-1 */ public class FileCopy2 { public static void main(String[] args) throws Exception{ //创建字节输入流对象 InputStream is = new FileInputStream("a.txt"); //创建字符流输出对象 OutputStream os = new FileOutputStream("b.txt"); //定义一个字节数组 byte[] b = new byte[1024]; int temp = 0; while((temp = is.read(b)) != -1){ os.write(b,0,temp); } //释放资源 is.close(); os.close(); } }
8.字节缓冲流
字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多哦,这是加入数组这样的缓冲效果,java本身在设计的时候,也考虑到了这样的设计思想(装饰模式),所以提供了字节缓冲区流
字节缓冲输出流
BufferedOutputStream
字节缓冲输入流
BufferedInputStream
package cn; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class BufferedOutputStreamDemo { public static void main(String[] args) throws IOException { OutputStream os = new BufferedOutputStream(new FileOutputStream("bos.txt")); os.write("helloworld".getBytes()); os.close(); } }
package cn; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class BufferedInputStreamDemo { public static void main(String[] args) throws IOException { InputStream is = new BufferedInputStream(new FileInputStream("bos.txt")); byte[] b = new byte[1024]; int temp = 0; while((temp=is.read(b)) != -1){ System.out.println(new String(b,0,temp)); } is.close(); } }