一、流的操作规律
四个明确:
明确一:明确要操作的数据是数据源还是数据目的地
源:InputStream Reader
目的地:OutputStream Writer
先根据需求明确是要读还是写
明确二:明确要操作的数据是字节还是文件(字符)
源:
字节:InputStream
文件:Reader
目的地:
字节:OutputStream
文件:Writer
已经明确到了具体的体系上
明确三:明确数据所在的具体设备
源设备:
硬盘:文件 File开头。
内存:数组,字符串。
键盘:System.in;
网络:Socket
目的设备:
硬盘:文件 File开头。
内存:数组,字符串。
屏幕:System.out
网络:Socket
完全可以明确具体要使用哪个流对象
明确四:是否需要额外功能
额外功能:是否需要转换?转换流:OutputStreamWriter InputStreamReader
是否需要加速?缓冲流:BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter
字节输入流:
InputStream
FileInputStream
BufferedInputStream
字节输出流:
OuputStream
FileOutputStream
BufferedOuputStream
字符输出流:
Writer
OutputStreamWriter
FileWriter
BufferedWriter
字符输入流
Reader
InputStreamReader
FileReader
BufferedReader
二、Properties类
Properties类表示了一个持久的属性集。可保存在流中或从流中加载。属性列表中每个键及对应的值都是字符串。
特点:
1、HashTable的子类,Map集合中的方法都可以使用
2、该集合没有泛型,键值都是字符串。
3、它是一个可以持久化的属性集。键值可以存储到集合中,也可以存储到持久化的设备上(硬盘、U盘上),也可以从持久化设备上被获取。
4、有和流技术相结合的地方
Properties类的方法:
1.load(); 从文件中读取键值对,并可以保存到集合中
2.store();将键值对输出到文件中,comments就是键值对的描述信息。
实例代码:1、 读取硬盘上的Properties文件:
package com.oracle.Demo01; import java.io.FileInputStream; import java.io.IOException; import java.util.Properties; import java.util.Set; public class Demo04 { //读取硬盘上的properties文件 public static void main(String[] args) throws IOException { // TODO Auto-generated method stub Properties pro=new Properties(); FileInputStream fis=new FileInputStream("e:\java\pro.properties"); pro.load(fis); Set<String> set=pro.stringPropertyNames(); for(String s:set){ System.out.println(s+"..."+pro.getProperty(s)); } fis.close(); } }
2.将键值对写入文件
package com.oracle.Demo01; import java.io.FileOutputStream; import java.io.IOException; import java.util.Properties; public class Demo05 { //将键值对写入文件 public static void main(String[] args) throws IOException { //properties是一个集合类,里面有操作IO流的方法 Properties pro=new Properties(); pro.setProperty("school", "jianghua"); pro.setProperty("father", "ligang"); FileOutputStream fos=new FileOutputStream("e:\java\pro.properties",true); pro.store(fos, "message"); fos.close(); } }
3.复制键值对
package com.oracle.Demo01; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Properties; public class PropertiesCopy { public static void main(String[] args) throws IOException { //1.获取数据源 Properties pro1=new Properties(); FileInputStream fis=new FileInputStream("e:\java\pro.properties"); //将文件中的数据存入属性集 pro1.load(fis); //2.确定目的地 FileOutputStream fos=new FileOutputStream("d:\java\pro.properties"); //将数据写入文件 pro1.store(fos, "message"); //3.释放资源 fos.flush(); fos.close(); fis.close(); } }
三、序列化流与反序列化流
用于向流中写入对象的操作流ObjectOutputStream,叫做序列化流,用于从流中读取对象的操作流ObjectInputStream,叫做反序列化流。
特点:用于操作对象,可以将对象写入文件或从文件中读取对象。
1.序列化流 ObjectOutputStream
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。
注意:只能将支持 java.io.Serializable 接口的对象写入流中
2.反序列化流ObjectInputStream
ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。支持 java.io.Serializable接口的对象才能从流读取。
3.序列化接口
当一个对象要能被序列化,这个对象所属的类必须实现Serializable接口。否则会发生异常NotSerializableException异常。
4.顺态关键字 transient
当一个类的对象需要被序列化时,某些属性不需要被序列化,这时不需要序列化的属性可以使用关键字transient修饰。只要被transient修饰了,序列化时这个属性就不会序列化了。
同时静态修饰也不会被序列化,因为序列化是把对象数据进行持久化存储,而静态的属于类加载时的数据,不会被序列化。
示例代码:
自定义类:
package com.oracle.Demo02; import java.io.Serializable; //实现序列化接口 public class Dog implements Serializable{ //设定一个固定的序列号,就会解决序列号冲突的问题 private static final long serialVersionUID = 42366998556L; private String name; //瞬态关键字 transient: 被修饰的属性就不会被序列化了 private transient String color; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } @Override public String toString() { return "Dog [name=" + name + ", color=" + color + "]"; } }
对象序列化流:
package com.oracle.Demo02; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class Demo01 { //对象序列化流 写入的内容是看不懂的,因为写入的是一个对象 public static void main(String[] args) throws IOException { //注意:序列化必须走的一步是自定义类实现序列化接口 // 1.确定目的地 FileOutputStream fos=new FileOutputStream("e:\java\dog.txt"); //2.创建对象输出流 ObjectOutputStream oos=new ObjectOutputStream(fos); //3.创建对象 对象属性如果有static修饰,就属于类了不属于对象,就无法获取,默认为null Dog d=new Dog(); d.setName("java"); d.setColor("white"); //4.讲对象写入文件 oos.writeObject(d); oos.flush(); oos.close(); } }
对象反序列化流:
package com.oracle.Demo02; import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class Demo02 { //对象反序列化 public static void main(String[] args) throws IOException, ClassNotFoundException { // 1.获取数据源 FileInputStream fis=new FileInputStream("e:\java\dog.txt"); //2.创建对象输入流 ObjectInputStream ois=new ObjectInputStream(fis); //3.向下转型 Dog g=(Dog)ois.readObject(); System.out.println(g); } }
四、打印流
打印流
添加输出数据的功能,使它们能够方便地打印各种数据值表示形式.
打印流根据流的分类:
1. 字节打印流 PrintStream
2. 字符打印流 PrintWriter
方法:
void print(String str): 输出任意类型的数据,
void println(String str): 输出任意类型的数据,自动写入换行操作
代码实例:
package com.oracle.Demo02; import java.io.File; import java.io.IOException; import java.io.PrintWriter; public class Demo03 { //打印流 //特点: //1.不负责数据源,只负责数据目的(不负责输入,只负责输出) //2.为其它输出流添加功能 //3.打印流永远不抛出IOExecption,但是会抛出其他异常 public static void main(String[] args) throws IOException { File f=new File("e:\java\test.txt"); PrintWriter pw=new PrintWriter(f); //.print()方法都是原样输出,但是writer方法如果输入int是走码表的 //pw.print("今天我养了一只狗"); pw.write("今天"); // pw.write(100); pw.flush(); pw.close(); } }
打印流打印数组的注意事项:
package com.oracle.Demo02; import java.io.IOException; public class Demo04 { public static void main(String[] args) throws IOException { //println()方法内没有打印除char[]数组以外其他类型的方法 //char[] 数组可以打印出来,但是其他类型的数组只会打印一个地址 int[] arr={1,2,3}; System.out.println(arr); char[] ch={'a','b'}; System.out.println(ch); } }
五、commons-IO jar包
1.导入ClassPath
加入classpath的第三方jar包内的class文件才能在项目中使用
创建lib文件夹
将commons-io.jar拷贝到lib文件夹
右键点击commons-io.jar,Build Path→Add to Build Path
2.FilenameUtils
这个工具类是用来处理文件名(包含文件路径)的,可以解决不同操作系统文件名称不规范的问题。
常用方法:
getExtension(String path); 获取文件的拓展名
getName(); 获取文件名
isExtension(String fileName,String ext); 查看ext是否是文件的拓展名
3.FileUtils
提供文件操作(移动文件,读取文件,检查文件是否存在等等)的方法。
常用方法:
readFileToString(File file):读取文件内容,并返回一个String;
writeStringToFile(File file,String content):将内容content写入到file中;
copyDirectoryToDirectory(File srcDir,File destDir);文件夹复制
copyFile(File srcFile,File destFile);文件复制
package com.oracle.Demo01; import java.io.File; import java.io.IOException; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; //commons-io工具包 public class Demo01 { public static void main(String[] args) throws IOException { //获取路径中的 扩展名 FilenameUtils.getExtension //若是个文件夹则会返回空字符串 String ext=FilenameUtils.getExtension("e:\java\demo.txt"); System.out.println(ext); //获取文件名 FilenameUtils.getName(); //若是文件夹,则会返回文件夹的名字 String name=FilenameUtils.getName("e:\java\demo.txt"); System.out.println(name); //判断文件是否以某个后缀结尾: FilenameUtils.isExtension(); boolean flag=FilenameUtils.isExtension("d:\java\test.txt", "txt"); System.out.println(flag); //写文件 :FileUtiles.writeStringToFile(); FileUtils.writeStringToFile(new File("e:\java\test.txt"),"你好",true); //读取文件:FileUtils.readFileToString(new File(文件路径)); String file=FileUtils.readFileToString(new File("e:\java\test.txt")); System.out.println(file); //复制文件夹:FileUtils.copyDirectoryToDirectory(); FileUtils.copyDirectoryToDirectory(new File("e:\java\dandan"), new File("d:\java")); //复制文件 FileUtils.copyFile(new File("e:\java\test.txt"),new File("d:\java\test.txt")); } }