[黑马程序员] I/O
0. IO流概述:
- Java对数据的操作是通过流的方式.
- IO流用来处理设备之间的数据传输.
- Java用于操作流的对象都在IO包中.
1. IO流的分类:
- 按所操作数据: 字节流、字符流
- 按流向: 输入流、输出流
2. IO流常用基类:
- 字节流的抽象基类: InputStream, OutputStream
- 字符流的抽象基类: reader, Writer
- p.s. 由这四个类派生的子类, 名称都是以其父类名作后缀的.
3. IO程序的一般书写流程:
- 导包.
- IO异常处理.
- 在finally中关闭流.
==============开始字符流的========================
4. FileWriter的小栗子:
import java.io.*; class Demo{ public static void main(String args[]) throws Exception{ //创建一个FileWriter对象,该对象一被初始化,就必须要明确被操作的文件 //而且该文件会被创建到指定目录下,如果该目录下已有同名的文件,将被覆盖。 //其实该步就是明确数据要存放的目的地 FileWriter fw = new FileWriter("Demo.txt"); //调用writer方法,将字符串写入到流中,会产生异常 fw.write("abc"); //刷新该流的缓冲。将数据刷新到文件中 fw.write("def"); fw.flush(); //关闭刘子源,但是关闭之前会刷新一次内部的缓冲的数据。,将数据刷到目的地中,和flush区别,flush(),刷新后,流可以继续使用,close刷新后,会将流关闭。 //操作完,必须关闭 fw.close(); } public static void sop(Object obj){ System.out.println(obj.toString()); } }
5. FileWriter的异常处理例子:
import java.io.*; class FileWriterDemo2 { public static void main(String[] args) { FileWriter fw=null;//需要在代码块外边建立引用. try { fw=new FileWriter("demo.txt",true); fw.write("accd\r\nde"); } catch (IOException e) { System.out.println(e.toString()); } finally { if(fw!=null)//判断fw是否为空.如果输入盘符错误的话.fw会是null;将执行不到close所以要判断 try { fw.close(); } catch (IOException e) { System.out.println("关闭资源失败"); } } } }
6. 读取的例子(先读入到数组中):
import java.io.*; class FileWriterDemo2 { public static void main(String[] args) { FileWriter fw=null;//需要在代码块外边建立引用. try { fw=new FileWriter("demo.txt",true); fw.write("accd\r\nde"); } catch (IOException e) { System.out.println(e.toString()); } finally { if(fw!=null)//判断fw是否为空.如果输入盘符错误的话.fw会是null;将执行不到close所以要判断 try { fw.close(); } catch (IOException e) { System.out.println("关闭资源失败"); } } } }
7. ** 复制文本文件的栗子:
import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class CopyText { public static void main(String[] args) throws IOException{ //copy_1(); copy_2(); } //一个char一个char地复制, 不建议 public static void copy_1() throws IOException { FileReader fr = new FileReader("C:\\CCCC.txt"); FileWriter fw = new FileWriter("D:\\CCCC.txt"); int ch=0; while((ch = fr.read()) != -1) { fw.write(ch); } fw.close(); fr.close(); } //用数组做缓冲, 建议这样 public static void copy_2() { FileWriter fw = null; //* 养成习惯, 局部变量直接初始化一下. FileReader fr = null; try { fr = new FileReader("C:\\CCCC.txt"); fw = new FileWriter("D:\\CCCC.txt"); char[] buf = new char[1024]; int len = 0; while((len = fr.read(buf)) != -1) { fw.write(buf, 0, len); } } 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) { } } } }
8. 字符流的缓冲区:
- 对应类: BufferedWriter, BufferedReader
- 缓冲区提高了读写效率
- 缓冲区要结合流才能使用
- 在流的基础上对流的功能进行了增强
- * 关闭缓冲区, 其实就是关闭缓冲区里的流对象
9.
BufferedWriter
例子:
import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; class Test2 { public static void main(String [] args) throws IOException { FileWriter fw = new FileWriter("buf.txt"); BufferedWriter bufw = new BufferedWriter(fw); bufw.write("abcde"); bufw.newLine(); //换行, 跨平台实现. bufw.flush(); //用到缓冲区都要flush bufw.close(); //缓冲区关闭, 其实就是在关闭fw流 } }
10. BufferedReader栗子:
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; class Test2 { public static void main(String [] args) throws IOException { FileReader fr = new FileReader("buf.txt"); BufferedReader bufr = new BufferedReader(fr); String line = null; while((line=bufr.readLine()) != null) { System.out.println(line); } bufr.close(); } }
11. 通过缓冲区复制文本文件:
import java.io.*; public class CopyTextByBuf { public static void main(String[] args) { BufferedReader bufr = null; BufferedWriter bufw = null; try { bufr = new BufferedReader(new FileReader("bufr.txt")); bufw = new BufferedWriter(new FileWriter("bufw.txt")); String line = null; while((line=bufr.readLine()) != null) { bufw.write(line); bufw.newLine(); //因为readLine()返回值并不带有行终止符, 所以自己来 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("写入关闭失败"); } } } }
12. 模拟BufferedReader的readLine()方法:
import java.io.FileReader; import java.io.IOException; /* * 模拟BufferedReader的readLine()方法, 写一个一次读取一行数据的方法. */ class MyBufferedReader { private FileReader r; MyBufferedReader(FileReader r) { this.r = r; } public String myReadLine() throws IOException { //定义一个临时容器, 原BufferedReader封装的是字符数组看这里用StringBuilder StringBuilder sb = new StringBuilder(); int ch = 0; while((ch=r.read()) != -1) { if(ch=='\r') //这个回车 continue; if(ch=='\n') //这是换行 return sb.toString(); else sb.append((char)ch); } return null; } public void myClose() throws IOException { r.close(); } }
13.
*
装饰设计模式(之前讲过单例和模板模式):
- 当想要对已有对象的功能进行功能增强时, 可以定义一个类, 将已有对象传入, 基于已有对象的功能提供加强功能. 自定义的该类称为* 装饰类.
- 装饰类通常会通过构造方法接收被装饰的对象.
14.
*
装饰与继承的区别:
答: 装饰模式比继承灵活, 避免了继承体系的臃肿. (继承需要好多子类, 而用装饰模式可以多态的形式装饰许多类. 提高扩展性.)
装饰类因为是增强已有对象, 具备的功能和已有对象是相同的, 只不过提供了更强的功能. 所以装饰类和被装饰类通常属于一个体系中.
==============下面是字节流的========================
15. 比如说想要操作图片数据, 就要用字节流了.
16. 字节流: InputStream, OutputStream
17. 复制一个图片:
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class CopyPic { public static void main(String[] args) { FileOutputStream fos = null; FileInputStream fis = null; try { fos = new FileOutputStream("d:\\A.jpg"); fis = new FileInputStream("c:\\A.jpg"); byte[] buf = new byte[1024]; int len = 0; while((len=fis.read(buf)) != -1) { fos.write(buf, 0, len); } } catch(IOException e) { throw new RuntimeException("复制文件失败"); } finally { try { if(fos!=null) fos.close(); } catch(IOException e) { throw new RuntimeException("读取关闭失败"); } try { if(fis!=null) fis.close(); } catch(IOException e) { throw new RuntimeException("写入关闭失败"); } } } }
18. 字节流也有对应的BufferedInputStream和BufferedOutputStream类.
19. * 读取键盘录入:
- System.out: 对应的是标准输出设备, 默认屏幕.
- System.in: 对应的是标准输入设备, 默认键盘.
例子:
/* * 录入一行, 然后输出. * 若是over, 则停止. */ import java.io.IOException; import java.io.InputStream; public class ReadIn { public static void main(String[] args) throws IOException { InputStream in = System.in; //标准输入流 StringBuilder sb = new StringBuilder(); while(true) { int ch = in.read(); if(ch=='\r') continue; if(ch=='\n') { String s = sb.toString(); if("over".equals(s)) //判断是否是over break; System.out.println(s.toUpperCase()); sb.delete(0, sb.length()); } else sb.append((char)ch); } } }
20. 转换流:
- InputStreamReader和OutputStreamWriter: 字节流转成字符流.
- 没有ReadInputStream和WriterOutputStream.
21. 改变标准输入输出设备.
public static void setIn(InputStream in): 改为指定的输入流.
==============下面是File的========================
22. java.io.File: 用来将文件或者文件夹封装成对象.
23. File.separator: 目录分隔符.
24. 常用方法:
- 创建
- boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false. 和输出流不一样棒,输出流对象一建立就创建文件,而且文件已经存在,会覆盖.
- boolean mkdir() 创建此抽象路径名指定的目录。
- 删除
- boolean delete() 删除此抽象路径名表示的文件或目录。
- void deleteOnExit() 在虚拟机终止时,请求删除此抽象路径名表示的文件或目录. 当被操作时候,删除不了,所以等虚拟机终止时,删除.
- 判断
- boolean canExecute() 测试应用程序是否可以执行此抽象路径名表示的文件。
- boolean canRead() 测试应用程序是否可以读取此抽象路径名表示的文件。
- boolean canWrite() 测试应用程序是否可以修改此抽象路径名表示的文件。
- int compareTo(File pathname) 按字母顺序比较两个抽象路径名
- boolean exists() 测试此抽象路径名表示的文件或目录是否存在
- boolean isAbsolute() 测试此抽象路径名是否为绝对路径名
- 判断类型时候。必须先判断是否存在
- boolean isDirectory() 测试此抽象路径名表示的文件是否是一个目录
- boolean isFile() 测试此抽象路径名表示的文件是否是一个标准文件。
- 获取信息
- String getName()
- String getPath
- String getParent() 此抽象路径名指定父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null
- String getAbsolutPath()
- String getAbsolutFile() 绝对路径对象
- long lastModified()
- long length() 返回由此抽象路径名表示的文件的长度。
25. 递归输出文件列表:
import java.io.File; public class FileDemo3 { public static void main(String[] args) { File dir = new File("F:\\itcast_video\\Java基础加强(5-7天)2010年Java高新技术"); showDir(dir); } public static void showDir(File dir) { System.out.println(dir); // 输出目录 File[] files = dir.listFiles(); for(int x=0; x<files.length; x++) // 输出文件 { if(files[x].isDirectory()) showDir(files[x]); else System.out.println(files[x]); } } }
26. 删除带内容的目录: 在Windows中的原理是从内往外删除.
==============下面是Properties的========================
27. java.util.Properties是hashtable的子类.
- 它里面存的键值对都是字符串.
- 是集合和IO技术相结合的集合容器.
- ? 可以用于键值对形式的配置文件.
28. 例子:
/* 演示,如何将流中的数据存储到集合中 想要将 info.txt 中的键值对数据存到集合中进行操作。 1、用一个流和info.txt文件关联 2、读取一行数据。将改行数据用"="进行切割。 3、等号左边作为键,右边作为值,存入到Properties集合中即可 */ import java.io.*; import java.util.*; public class Demo{ public static void main(String args[])throws IOException{ loadDemo(); } public static void loadDemo()throws IOException{ FileInputStream fis = new FileInputStream("info.txt"); Properties prop = new Properties(); prop.load(fis); sop(prop); FileOutputStream fos = new FileOutputStream("info.txt"); prop.store(fos,"haha"); prop.list(System.out); fos.close(); fis.close(); } //设置和获取元素 public static void method()throws IOException{ BufferedReader bufr = new BufferedReader(new FileReader("info.txt")); String line = null; Properties prop = new Properties(); while((line=bufr.readLine())!=null){ String[] arr = line.split("="); prop.setProperty(arr[0],arr[1]); sop(prop); } } public static void sop(Object obj){ System.out.println(obj.toString()); } }
=====================其 他========================
29. 很多, 只需了解, 用的时候细查API文档即可:
- 打印流: PrintWriter 与 PrintStream: 可以直接操作输入流和文件.
- 序列流: SequenceInputStream: 对多个流进行合并.
- 操作对象: ObjectInputStream 与 ObjectOutputStream: 被操作的对象需要实现 Serializale (标记接口).