1:登录注册IO版本案例(掌握)
要求,对着写一遍。
cn.itcast.pojo User
cn.itcast.dao UserDao
cn.itcast.dao.impl UserDaoImpl(实现我不管)
cn.itcast.game GuessNumber
cn.itcast.test UserTest
2:数据操作流(操作基本类型数据的流)(理解)
(1)可以操作基本类型的数据
(2)流对象名称
DataInputStream
DataOutputStream
3:内存操作流(理解)
(1)有些时候我们操作完毕后,未必需要产生一个文件,就可以使用内存操作流。
(2)三种
A:ByteArrayInputStream,ByteArrayOutputStream
B:CharArrayReader,CharArrayWriter
C:StringReader,StringWriter
4:打印流(掌握)
(1)字节打印流,字符打印流
(2)特点:
A:只操作目的地,不操作数据源
B:可以操作任意类型的数据
C:如果启用了自动刷新,在调用println()方法的时候,能够换行并刷新
D:可以直接操作文件
问题:哪些流可以直接操作文件呢?
看API,如果其构造方法能够同时接收File和String类型的参数,一般都是可以直接操作文件的
(3)复制文本文件
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
PrintWriter pw = new PrintWriter(new FileWriter("b.txt"),true);
String line = null;
while((line=br.readLine())!=null) {
pw.println(line);
}
pw.close();
br.close();
Demo:
import java.io.IOException; import java.io.PrintWriter; /* * 打印流 * 字节流打印流 PrintStream * 字符打印流 PrintWriter * * 打印流的特点: * A:只有写数据的,没有读取数据。只能操作目的地,不能操作数据源。 * B:可以操作任意类型的数据。 * C:如果启动了自动刷新,能够自动刷新。 * D:该流是可以直接操作文本文件的。 * 哪些流对象是可以直接操作文本文件的呢? * FileInputStream * FileOutputStream * FileReader * FileWriter * PrintStream * PrintWriter * 看API,查流对象的构造方法,如果同时有File类型和String类型的参数,一般来说就是可以直接操作文件的。 * * 流: * 基本流:就是能够直接读写文件的 * 高级流:在基本流基础上提供了一些其他的功能 */ public class PrintWriterDemo { public static void main(String[] args) throws IOException { // 作为Writer的子类使用 PrintWriter pw = new PrintWriter("pw.txt"); pw.write("hello"); pw.write("world"); pw.write("java"); pw.close(); } }
Demo2:
import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; /* * 1:可以操作任意类型的数据。 * print() * println() * 2:启动自动刷新 * PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true); * 还是应该调用println()的方法才可以 * 这个时候不仅仅自动刷新了,还实现了数据的换行。 * * println() * 其实等价于于: * bw.write(); * bw.newLine(); * bw.flush(); */ public class PrintWriterDemo2 { public static void main(String[] args) throws IOException { // 创建打印流对象 // PrintWriter pw = new PrintWriter("pw2.txt"); PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true); // write()是搞不定的,怎么办呢? // 我们就应该看看它的新方法 // pw.print(true); // pw.print(100); // pw.print("hello"); pw.println("hello"); pw.println(true); pw.println(100); pw.close(); } }
5:标准输入输出流(理解)
(1)System类下面有这样的两个字段
in 标准输入流
out 标准输出流
Demo:
import java.io.PrintStream; /* * 标准输入输出流 * System类中的两个成员变量: * public static final InputStream in “标准”输入流。 * public static final PrintStream out “标准”输出流。 * * InputStream is = System.in; * PrintStream ps = System.out; */ public class SystemOutDemo { public static void main(String[] args) { // 有这里的讲解我们就知道了,这个输出语句其本质是IO流操作,把数据输出到控制台。 System.out.println("helloworld"); // 获取标准输出流对象 PrintStream ps = System.out; ps.println("helloworld"); ps.println(); // ps.print();//这个方法不存在 // System.out.println(); // System.out.print(); } }
Demo2:
import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStreamWriter; /* * 转换流的应用。 */ public class SystemOutDemo2 { public static void main(String[] args) throws IOException { // 获取标准输入流 // // PrintStream ps = System.out; // // OutputStream os = ps; // OutputStream os = System.out; // 多态 // // 我能不能按照刚才使用标准输入流的方式一样把数据输出到控制台呢? // OutputStreamWriter osw = new OutputStreamWriter(os); // BufferedWriter bw = new BufferedWriter(osw); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter( System.out)); bw.write("hello"); bw.newLine(); // bw.flush(); bw.write("world"); bw.newLine(); // bw.flush(); bw.write("java"); bw.newLine(); bw.flush(); bw.close(); } }
(2)三种键盘录入方式
A:main方法的args接收参数
B:System.in通过BufferedReader进行包装
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
C:Scanner
Scanner sc = new Scanner(System.in);
Demo:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /* * System.in 标准输入流。是从键盘获取数据的 * * 键盘录入数据: * A:main方法的args接收参数。 * java HelloWorld hello world java * B:Scanner(JDK5以后的) * Scanner sc = new Scanner(System.in); * String s = sc.nextLine(); * int x = sc.nextInt() * C:通过字符缓冲流包装标准输入流实现 * BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); */ public class SystemInDemo { public static void main(String[] args) throws IOException { // //获取标准输入流 // InputStream is = System.in; // //我要一次获取一行行不行呢? // //行。 // //怎么实现呢? // //要想实现,首先你得知道一次读取一行数据的方法是哪个呢? // //readLine() // //而这个方法在哪个类中呢? // //BufferedReader // //所以,你这次应该创建BufferedReader的对象,但是底层还是的使用标准输入流 // // BufferedReader br = new BufferedReader(is); // //按照我们的推想,现在应该可以了,但是却报错了 // //原因是:字符缓冲流只能针对字符流操作,而你现在是字节流,所以不能是用? // //那么,我还就想使用了,请大家给我一个解决方案? // //把字节流转换为字符流,然后在通过字符缓冲流操作 // InputStreamReader isr = new InputStreamReader(is); // BufferedReader br= new BufferedReader(isr); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.println("请输入一个字符串:"); String line = br.readLine(); System.out.println("你输入的字符串是:" + line); System.out.println("请输入一个整数:"); // int i = Integer.parseInt(br.readLine()); line = br.readLine(); int i = Integer.parseInt(line); System.out.println("你输入的整数是:" + i); } }
(3)输出语句的原理和如何使用字符流输出数据
A:原理
System.out.println("helloworld");
PrintStream ps = System.out;
ps.println("helloworld");
B:把System.out用字符缓冲流包装一下使用
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
6:随机访问流(理解)
(1)可以按照文件指针的位置写数据和读数据。
(2)案例:
A:写数据
B:读数据
C:获取和改变文件指针的位置
Demo:
import java.io.IOException; import java.io.RandomAccessFile; /* * 随机访问流: * RandomAccessFile类不属于流,是Object类的子类。 * 但它融合了InputStream和OutputStream的功能。 * 支持对文件的随机访问读取和写入。 * * public RandomAccessFile(String name,String mode):第一个参数是文件路径,第二个参数是操作文件的模式。 * 模式有四种,我们最常用的一种叫"rw",这种方式表示我既可以写数据,也可以读取数据 */ public class RandomAccessFileDemo { public static void main(String[] args) throws IOException { // write(); read(); } private static void read() throws IOException { // 创建随机访问流对象 RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw"); int i = raf.readInt(); System.out.println(i); // 该文件指针可以通过 getFilePointer方法读取,并通过 seek 方法设置。 System.out.println("当前文件的指针位置是:" + raf.getFilePointer()); char ch = raf.readChar(); System.out.println(ch); System.out.println("当前文件的指针位置是:" + raf.getFilePointer()); String s = raf.readUTF(); System.out.println(s); System.out.println("当前文件的指针位置是:" + raf.getFilePointer()); // 我不想重头开始了,我就要读取a,怎么办呢? raf.seek(4); ch = raf.readChar(); System.out.println(ch); } private static void write() throws IOException { // 创建随机访问流对象 RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw"); // 怎么玩呢? raf.writeInt(100); raf.writeChar('a'); raf.writeUTF("中国"); raf.close(); } }
7:合并流(理解)
(1)把多个输入流的数据写到一个输出流中。
(2)构造方法:
A:SequenceInputStream(InputStream s1, InputStream s2)
B:SequenceInputStream(Enumeration<? extends InputStream> e)
Demo:
import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.SequenceInputStream; /* * 以前的操作: * a.txt -- b.txt * c.txt -- d.txt * * 现在想要: * a.txt+b.txt -- c.txt */ public class SequenceInputStreamDemo { public static void main(String[] args) throws IOException { // SequenceInputStream(InputStream s1, InputStream s2) // 需求:把ByteArrayStreamDemo.java和DataStreamDemo.java的内容复制到Copy.java中 InputStream s1 = new FileInputStream("ByteArrayStreamDemo.java"); InputStream s2 = new FileInputStream("DataStreamDemo.java"); SequenceInputStream sis = new SequenceInputStream(s1, s2); BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream("Copy.java")); // 如何写读写呢,其实很简单,你就按照以前怎么读写,现在还是怎么读写 byte[] bys = new byte[1024]; int len = 0; while ((len = sis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); sis.close(); } }
Demo2:
import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.SequenceInputStream; import java.util.Enumeration; import java.util.Vector; /* * 以前的操作: * a.txt -- b.txt * c.txt -- d.txt * e.txt -- f.txt * * 现在想要: * a.txt+b.txt+c.txt -- d.txt */ public class SequenceInputStreamDemo2 { public static void main(String[] args) throws IOException { // 需求:把下面的三个文件的内容复制到Copy.java中 // ByteArrayStreamDemo.java,CopyFileDemo.java,DataStreamDemo.java // SequenceInputStream(Enumeration e) // 通过简单的回顾我们知道了Enumeration是Vector中的一个方法的返回值类型。 // Enumeration<E> elements() Vector<InputStream> v = new Vector<InputStream>(); InputStream s1 = new FileInputStream("ByteArrayStreamDemo.java"); InputStream s2 = new FileInputStream("CopyFileDemo.java"); InputStream s3 = new FileInputStream("DataStreamDemo.java"); v.add(s1); v.add(s2); v.add(s3); Enumeration<InputStream> en = v.elements(); SequenceInputStream sis = new SequenceInputStream(en); BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream("Copy.java")); // 如何写读写呢,其实很简单,你就按照以前怎么读写,现在还是怎么读写 byte[] bys = new byte[1024]; int len = 0; while ((len = sis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); sis.close(); } }
8:序列化流(理解)
(1)可以把对象写入文本文件或者在网络中传输
(2)如何实现序列化呢?
让被序列化的对象所属类实现序列化接口。
该接口是一个标记接口。没有功能需要实现。
(3)注意问题:
把数据写到文件后,在去修改类会产生一个问题。
如何解决该问题呢?
在类文件中,给出一个固定的序列化id值。
而且,这样也可以解决×××警告线问题
(4)面试题:
什么时候序列化?
如何实现序列化?
什么是反序列化?
Person类:
import java.io.Serializable; /* * NotSerializableException:未序列化异常 * * 类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。 * 该接口居然没有任何方法,类似于这种没有方法的接口被称为标记接口。 * * java.io.InvalidClassException: * cn.itcast_07.Person; local class incompatible: * stream classdesc serialVersionUID = -2071565876962058344, * local class serialVersionUID = -8345153069362641443 * * 为什么会有问题呢? * Person类实现了序列化接口,那么它本身也应该有一个标记值。 * 这个标记值假设是100。 * 开始的时候: * Person.class -- id=100 * wirte数据: oos.txt -- id=100 * read数据: oos.txt -- id=100 * * 现在: * Person.class -- id=200 * wirte数据: oos.txt -- id=100 * read数据: oos.txt -- id=100 * 我们在实际开发中,可能还需要使用以前写过的数据,不能重新写入。怎么办呢? * 回想一下原因是因为它们的id值不匹配。 * 每次修改java文件的内容的时候,class文件的id值都会发生改变。 * 而读取文件的时候,会和class文件中的id值进行匹配。所以,就会出问题。 * 但是呢,如果我有办法,让这个id值在java文件中是一个固定的值,这样,你修改文件的时候,这个id值还会发生改变吗? * 不会。现在的关键是我如何能够知道这个id值如何表示的呢? * 不用担心,你不用记住,也没关系,点击鼠标即可。 * 你难道没有看到×××警告线吗? * * 我们要知道的是: * 看到类实现了序列化接口的时候,要想解决×××警告线问题,就可以自动产生一个序列化id值。 * 而且产生这个值以后,我们对类进行任何改动,它读取以前的数据是没有问题的。 * * 注意: * 我一个类中可能有很多的成员变量,有些我不想进行序列化。请问该怎么办呢? * 使用transient关键字声明不需要序列化的成员变量 */ public class Person implements Serializable { private static final long serialVersionUID = -2071565876962058344L; private String name; // private int age; private transient int age; // int age; public Person() { super(); } public Person(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
Demo:
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; /* * 序列化流:把对象按照流一样的方式存入文本文件或者在网络中传输。对象 -- 流数据(ObjectOutputStream) * 反序列化流:把文本文件中的流对象数据或者网络中的流对象数据还原成对象。流数据 -- 对象(ObjectInputStream) */ public class ObjectStreamDemo { public static void main(String[] args) throws IOException, ClassNotFoundException { // 由于我们要对对象进行序列化,所以我们先自定义一个类 // 序列化数据其实就是把对象写到文本文件 // write(); read(); } private static void read() throws IOException, ClassNotFoundException { // 创建反序列化对象 ObjectInputStream ois = new ObjectInputStream(new FileInputStream( "oos.txt")); // 还原对象 Object obj = ois.readObject(); // 释放资源 ois.close(); // 输出对象 System.out.println(obj); } private static void write() throws IOException { // 创建序列化流对象 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream( "oos.txt")); // 创建对象 Person p = new Person("林青霞", 27); // public final void writeObject(Object obj) oos.writeObject(p); // 释放资源 oos.close(); } }
9:Properties(理解)
(1)是一个集合类,Hashtable的子类
(2)特有功能
A:public Object setProperty(String key,String value)
B:public String getProperty(String key)
C:public Set<String> stringPropertyNames()
(3)和IO流结合的方法
把键值对形式的文本文件内容加载到集合中
public void load(Reader reader)
public void load(InputStream inStream)
把集合中的数据存储到文本文件中
public void store(Writer writer,String comments)
public void store(OutputStream out,String comments)
(4)案例:
A:根据给定的文件判断是否有键为"lisi"的,如果有就修改其值为100
B:写一个程序实现控制猜数字小游戏程序不能玩超过5次
10:NIO(了解)
(1)JDK4出现的NIO,对以前的IO操作进行了优化,提供了效率。但是大部分我们看到的还是以前的IO
(2)JDK7的NIO的使用
Path:路径
Paths:通过静态方法返回一个路径
Files:提供了常见的功能
复制文本文件
把集合中的数据写到文本文件