java IO流-java学习笔记

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

 *                 DataInputStream(InputStream in)

  • 数据输出流:DataOutputStream

 *                 DataOutputStream(OutputStream out)

public class DataStreamDemo {

       public static void main(String[] args) throws IOException {

              // 写

              // write();



              // 读

              read();

       }



       private static void read() throws IOException {

              // DataInputStream(InputStream in)

              // 创建数据输入流对象

              DataInputStream dis = new DataInputStream(

                            new FileInputStream("dos.txt"));



              // 读数据//注意要对应

              byte b = dis.readByte();

              short s = dis.readShort();

              int i = dis.readInt();

              long l = dis.readLong();

              float f = dis.readFloat();

              double d = dis.readDouble();

              char c = dis.readChar();

              boolean bb = dis.readBoolean();



              // 释放资源

              dis.close();



              System.out.println(b);

              System.out.println(s);

              System.out.println(i);

              System.out.println(l);

              System.out.println(f);

              System.out.println(d);

              System.out.println(c);

              System.out.println(bb);

       }



       private static void write() throws IOException {

              // DataOutputStream(OutputStream out)

              // 创建数据输出流对象

              DataOutputStream dos = new DataOutputStream(new FileOutputStream(

                            "dos.txt"));



              // 写数据了

              dos.writeByte(10);

              dos.writeShort(100);

              dos.writeInt(1000);

              dos.writeLong(10000);

              dos.writeFloat(12.34F);

              dos.writeDouble(12.56);

              dos.writeChar('a');

              dos.writeBoolean(true);



              // 释放资源

              dos.close();

       }

}

3:内存操作流(理解)

       (1)有些时候我们操作完毕后,未必需要产生一个文件,就可以使用内存操作流。

       (2)三种

 * 内存操作流:用于处理临时存储信息的,程序结束,数据就从内存中消失。

 * 字节数组:

 *          ByteArrayInputStream

 *          ByteArrayOutputStream

 * 字符数组:

 *          CharArrayReader

 *          CharArrayWriter

 * 字符串:

 *          StringReader

 *          StringWriter

public class ByteArrayStreamDemo {

       public static void main(String[] args) throws IOException {

              // 写数据

              // ByteArrayOutputStream()

              ByteArrayOutputStream baos = new ByteArrayOutputStream();



              // 写数据

              for (int x = 0; x < 10; x++) {

                     baos.write(("hello" + x).getBytes());

              }



              // 释放资源

              // 通过查看源码我们知道这里什么都没做,所以根本需要close()

              // baos.close();



              // public byte[] toByteArray()

              byte[] bys = baos.toByteArray();



              // 读数据

              // ByteArrayInputStream(byte[] buf)

              ByteArrayInputStream bais = new ByteArrayInputStream(bys);



              int by = 0;

              while ((by = bais.read()) != -1) {

                     System.out.print((char) by);

              }



              // bais.close();

       }

}

4:打印流(掌握)

       (1)字节打印流,字符打印流

       (2)特点:

              * 打印流

 * 字节流打印流  PrintStream

 * 字符打印流      PrintWriter

 *

 * 打印流的特点:

  • A:只有写数据的,没有读取数据。只能操作目的地,不能操作数据源。
  • B:可以操作任意类型的数据。
  • C:如果启动了自动刷新,能够自动刷新。
  • D:该流是可以直接操作文本文件的。
  • 哪些流对象是可以直接操作文本文件的呢?
  • FileInputStream
  • FileOutputStream
  • FileReader
  • FileWriter
  • PrintStream
  • PrintWriter

 *                 看API,查流对象的构造方法,如果同时有File类型和String类型的参数,一般来说就是可以直接操作文件的。

 *

 *                 流:

 *                        基本流:就是能够直接读写文件的

 *                        高级流:在基本流基础上提供了一些其他的功能

* 1:可以操作任意类型的数据。

 *          print()

 *          println()

 * 2:启动自动刷新

  • PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true);
  • 还是应该调用println()的方法才可以
  • 这个时候不仅仅自动刷新了,还实现了数据的换行。
  • println()
  • 其实等价于于:
  • write();
  • newLine();
  • 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();

       }

}

       (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) {

  • println(line);

              }

             

              pw.close();

              br.close();

                    

5:标准输入输出流(理解)

       (1)System类下面有这样的两个字段

  in 标准输入流

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);

       }

}

  out 标准输出流

* 标准输入输出流

 * 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();

       }

}

  转换流的应用。

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);

       (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:获取和改变文件指针的位置

* 随机访问流:

 *          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)

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();

       }

}

           B:SequenceInputStream(Enumeration<? extends InputStream> e)

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值。

                     而且,这样也可以解决黄色警告线问题

* 序列化流:把对象按照流一样的方式存入文本文件或者在网络中传输。对象 -- 流数据(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();

       }

}

      

/*

 * 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 + "]";

       }

}

(4)面试题:

              什么时候序列化?

              如何实现序列化?

              什么是反序列化?

9:Properties(理解)

       (1)是一个集合类,Hashtable的子类

       (2)特有功能

              A:public Object setProperty(String key,String value)

              B:public String getProperty(String key)

              C:public Set<String> stringPropertyNames()

  • 特殊功能:
  • public Object setProperty(String key,String value):添加元素
  • public String getProperty(String key):获取元素
  • public Set<String> stringPropertyNames():获取所有的键的集合
public class PropertiesDemo2 {

      



public static void main(String[] args) {

              // 创建集合对象

              Properties prop = new Properties();

              // 添加元素

              prop.setProperty("张三", "30");

              prop.setProperty("李四", "40");

              prop.setProperty("王五", "50");



// public Set<String> stringPropertyNames():获取所有的键的集合

Set<String> set = prop.stringPropertyNames();

for (String key : set) {

       String value = prop.getProperty(key);

              System.out.println(key + "---" + value);

              }

       }

}

/*

 * class Hashtalbe<K,V> { public V put(K key,V value) { ... } }

 *

 * class Properties extends Hashtable { public V setProperty(String key,String

 * value) { return put(key,value); } }

(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)

这里的集合必须是Properties集合:

 * public void load(Reader reader):把文件中的数据读取到集合中

 * public void store(Writer writer,String comments):把集合中的数据存储到文件

 *

 * 单机版游戏:

 *          进度保存和加载。

 *          三国群英传,三国志,仙剑奇侠传...

 *

 *          吕布=1

 *          方天画戟=1

 */

public class PropertiesDemo3 {

       public static void main(String[] args) throws IOException {

              // myLoad();



              myStore();

       }



       private static void myStore() throws IOException {

              // 创建集合对象

              Properties prop = new Properties();



              prop.setProperty("林青霞", "27");

              prop.setProperty("武鑫", "30");

              prop.setProperty("刘晓曲", "18");

             

              //public void store(Writer writer,String comments):把集合中的数据存储到文件

              Writer w = new FileWriter("name.txt");

              prop.store(w, "helloworld");

              w.close();

       }



       private static void myLoad() throws IOException {

              Properties prop = new Properties();



              // public void load(Reader reader):把文件中的数据读取到集合中

              // 注意:这个文件的数据必须是键值对形式

              Reader r = new FileReader("prop.txt");

              prop.load(r);

              r.close();



              System.out.println("prop:" + prop);

       }

}

       (4)案例:

           A:根据给定的文件判断是否有键为"lisi"的,如果有就修改其值为100

  • 我有一个文本文件(user.txt),我知道数据是键值对形式的,但是不知道内容是什么。
  • 请写一个程序判断是否有“lisi”这样的键存在,如果有就改变其实为”100”
  • *
  • 分析:
  • A:把文件中的数据加载到集合中
  • B:遍历集合,获取得到每一个键
  • C:判断键是否有为"lisi"的,如果有就修改其值为"100"
  • D:把集合中的数据重新存储到文件中

 */

public class PropertiesTest {

       public static void main(String[] args) throws IOException {

              // 把文件中的数据加载到集合中

              Properties prop = new Properties();

              Reader r = new FileReader("user.txt");

              prop.load(r);

              r.close();



              // 遍历集合,获取得到每一个键

Set<String> set = prop.stringPropertyNames();

              for (String key : set) {

                     // 判断键是否有为"lisi"的,如果有就修改其值为"100"

                     if ("lisi".equals(key)) {

                            prop.setProperty(key, "100");

                            break;

                     }

              }



              // 把集合中的数据重新存储到文件中

              Writer w = new FileWriter("user.txt");

              prop.store(w, null);

              w.close();

       }

}

           B:写一个程序实现控制猜数字小游戏程序不能玩超过5次

* 我有一个猜数字小游戏的程序,请写一个程序实现在测试类中只能用5次,超过5次提示:游戏试玩已结束,请付费。

public class PropertiesTest2 {

       public static void main(String[] args) throws IOException {

              // 读取某个地方的数据,如果次数不大于5,可以继续玩。否则就提示"游戏试玩已结束,请付费。"

              // 创建一个文件

              // File file = new File("count.txt");

              // if (!file.exists()) {

              // file.createNewFile();

              // }

              // 把数据加载到集合中

              Properties prop = new Properties();

              Reader r = new FileReader("count.txt");

              prop.load(r);

              r.close();

       // 我自己的程序,我当然知道里面的键是谁

              String value = prop.getProperty("count");

              int number = Integer.parseInt(value);



              if (number > 5) {

                     System.out.println("游戏试玩已结束,请付费。");

                     System.exit(0);

              } else {

                     number++;

prop.setProperty("count",String.valueOf(number));

              Writer w = new FileWriter("count.txt");

                     prop.store(w, null);

                     w.close();

                     GuessNumber.start();

              }

       }

}

(了解)

(1)JDK4出现的NIO,对以前的IO操作进行了优化,提供了效率。但是大部分我们看到的还是以前的IO

(2)JDK7的NIO的使用      

              Path:路径

              Paths:通过静态方法返回一个路径

              Files:提供了常见的功能

                     复制文本文件

                     把集合中的数据写到文本文件

* nio包在JDK4出现,提供了IO流的操作效率。但是目前还不是大范围的使用。

 * 有空的话了解下,有问题再问我。

* JDK7的之后的nio:

 * Path:路径

 * Paths:有一个静态方法返回一个路径

 *          public static Path get(URI uri)

 * Files:提供了静态方法供我们使用

 *          public static long copy(Path source,OutputStream out):复制文件

 *          public static Path write(Path path,Iterable<? extends CharSequence> lines,Charset cs,OpenOption... options)

public class NIODemo {

       public static void main(String[] args) throws IOException {

// public static long copy(Path source,OutputStream out)

// Files.copy(Paths.get("ByteArrayStreamDemo.java"), new

              // FileOutputStream(

              // "Copy.java"));

              ArrayList<String> array = new ArrayList<String>();

              array.add("hello");

              array.add("world");

              array.add("java");

              Files.write(Paths.get("array.txt"), array, Charset.forName("GBK"));

       }

}

转载 http://www.51csdn.cn/article/251.html 

猜你喜欢

转载自blog.csdn.net/qq_43599835/article/details/84873064