IO流概述
IO流(Input Output)用来处理设备之间的数据传输
Java对数据的操作是通过流的方式
Java用于操作流的对象都在IO包中
流按操作数据分为两种:字节流与字符流。
流按流向分为:输入流,输出流。
字节流的抽象基类:
InputStream ,OutputStream。
字符流的抽象基类:
Reader , Writer。
注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:InputStream的子类FileInputStream。
如:Reader的子类FileReader。
字符流的特点:
IO流是用来操作数据的,那么数据的最常见形式是:文件
先以操作文件来演示IO流
需求:在硬盘上创建一个文件并写入一些文字数据
用到Writer的子类:后缀名是父类名,前缀名是功能;在API中找到一个专门用于操作文件的对象:FileWriter
创建FileWriter对象该对象一被初始化就必须要明确要操作的对象;没有空参的构造方法
而且该文件会被创建在指定的目录下,如果该目录已有同名文件则会被覆盖
其实该操作就是在明确数据要存放的目的地
FileWriter示例:
文件写入
import java.io.*; class IODemo { public static void main(String[] args) throws IOException //抛IO异常 { FileWriter fw = new FileWriter("Demo.txt");//1,创建文本对象 fw.write("asdff"); //2,调用write方法,将字符串写入到流中 /// fw.flush(); //3,刷新流对象中缓冲区数据;到目的地中 fw.close(); //4,关闭流资源,并在关闭之前刷新一次缓冲区数据,刷到目的地中 //flush刷新后流可以继续使用,close刷新后会将流关闭 } }
IO异常的处理:
new 、write、close都会造成IO异常,所以要做处理import java.io.*; class FileWriterDemo2 { public static void main(String[] args) { FileWriter fw = null; //将FileWriter外置,以调用finally中的close try{ fw = new FileWriter("Demo.txt"); fw.write("haha"); } catch (IOException e){ System.out.println("catch: "+e.toString()); } finally{ //开启了几个写入流就要关闭几次,切记 try{ if(fw!==null) //一定要判断是否为null,因为close的操作要有对象 fw.close(); //要对异常进行处理 } catch (IOException e){ System.out.println(e.toString()); } } } }
文件的续写
FileWriter(" ",append)方法 append值为true时将数据写入文件末尾处,为false则覆盖原文件
try { //append值为true时将数据写入文件末尾处,为false则覆盖原文件 fw = new FileWriter("Demo.txt",true);//传递一个true fw.write("换行 文件续写"); }
FileRader
文本文件的读取
方法一:read()
该方法一次只读取一个字符,返回值为该字符在码表中对应的int值,到达文件末尾时返回-1
创建一个文件读取流对象,和指定名称的文件相关联
要保证该文件已经存在,否则会发生异常:FileNotFoundException
import java.io.*; class FileReaderDemo { public static void main(String[] args) throws IOException { FileReader fr = new FileReader("Demo.txt");//创建读取流 // int ch = fr.read(); //read一次只读取一个字符,多次调用则继续往下读;返回值为该字符在码表中的int值 int ch = 0; //循环获取文本内容 while ((ch = fr.read())!=-1)//read()到达文件末尾返回-1 { System.out.print((char)ch); } fr.close(); } }
方法二:read(char[] cbuf)
通过字符数组进行获取,该方法一次获取数组个数的字符,返回值为实际获取的元素个数,一般是数组长度,到达文件末尾时返回-1。read()和 read(char[] cbuf)都有in型的返回值,不同的是前者返回的是该字符在码表中对应的值,后者返回的是该字符数组的元素个数
示例:
import java.io.*; class FileReader2 { public static void main(String[] args) throws IOException{ FileReader fr = new FileReader("Demo.txt"); char[] buf = new char[1024];//定义数组用于存储读取的字数 // int num = fr.read(buf); //该read返回数组元素个数 // sop("num: "+num+" ... "+new String(buf)); int num ;// while ((num=fr.read(buf)) !=-1){//read(char[] cbuf)到达文件末尾返回-1 sop(new String(buf,0,num) ); } fr.close(); } public static void sop(Object obj){ System.out.println(obj); } }
内存示例:
文件内容的copy
将一个文件内容copy到另一个文件,要做整点掌握原理:1,创建一个文件,用于接收写入流2,定义读取流和目标文件关联3,通过不断的读写完成数据4,关闭资源
根据文件读取两种方式的不同,有两种copy方式,但原理是一致的
示例:
import java.io.*; class CopyTest { public static void main(String[] args) throws IOException { // copy_1(); copy_2(); } public static void copy_2() //方法二:利用数组,每次存取1024个字符,减少循环次数,提高效率 { FileWriter fw = null; FileReader fr = null; try //异常要进行处理,不建议throws { fw = new FileWriter("CopyTest_copy.txt"); fr = new FileReader("CopyTest.java"); char[] buf = new char[1024]; int num; while ((num=fr.read(buf)) !=-1){ fw.write(buf,0,num);//写入字符数组的某一部分,这么定义是因为末尾时num有不满足1024的情况 } } catch (IOException e){ throw new RuntimeException("访问失败");//处理异常,可以定义更加详细的规则 } finally //关闭流的动作一定要执行,要分开写 { if(fr!=null)//关闭流的动作一定要有对象,所以要做判断 try{ fr.close(); } catch (IOException e) {} if(fw!=null) try{ fw.close(); } catch (IOException e) {} } } public static void copy_1() throws IOException//方法一:每次读写一个字符,循环次数多 { FileWriter fw = new FileWriter("RuntimeDemo_copy.txt");//1,写入流 创建目的地 FileReader fr = new FileReader("CopyTest.java"); //2,读取流 与已有文件关联 int ch; while ((ch=fr.read()) !=-1)//3,读取 { fw.write(ch); //写入 } fw.close();//4,关闭流 fr.close(); } }
文件的Copy过程简述:
文件读取流对象通过调用系统底层,将硬盘上的文件读取到内存中封装成数组,写入流将数组中的元素写入到硬盘的目的地中,读写完成后关闭两个流资源硬盘中源文件>读取流>内存中数组>写入流>目标文件>关闭流资源
字符流缓冲区
缓冲区的出现是为了提高流的操作效率,在开发中一般都要加缓冲区,提高性能在创建缓冲区之前,必须要现有流对象写入流缓冲区
BufferedWriter;是Writer的子类示例:
import java.io.*; class BufferedWriterDemo { public static void main(String[] args) throws IOException { FileWriter fw = new FileWriter("buf.txt"); BufferedWriter bfw = new BufferedWriter(fw);//将要提高效率的流对象作为参数传递给缓冲区的构造函数 for (int x= 1; x<5; x++) { bfw.write("hahahah"+x); //子类继承自父类的方法 bfw.newLine(); //换行。缓冲区中跨平台的换行符, Windows和Linux中换行符是不一样的,为了保证Java的跨平台性 bfw.flush(); //只要用到了缓冲区,就要记得刷新 } bfw.close(); //关闭缓冲区就是在关闭缓冲区中的流对象,所以不用再进行流对象的关闭动作 } }
读取流缓冲区
该方法提供了一个一次读取一行的方法,方便与对文本文件的获取
readLine()方法,该方法返回含有该行内容的字符串,不包含换行符;到达流末尾则返回null
简写示例:
FileReader fr = new FileReader("buf.txt");//创建读取流 关联文件 BufferedReader bufr = new BufferedReader(fr);//为了提高效率,将字符读取流对象传递给缓冲区对象的构造函数 String line = null; while ((line = bufr.readLine()) !=null)//readLine到达文件末尾返回null { System.out.println(line); }
通过缓冲区复制文件
import java.io.*; class CopyTextByBuf { public static void main(String[] args) { BufferedReader bufr = null; BufferedWriter bufw = null; try { bufr = new BufferedReader(new FileReader("CopyTextByBuf.java"));//copy当前java文件 bufw = new BufferedWriter(new FileWriter("BufferedWriter_copy.txt")); String line = null; while ((line=bufr.readLine()) !=null)//readLine()只返回回车符之前的内容 { bufw.write(line); // bufw.newLine(); //必须要换行 bufw.flush(); } } catch (IOException e){ throw new RuntimeException("访问失败"); } finally{ try{ if(bufr !=null) bufr.close(); } catch (IOException e){ throw new RuntimeException("读取关闭失败"); } try{ if(bufw !=null) bufw.close(); } catch (IOException e){ throw new RuntimeException("写入关闭失败"); } } }