流按操作数据分为两种:字节流和字符流
字节流的抽象基类:InputStream OutputStream
字符流的抽象基类:Reader Writer
流按流向分为:输入流和输出流
字符流的特点:
既然IO流是用于操作数据的。那么先以操作文件为主来演示。
需求:在硬盘上,创建一个文件并写入一些文字数据。
找到一个专门用于操作文件的Writer子类对象。FileWriter. 后缀名是父类名,前缀名是该流对象的功能。
FileWriter
public class FileWriter_06 { public static void main(String[] args) throws IOException { //创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件。 //而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。 //这一步就是在明确数据要存放的目的地。这一步可能发生异常,如:盘不存在,盘已经满了 FileWriter fw=new FileWriter("d:\\demo.txt"); //调用writer方法,将字符串写入到流中。 fw.write("abcde"); //刷新流对象中的缓冲中的数据,将数据刷到目的地中。 fw.flush(); //关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。将数据刷到目的地中。 //和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。 fw.close(); //fw.write("haha"); //fw.flush(); } }
IO异常的处理方式
public class FileWriter_07 { public static void main(String[] args) { // TODO Auto-generated method stub FileWriter fw=null; try { fw=new FileWriter("d:\\demo.txt"); fw.write("abcde"); } catch (IOException e) { // TODO Auto-generated catch block System.out.println(e.toString()); }finally{ try { if(fw!=null){ fw.close(); } } catch (IOException e) { // TODO Auto-generated catch block System.out.println(e.toString()); } } } }
文件的续写
演示对已有文件的数据续写
public class FileWriter_08 { public static void main(String[] args) { FileWriter fw=null; try { //传递一个true参数,代表不覆盖已有的文件,并在已有文件的末尾处进行数据的续写。 //FileWriter(String fileName, boolean append) //在给出文件名的情况下构造 FileWriter 对象,它具有指示是否挂起写入数据的 boolean 值。 fw=new FileWriter("d:\\demo.txt",true); //\r\n是window中的换行符 fw.write("xuxie\r\nnihao"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ if(fw!=null){ try { fw.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
FileReader
第一种方式:一个一个读
public class FileReader_09 { public static void main(String[] args) throws IOException{ //创建一个文件读取流对象,和指定名称的文件相关联。 //要保证该文件是已经存在的,如果不存在,会发生FileNotFoundException FileReader fr=new FileReader("d:\\demo.txt"); //调用读取流对象的read方法 //read方法一次读一个字符,而且会自动往下读 //int ch=fr.read();
int ch=0;
while((ch=fr.read())!=-1){
System.out.println((char)ch);
}
fr.close();
}
}
第二种方式:通过字符数组进行读取
public class FileReader_10 { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub FileReader fr=new FileReader("d:\\demo.txt"); //定义一个字符串数组,用于存储读到的字符 //该read(char [])返回的是读到的字符个数 char [] buf=new char[3]; //int num=fr.read(buf); //System.out.println("num="+num+"..."+new String(buf)); int num=0; while((num=fr.read(buf))!=-1){ String s=new String(buf,0,num); System.out.println("num="+num+",s="+s); } fr.close(); } }
练习:读取一个.java文件,并打印在控制台
public class FileReader_11 { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub FileReader fr=new FileReader("d:\\FileWriter_07.java"); char [] buf=new char[1024]; int num=0; while((num=fr.read(buf))!=-1){ System.out.println("num="+num+",s="+new String(buf,0,num)); } fr.close(); } }
将c盘一个文本文件复制导d盘
复制原理:
其实就是将c盘下的文件数据存储到d盘一个文件中
步骤:
1.在d盘创建一个文件,用于存储c盘文件中的数据
2.定义读取流和c盘文件相关联
3.通过不断的读写完成数据存储
4.关闭流
public class Copy_12 { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub //copy_1(); copy_2(); } //从c盘读一个字符就往d盘写一个字符 public static void copy_1() throws IOException{ //创建目的地 FileWriter fw=new FileWriter("d:\\destination.java"); //与已有文件关联 FileReader fr=new FileReader("c:\\FileWriter_07.java"); int ch=0; while((ch=fr.read())!=-1){ fw.write(ch); // 写入单个字符 } fw.flush(); fw.close(); fr.close(); } //用数组将c盘文件写入d盘 public static void copy_2(){ FileWriter fw=null; FileReader fr=null; try { fw=new FileWriter("d:\\hello.java"); fr=new FileReader("c:\\FileWriter_07.java"); char [] buf=new char[1024]; int num=0; while((num=fr.read(buf))!=-1){ fw.write(buf,0,num); } } catch (IOException e) { // TODO Auto-generated catch block throw new RuntimeException("读写失败"); }finally{ if(fr!=null){ try { fr.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(fw!=null){ try { fw.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
BufferedWriter
缓冲区的出现提高了对数据的读写效率。缓冲区的出现是为了提高流的操作效率而出现。
所以在创建缓冲区之前,必须要先有流对象。
该缓冲区中提供了一个跨平台的换行符。newLine()
public class BufferedWriter_01 { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub //创建一个流对象 FileWriter fw=new FileWriter("d:\\buf.txt"); //为了提高字符写入流的效率,加入了缓冲技术。 //只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可 BufferedWriter bufw=new BufferedWriter(fw); for(int i=0;i<5;i++){ bufw.write("abcd"+i); bufw.newLine(); //自动换行 bufw.flush(); } //记住:只要用到缓冲区,就要记得刷新 bufw.flush(); bufw.close(); //缓冲区的关闭其实关闭的是缓冲区中的流对象 } }
字符读取流缓冲区:
该缓冲区提供了一个一次读一行的方法readLine,方便于对文本数据的获取。
当返回null时,表示读到文件末尾
readLine方法只返回回车符之前的数据内容,并不返回回车符。
public class BufferedReader_02 { public static void main(String[] args) throws IOException { //read_1(); read_2(); //read_3(); } //一个一个读 public static void read_1() throws IOException{ FileReader fr=new FileReader("d:\\buf.txt"); int num=0; while((num=fr.read())!=-1){ System.out.println((char)num); } } //一行一行读 public static void read_2() throws IOException{ //创建一个读取流对象和文件相关联 FileReader fr=new FileReader("d:\\buf.txt"); //为了提高效率,加入缓冲技术,将字符读取流对象作为参数传递给缓冲对象的构造函数 BufferedReader bufr=new BufferedReader(fr); String line=null; while((line=bufr.readLine())!=null){ //如果已到达流末尾,则返回 null System.out.println(line); } } //用数组读 public static void read_3() throws IOException{ FileReader fr=new FileReader("d:\\demo.txt"); char [] chs=new char[3]; int len=0; while((len=fr.read(chs))!=-1){ System.out.println("len:"+len+",char:"+new String(chs,0,len)); } } }
通过缓冲区复制一个.java文件
public class Copy_03 { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub FileWriter fw=null; BufferedWriter bufw=null; FileReader fr=null; BufferedReader bufr=null; fw=new FileWriter("e:\\FileCopy.txt"); bufw=new BufferedWriter(fw); fr=new FileReader("d:\\buf.txt"); bufr=new BufferedReader(fr); String line=null; while((line=bufr.readLine())!=null){ bufw.write(line); bufw.newLine(); //一次读一行,但打印到目标文件时并没有换行。可手动换行 bufw.flush(); } bufr.close(); bufw.close(); } }