day18(下)IO流1(FileWriter,FileReader)
1.IO概述:
/* IO流概述: 1.IO流用来处理设备之间的数据传输 2.java对数据的操作时通过流的方式 3.java用于操作流的对象都在IO包中 4.流按操作数据分为两种:字节流和字符流 简单来说: 字符流:在内部融合了编码表(UTF-8,GBK....) 文字,字符等涉及到编码. 通用为字节流,字符流基于字节流 5.流按流向分为:输入流,输出流 */
2.FileWriter类:
/* 字符流和字节流 字节流两个基类: InputStream OutputStream 字符流两个基类: Reader writer 既然IO流是用于操作数据的 那么数据的最常见体现形式为:文件(存储数据) 找到一个专门用于操作文件的Writer子类对象 FileWriter,后缀名为父类名,前缀名是该流对象功能 FileWriter中为什么没有空参数构造函数? 需要向文件中写入数据,流对象一经初始化需要有操作的文件存在. *///需求:在硬盘上,创建一个文件并写入一些文字数据package filewriter; import java.io.FileWriter; import java.io.IOException; class FileWriterDemo{ public static void main(String[] args)throws IOException{ //创建一个FileWriter对象,该对象一经初始化必须要明确被操作的文件 //而且文件会被创建到指定目录下(不写路径默认当前目录) //如果该目录下已有同名文件,将被覆盖 FileWriter fw= new FileWriter("FileWriter.txt");//该构造函数会抛出IOException //该部就是在明确数据要存放的目的地. fw.write("hello");//写入字符串:并没有写入目的地,而是写到内存(流)中 fw.flush(); /* 刷新该流的缓冲。 如果该流已保存缓冲区中各种 write() 方法的所有字符, 则立即将它们写入预期目标。 */ fw.write("java"); fw.flush(); fw.close(); /* 关闭此流,但要先刷新它. 在关闭该流之后, 再调用 write() 或 flush() 将导致抛出 IOException。 对比flush(): flush刷新后,流依然可以使用.而close刷新后,会将关闭流 */ } } /* 关于IOException 如果指定文件存在,但它是一个目录, 而不是一个常规文件;或者该文件不存在,但无法创建它; 抑或因为其他某些原因而无法打开它 以上write,flush,close方法均可能发生I/O错误->产生IOException ->函数上均有异常声明->必须try..catch/throws */ /* 关于close(): 其实java在调用所在平台(windows,linux...) 的各种功能来完成文件的创建,写入... 所做的调用均是在使用OS的资源,因此在使用后释放(close)该资源. */
3.※IO异常处理:
/* IOException处理 */ package filewriter; import java.io.FileWriter; import java.io.IOException; class FileWriterDemo2{ public static void main(String[] args){ FileWriter fw=null; try{ fw= new FileWriter("k:\\test.txt"); fw.write("haha"); fw.flush(); } catch(IOException e){ System.out.println("catch "+e.toString()); } finally{ try{ if(fw!=null) fw.close(); } catch(IOException e){ System.out.println(e.toString()); } } System.out.println("over"); return; } } /* 分析以上写法: ①.write,flush,close均会发出异常,为什么不用3个try..catch处理?? 这是因为一旦 初始化时发生异常/write发生异常 下面操作(flush,close)将 无任何意义,也就是不再执行. try{ FileWriter fw = new FileWriter("test.txt"); fw.write("abcd"); fw.flush(); fw.close(); } catch(IOException e){ } ②如果初始化成功(创建文件成功),在write过程中发生IOException(例如:不断写导致硬盘空间不足) 那么fw.close()将不再执行,也就是说流资源无法关闭.(这点类似数据库操作异常导致数据库与用户连接不能断开) 鉴于此,把fw.close放在finally中(finally经常用于关闭资源),不论是否发生异常,都在退出方法前执行fw.close() 放到finally中的close依然需要try...catch try{ FileWriter fw = new FileWriter("test.txt"); fw.write("abcd"); fw.flush(); } catch(IOException e){ } finally{ try{ fw.close(); } catch(IOException e){ System.out.println(e.toString()); } } ->fw的作用域仅仅在try中->因此在try外声明,try内初始化 FileWriter fw =null; try{ fw = new FileWriter("test.txt"); fw.write("abcd"); fw.flush(); } catch(IOException e){ } ③当new FileWriter("test.txt")发生异常,此时fw依然为null 那么下面fw.close()将引发NullPointerException 对此在fw.close()之前加上if(fw!=null) 如果多个流分别关(多个if判断) */
4. FileWriter(String fileName, boolean append) :
/* 对已有文件的内容进行续写 把新的内容添加到文件的结尾 利用FileWriter中的 FileWriter(String fileName, boolean append) 根据给定的文件名以及指示是否附加写入数据的boolean值来构造 FileWriter 对象。 append - 一个 boolean 值,如果为 true,则将数据写入文件末尾处, 而不是写入文件开始处。 */ package filewriter; import java.io.FileWriter; import java.io.IOException; class FileWriterDemo3{ public static void main(String[] args){ FileWriter fw = null; try{ fw=new FileWriter("test.txt",true);//传递一个true参数,代表将不覆盖已有文件(若不存在 //该文件,则会创建)并在已有文件末尾处进行续写 fw.write("\r\nheixiu");//在windows下实现换行为两个字符\r\n,单独\r,\n无效果 } catch(IOException e){ System.out.println(e.toString()); } finally{ try{ if(fw!=null) fw.close(); } catch(IOException e){ System.out.println(e.toString()); } } } }
5.FileReader:
package filereader; import java.io.FileReader; import java.io.IOException; import java.io.FileNotFoundException; import static java.lang.System.out; class FileReaderDemo{ public static void main(String[] args){ //创建一个文件读取流对象,和指定名称的文件相关联 //要保证该文件是已经存在的,如果不存在,会抛出FileNotFoundException(IOException子类) FileReader fr=null; try{ fr = new FileReader("test.txt");//文本内容为b int ch=0; while((ch=fr.read())!=-1) out.println((char)ch); /* read()读取单个字符,一次读一个字符,会自动往下读 作为整数读取的字符,范围在0到65535之间(0x00-0xffff,char的范围), 如果已到达流的末尾,则返回 -1 */ } catch(IOException e){ e.printStackTrace(); } finally{ try{ if(fr!=null) fr.close(); } catch(IOException e){ out.println(e.toString()); } } } } /* 关于字符: ascll码中:128-255是IBM-PC上专用的。000-127是标准 也就是说: out.println((char)128);//? out.println((char)-1);//? //-1补码全1->强转为char->后16位全1(正)->2^16-1(65535) */
6.Reader:public int read(char[] cbuf) throws IOException
/* public int read(char[] cbuf) throws IOException 功能:将字符读入数组 返回:读取的字符数,如果已到达流的末尾,则返回 -1 (画一个示意图) */ package filereader; import java.io.FileReader; import java.io.IOException; import static java.lang.System.out; class FileReaderDemo2{ public static void main(String[] args)throws IOException{ FileReader fr = new FileReader("test.txt");//文件内容abcdefgchar[] buf = new char[3];//定义数组长度为3,通常定义为1024的整数倍 int num=0; while((num=fr.read(buf))!=-1) out.println(num+"..."+new String(buf,0,num)); fr.close(); } }
7.练习:read(char[] buf):
/* 读取一个.java文件打印到控制台上 */ package filereader; import java.io.FileReader; import java.io.IOException; import java.io.FileNotFoundException; import static java.lang.System.out; class FileReaderTest{ public static void main(String[] args){ FileReader fr =null; try{ fr=new FileReader("7_FileReaderTest.java");//当前java文件 char[] buf = new char[1024]; int readNum=0; while((readNum=fr.read(buf))!=-1) out.println(new String(buf,0,readNum));//分配一个新的 String,它包含取自字符数组参数一个子数组的字符。offset (第二个)参数是子数组第一个字符的索引,count(第三个)参数指定子数组的长度。 } catch(IOException e){ e.printStackTrace(); } finally{ try{ if(fr!=null) fr.close(); } catch(IOException e){ e.printStackTrace(); } } } }
8.文件拷贝:
/* 将C盘一个文本文件复制到D盘 其实就是将C盘下的文件数据存储到D盘的一个文件中 步骤: 1.在D盘创建一个文件,用于存储c盘文件中的数据 2.定义读取流和c盘文件关联. 3.通过不断读写完成数据存储 4.关闭资源. (画一个示意图) */ package copy; import static java.lang.System.out; import java.io.IOException; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.FileReader; class FileReaderTest2{ public static void copy(String fileName,String destPath){ FileReader fr=null; FileWriter fw=null; char[] buf = new char[1024]; try{ fr=new FileReader(fileName); String[] str=fileName.split("\\\\");//regex为\\\\,因为在java中\\表示一个\,而regex中\\也表示\,所以当\\\\解析成regex的时候为\\。 //正则表达式内容 fw=new FileWriter(destPath+str[str.length-1]);//以上分割成路径+文件名 两部分,可能路径有多级目录c:\\xx\\xx\\aa.txt int len=0; while((len=fr.read(buf))!=-1) fw.write(buf,0,len);//从数组0角标开始,读length=num个字符 } //假如只有4个字符,如果用write(buf)将把4+1020个全写入流中,因此需要只写读到的. catch(IOException e){ throw new RuntimeException("读写失败");//停掉程序 } finally{ if(fr!=null) try{ fr.close(); } catch(IOException e){ e.printStackTrace(); } if(fw!=null) try{ fw.close(); } catch(IOException e){ e.printStackTrace(); } } } /* 也可利用读一个写一个(但是循环次数增多,效率低) int ch=0; while((ch=fr.read())!=-1) fw.write(ch); */ public static void main(String[] args) { copy("c:\\abc.txt","e:\\"); } }
以上示意图: