1.Java IO四个重要抽象类
(1) InputStream(字节输入流)
(2) Reader(字符输入流)
(3) OutputStream
(4) Writer
2.文件相关
(1) 创建File对象:File()
(2) 创建、删除文件:createNewFile()、delete()
(3) 创建目录:mkdir()
(4) 列出目录中的文件:
public String[] list():只列出文件名字
public File[] listFiles():列出文件完整路径
(5) 运行可执行文件:
Runtime ec = Runtime.getRuntime();
ec.exec(可执行文件路径);
/** * 列出指定目录的全部内容 * */ import java.io.*; class hello{ public static void main(String[] args) { String fileName="D:"+File.separator; File f=new File(fileName); print(f); } public static void print(File f){ if(f!=null){ if(f.isDirectory()){ File[] fileArray=f.listFiles(); if(fileArray!=null){ for (int i = 0; i < fileArray.length; i++) { //递归调用 print(fileArray[i]); } } } else{ System.out.println(f); } } } }
3.文件字节流
(1) FileInputStream类:FileInputStream(String name)或FileInputStream(File file)
(2) FileOutputStream类:
4.文件字符流:
(1) FileReader类:
(2) FileWriter类:
(3) 字节流与字符流区别:字节流不能直接操作Unicode字符,由于汉字在文件中占用2字节,如果使用字节流,读取不当会出现乱码现象,采用字符流就可以避免这个现象,在Unicode字符中,一个汉字被看成一个字符。
注意:write()方法将数据首先写入到缓冲区,每当缓冲区溢出时,缓冲区的内容会自动写入到目的地,如果关闭流,缓冲区的内容会马上写入到目的地,流调用flush()方法可以立刻冲洗当前缓冲区,即将当前缓冲区的内容写入到目的地。
5.缓冲流:
(1) BufferedReader类:该输入流的指向必须是一个Reader流,BufferedReader流的源就是这个缓冲区,缓冲输入流再从缓冲区中读取数据。
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /** * 使用缓冲区从键盘上读入内容 * */ public class BufferedReaderDemo{ public static void main(String[] args){ BufferedReader buf = new BufferedReader( new InputStreamReader(System.in)); String str = null; System.out.println("请输入内容"); try{ str = buf.readLine(); }catch(IOException e){ e.printStackTrace(); } System.out.println("你输入的内容是:" + str); } }
(2) BufferedWriter类:调用newLine()可以向文件写入一个回行,调用flush()可以刷新缓冲区。
6.数组流:
(1) 数组字节流:ByteArrayInputStream 、ByteArrayOutputStream
流的源和目标都是字节数组,不会发生IO异常,toByteArray()可以返回输出流写入到缓冲区的全部字节
(2) 数组字符流:CharArrayReader、CharArrayWriter
流的源和目标都是字符数组,会发生IO异常,toCharArray()可以返回输出流写入到缓冲区的全部字符。
7.字符串流:
(1) StringReader类
(2) StringWriter类
流的源为字符串,toString()方法可以返回输出流写入到缓冲区的全部字符
8.数据流:当读取一个数值时,不必关心这个数值应当是多少个字节
(1) DataInputStream类:DataInputStream(InputStream in)
(2) DataOutputStream类:DataOutputStream(OutputStream out)
9.对象流:使用对象流写入或读入对象时,要保证对象是序列化的。一个类如果实现了Serializable接口,那么这个类创建的对象就是序列化的对象。使用对象流把一个对象写入到文件时不仅保证该对象是序列化的,而且该对象的成员对象也是序列化的。
(1) ObjectInputStream(InputStream in):
(2) ObjectOutputStream(OutputStream out):
(3) readObject()和writeObject(Object obj):
10.序列化和对象克隆
(1) 对象调用clone()方法就可以获取对象的“副本”,称为原对象的克隆对象,副本实体的变化不会引起原对象实体发成变化。
(2) 如果原对象有引用型成员变量,那么克隆对象对应的成员变量的引用就与原对象那个成员变量的引用相同,克隆对象对自己的这个成员变量所引用的实体的操作,将影响原对象引用型成员变量的实体,这就涉及深度克隆的问题,程序必须重写clone()方法,增加了编程的难度。
使用对象流很容易获取一个序列化对象的克隆。只需将该对象写入到对象输出流,然后用对象输入流读回的对象就是原对象的一个克隆。
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; class Goods implements Serializable { private static final long serialVersionUID = 1L; String name = null; public String getName() { return name; } public void setName(String name) { this.name = name; } public Goods(String name) { super(); this.name = name; } } class Shop implements Serializable { private static final long serialVersionUID = 1L; Goods goods[]; public Goods[] getGoods() { return goods; } public void setGoods(Goods[] goods) { this.goods = goods; } } public class Main{ public static void main(String[] args) { Shop shop1 = new Shop(); Goods s1[] = {new Goods("TV"), new Goods("PC")}; shop1.setGoods(s1); try { ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream objectOut = new ObjectOutputStream(out); objectOut.writeObject(shop1); ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); ObjectInputStream objectIn = new ObjectInputStream(in); Shop shop2 = (Shop)objectIn.readObject(); Goods good1[] = shop1.getGoods(); Goods good2[] = shop2.getGoods(); System.out.println("shop1中的商品:"); for(int i = 0; i < good1.length; i++) System.out.println(good1[i].getName()); System.out.println("shop2中的商品:"); for(int i = 0; i < good2.length; i++) System.out.println(good2[i].getName()); Goods s2[] = {new Goods("MP3"), new Goods("Phone")}; shop2.setGoods(s2); good1 = shop1.getGoods(); good2 = shop2.getGoods(); System.out.println("目前,shop1中的商品:"); for(int i = 0; i < good1.length; i++) System.out.println(good1[i].getName()); System.out.println("目前,shop2中的商品:"); for(int i = 0; i < good2.length; i++) System.out.println(good2[i].getName()); } catch (Exception e) { } } } 运行结果: shop1中的商品: TV PC shop2中的商品: TV PC 目前,shop1中的商品: TV PC 目前,shop2中的商品: MP3 Phone
(3)Externalizable接口:
被Serializable接口声明的类的对象的属性都将被序列化,但是如果想自定义序列化的内容的时候,就需要实现Externalizable接口。
当一个类要使用Externalizable这个接口的时候,这个类中必须要有一个无参的构造函数,如果没有的话,在构造的时候会产生异常,这是因为在反序列话的时候会默认调用无参的构造函数。
import java.io.Externalizable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; /** * 序列化和反序列化的操作 * */ public class ExternalizableDemo{ public static void main(String[] args) throws Exception{ ser(); // 序列化 dser(); // 反序列话 } public static void ser() throws Exception{ File file = new File("d:" + File.separator + "hello.txt"); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream( file)); out.writeObject(new Person("gaosheng", 20)); out.close(); } public static void dser() throws Exception{ File file = new File("d:" + File.separator + "hello.txt"); ObjectInputStream input = new ObjectInputStream(new FileInputStream( file)); Object obj = input.readObject(); input.close(); System.out.println(obj); } } class Person implements Externalizable{ public Person(){ } public Person(String name, int age){ this.name = name; this.age = age; } @Override public String toString(){ return "姓名:" + name + " 年龄:" + age; } // 复写这个方法,根据需要可以保存的属性或者具体内容,在序列化的时候使用 @Override public void writeExternal(ObjectOutput out) throws IOException{ out.writeObject(this.name); out.writeInt(age); } // 复写这个方法,根据需要读取内容 反序列话的时候需要 @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{ this.name = (String) in.readObject(); this.age = in.readInt(); } private String name; private int age; } 运行结果: 姓名:gaosheng 年龄:20
(4)当我们使用Serializable接口实现序列化操作的时候,如果一个对象的某一个属性不想被序列化保存下来,那么我们可以使用transient关键字进行说明
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; /** * 序列化和反序列化的操作 * */ public class serDemo{ public static void main(String[] args) throws Exception{ ser(); // 序列化 dser(); // 反序列话 } public static void ser() throws Exception{ File file = new File("d:" + File.separator + "hello.txt"); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream( file)); out.writeObject(new Person1("gaosheng", 20)); out.close(); } public static void dser() throws Exception{ File file = new File("d:" + File.separator + "hello.txt"); ObjectInputStream input = new ObjectInputStream(new FileInputStream( file)); Object obj = input.readObject(); input.close(); System.out.println(obj); } } class Person1 implements Serializable{ public Person1(){ } public Person1(String name, int age){ this.name = name; this.age = age; } @Override public String toString(){ return "姓名:" + name + " 年龄:" + age; } // 注意这里 private transient String name; private int age; } 运行结果: 姓名:null 年龄:20
11.管道流:管道流主要可以进行两个线程之间的通信。
/** * 验证管道流 * */ import java.io.*; /** * 消息发送类 * */ class Send implements Runnable{ private PipedOutputStream out=null; public Send() { out=new PipedOutputStream(); } public PipedOutputStream getOut(){ return this.out; } public void run(){ String message="hello , gaosheng"; try{ out.write(message.getBytes()); }catch (Exception e) { e.printStackTrace(); }try{ out.close(); }catch (Exception e) { e.printStackTrace(); } } } /** * 接受消息类 * */ class Recive implements Runnable{ private PipedInputStream input=null; public Recive(){ this.input=new PipedInputStream(); } public PipedInputStream getInput(){ return this.input; } public void run(){ byte[] b=new byte[1000]; int len=0; try{ len=this.input.read(b); }catch (Exception e) { e.printStackTrace(); }try{ input.close(); }catch (Exception e) { e.printStackTrace(); } System.out.println("接受的内容为 "+(new String(b,0,len))); } } /** * 测试类 * */ class hello{ public static void main(String[] args) throws IOException { Send send=new Send(); Recive recive=new Recive(); try{ //管道连接 send.getOut().connect(recive.getInput()); }catch (Exception e) { e.printStackTrace(); } new Thread(send).start(); new Thread(recive).start(); } } 运行结果: 接受的内容为 hello , gaosheng
12.随机读写流
(1) RandomAccessFile类创建的流的指向既可以作为源,也可以作为目的地。
(2) RandomAccessFile流的readLine()方法在读取含有非ASCII字符的文件时会出现乱码问题,使用以下方法读取:
String str = in.readLine();
byte b[] = str.getBytes(“iso-8895-1”);
String content = new String(b);
13.使用Scanner解析文件
(1) 使用Scanner类和正则表达式来解析文件的特点是以时间换取空间,即解析的速度相对较慢,但节省内存。
14.文件锁
(1) FileChannel channel = input.getChannel();
FileLock lock = channel.tryLock();//channel.lock();
…
lock.release();
15.输入输出重定向:保存错误日志数据等
import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; /** * System.err重定向 这个例子也提示我们可以使用这种方法保存错误信息 * */ public class systemErr{ public static void main(String[] args){ File file = new File("d:" + File.separator + "hello.txt"); System.err.println("这些在控制台输出"); try{ System.setErr(new PrintStream(new FileOutputStream(file))); // System.setOut(new PrintStream(new FileOutputStream(file))); }catch(FileNotFoundException e){ e.printStackTrace(); } System.err.println("这些在文件中才能看到哦!"); } }
16.其他流
(1)合并流:SequenceInputStream
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.SequenceInputStream; /** * 将两个文本文件合并为另外一个文本文件 * */ public class SequenceInputStreamDemo{ public static void main(String[] args) throws IOException{ File file1 = new File("d:" + File.separator + "hello1.txt"); File file2 = new File("d:" + File.separator + "hello2.txt"); File file3 = new File("d:" + File.separator + "hello.txt"); InputStream input1 = new FileInputStream(file1); InputStream input2 = new FileInputStream(file2); OutputStream output = new FileOutputStream(file3); // 合并流 SequenceInputStream sis = new SequenceInputStream(input1, input2); int temp = 0; while((temp = sis.read()) != -1){ output.write(temp); } input1.close(); input2.close(); output.close(); sis.close(); } }
(2)文件压缩解压流:ZipInputStream类、ZipOutputStream类
(3)回退流:PushbackInputStream类
17.总结
分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
抽象基类 | InputStream | OutputStream | Reader | Writer |
访问文件 | FileInputStream | FileOutputStream | FileReader | FileWriter |
访问数组 | ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter |
访问字符串 | StringReader | StringWriter | ||
缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
转换流 | InputStreamReader | OutputStreamWriter | ||
对象流 | ObjectInputStream | ObjectOutputStream | ||
抽象基类 | FilterInputStream | FilterOutputStream | FilterReader | FilterWriter |
打印流 | PrintStream | PrintWriter | ||
回退输入流 |
PushbackInputStream | PushbackReader | ||
特殊流 |
DataInputStream |
DataOutputStream |