转换流
1. OutputStreamWriter类
它的作用的就是,将字符串按照指定的编码表转成字节,在使用字节流将这些字节写出去。
public static void writeCN() throws Exception { //创建与文件关联的字节输出流对象 FileOutputStream fos = new FileOutputStream("c:\cn8.txt"); //创建可以把字符转成字节的转换流对象,并指定编码 OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8"); //调用转换流,把文字写出去,其实是写到转换流的缓冲区中 osw.write("你好");//写入缓冲区。 osw.close(); }
2. InputStreamReader类
InputStreamReader 是字节流通向字符流的桥梁:它使用指定的字符编码表读取字节并将其解码为字符。
它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
public class InputStreamReaderDemo { public static void main(String[] args) throws IOException { //演示字节转字符流的转换流 readCN(); } public static void readCN() throws IOException{ //创建读取文件的字节流对象 InputStream in = new FileInputStream("c:\cn8.txt"); //创建转换流对象 //InputStreamReader isr = new InputStreamReader(in);这样创建对象,会用本地默认码表读取,将会发生错误解码的错误 InputStreamReader isr = new InputStreamReader(in,"utf-8"); //使用转换流去读字节流中的字节 int ch = 0; while((ch = isr.read())!=-1){ System.out.println((char)ch); } //关闭流 isr.close(); } }
缓冲流
1 字节缓冲流
字节缓冲流根据流的方向,共有2个
l 写入数据到流中,字节缓冲输出流 BufferedOutputStream
l 读取流中的数据,字节缓冲输入流 BufferedInputStream
1.1 字节缓冲输出流BufferedOutputStream
1.2 字节缓冲输入流 BufferedInputStream
public static void main(String[] args) throws IOException { FileInputStream shuru=new FileInputStream("D:\表约束.wmv"); //创建字节输出缓冲流 BufferedInputStream bis=new BufferedInputStream(shuru); //创建字节输出流 FileOutputStream shuchu=new FileOutputStream("D:\io0512\a\字符流.wmv"); //创建字节输出 BufferedOutputStream bos=new BufferedOutputStream(shuchu); //复制 int len=0; while((len=bis.read())!=-1){ bos.write(len); } bis.close(); bos.close(); }
2 字符缓冲流
l 字符缓冲输入流 BufferedReader
l 字符缓冲输出流 BufferedWriter
完成文本数据的高效的写入与读取的操作
字符缓冲输出流 BufferedWriter
l 方法:
void newLine() 根据当前的系统,写入一个换行符
public class BufferedWriterDemo { public static void main(String[] args) throws IOException { //创建流 //基本字符输出流 FileWriter fileOut = new FileWriter("file.txt"); //把基本的流进行包装 BufferedWriter out = new BufferedWriter(fileOut); //2,写数据 for (int i=0; i<5; i++) { out.write("hello"); out.newLine(); } //3,关闭流 out.close(); } }
字符缓冲输入流 BufferedReader
l 方法
public String readLine() 读取一个文本行,包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
public class BufferedReaderDemo { public static void main(String[] args) throws IOException { //1,创建流 BufferedReader in = new BufferedReader(new FileReader("file.txt")); //2,读数据 //一次一个字符 //一次一个字符数组 //一次读取文本中一行的字符串内容 String line = null; while( (line = in.readLine()) != null ){ System.out.println(line); } //3,关闭流 in.close(); } }
文本复制,一个字符数组一个数组读
public class Demo04 { public static void main(String[] args) throws IOException { //创建字符输入 FileReader shuru=new FileReader("D:\io0512\utf-8.txt"); BufferedReader br=new BufferedReader(shuru); FileWriter shuchu=new FileWriter("D:\io0512\a\utf-8.txt"); BufferedWriter bw=new BufferedWriter(shuchu); int len=0; char[] ch=new char[2]; while((len=br.read(ch))!=-1){ bw.write(ch,0,len); bw.flush(); } br.close(); bw.close(); } }
一个字节一个字节复制
public static void main(String[] args) throws IOException { FileInputStream shuru=new FileInputStream("D:\表约束.wmv"); //创建字节输出缓冲流 BufferedInputStream bis=new BufferedInputStream(shuru); //创建字节输出流 FileOutputStream shuchu=new FileOutputStream("D:\io0512\a\字符流.wmv"); //创建字节输出 BufferedOutputStream bos=new BufferedOutputStream(shuchu); //复制 int len=0; while((len=bis.read())!=-1){ bos.write(len); } bis.close(); bos.close(); } }
一行一行的读
public static void main(String[] args) throws IOException { //chuang减字符输入流 FileReader shuru=new FileReader("D:\io0512\utf-8.txt"); BufferedReader br=new BufferedReader(shuru); FileWriter shuchu=new FileWriter("D:\io0512\utf-82.txt"); BufferedWriter bw=new BufferedWriter(shuchu); //复制 String len=null; while((len=br.readLine())!=null){//一行一行读 bw.write(len); bw.newLine();//换行 bw.flush(); } br.close(); bw.close(); }
流的操作规律
IO流中对象很多,解决问题(处理设备上的数据时)到底该用哪个对象呢?
把IO流进行了规律的总结(四个明确):
l 明确一:要操作的数据是数据源还是数据目的。
源:InputStream Reader
目的:OutputStream Writer
先根据需求明确要读,还是要写。
l 明确二:要操作的数据是字节还是文本呢?
源:
字节:InputStream
文本:Reader
目的:
字节:OutputStream
文本:Writer
已经明确到了具体的体系上。
l 明确三:明确数据所在的具体设备。
源设备:
硬盘:文件 File开头。
内存:数组,字符串。
键盘:System.in;
网络:Socket
目的设备:
硬盘:文件 File开头。
内存:数组,字符串。
屏幕:System.out
网络:Socket
完全可以明确具体要使用哪个流对象。
l 明确四:是否需要额外功能呢?
额外功能:
转换吗?转换流。InputStreamReader OutputStreamWriter
高效吗?缓冲区对象。BufferedXXX
InputStream
FileInputStream
BufferedInputStream
OuputStream
FileOutputStream
BufferedOuputStream
Writer
OutputStreamWriter
FileWriter
BufferedWriter
Reader
InputStreamReader
FileReader
BufferedReader
Properties类
Properties
类表示了一个持久的属性集。Properties
可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
特点:
1、Hashtable的子类,map集合中的方法都可以用。
2、该集合没有泛型。键值都是字符串。
3、它是一个可以持久化的属性集。键值可以存储到集合中,也可以存储到持久化的设备(硬盘、U盘、光盘)上。键值的来源也可以是持久化的设备。
4、有和流技术相结合的方法。
public static void main(String[] args) { //创建Pro集合 Properties pro=new Properties(); pro.put("a", "18");//存值 pro.put("b", "16"); System.out.println(pro.getProperty("a"));//输出18,取值 System.out.println(pro.getProperty("b"));//输出16 }
public static void main(String[] args) throws IOException { Properties pro=new Properties();//创建Propertues对象 pro.put("name","Amy"); pro.put("age", "19");
//明确properties的路径 FileOutputStream fos=new FileOutputStream("src/com/oracle/demo02/pro.properties",true); pro.store(fos, "");//注释,注释不写显示当前时间 }
l load(InputStream) 把指定流所对应的文件中的数据,读取出来,保存到Propertie集合中
l load(Reader)
l store(OutputStream,commonts)把集合中的数据,保存到指定的流所对应的文件中,参数commonts代表对描述信息
l stroe(Writer,comments);
load读取
序列化流与反序列化流
创建对象的方式:一种是new,一种是对象序列化
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。
序列化:将一个对象封装到文件中(ObjectOutputStream )
//序列化 public class Demo01 {//将一个对象封存到文件中 public static void main(String[] args) throws IOException { //明确目的地 FileOutputStream fos=new FileOutputStream("D:\io0512\person.txt"); //创建序列化流 ObjectOutputStream oos=new ObjectOutputStream(fos); oos.writeObject(new Person("张三",20)); oos.close(); } }
反序列化:将封装好的文件读出来(ObjectInputStream)
用于从流中读取对象的
//反序列化 public class Demo02 {//将封存的对向读回来 public static void main(String[] args) throws ClassNotFoundException, IOException { //明确数据源 FileInputStream fis=new FileInputStream("D:\io0512\person.txt"); //创建反序列化流对象 ObjectInputStream ois=new ObjectInputStream(fis); //读取对象 Person p=(Person)ois.readObject(); System.out.println(p);//打印存好的信息,Person【name=张三,age=18】 ois.close(); } }
Person类
public class Person implements Serializable{//序列化接口 public static String name;//静态修饰不属于对象,属于类,不被序列化(序列化是对象) private transient int age;//不需要被序列化的属性可以加transient,就不被序列化,写的值就不能被读出来 //定死uid的序列化号,保证txt和person里的序列号一致 private static final long serialVersionUID=123L;//序列化号 public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } public Person(String name, int age) { super(); this.name = name; this.age = age; } public Person() { super(); } 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; } }
序列化接口
当一个对象要能被序列化,这个对象所属的类必须实现Serializable接口。否则会发生异常NotSerializableException异常。
同时当反序列化对象时,如果对象所属的class文件在序列化之后进行的修改,那么进行反序列化也会发生异常InvalidClassException。发生这个异常的原因如下:
l 该类的序列版本号与从流中读取的类描述符的版本号不匹配
l 该类包含未知数据类型
l 该类没有可访问的无参数构造方法
Serializable标记接口。该接口给需要序列化的类,提供了一个序列版本号。serialVersionUID. 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。
瞬态关键字transient
当一个类的对象需要被序列化时,某些属性不需要被序列化,这时不需要序列化的属性可以使用关键字transient修饰。只要被transient修饰了,序列化时这个属性就不会序列化了。
同时静态修饰也不会被序列化,因为序列化是把对象数据进行持久化存储,而静态的属于类加载时的数据,不会被序列化。
不被序列化就无法写入数据,读取到的是默认值