数据操作流:操作基本类型数据的流
(1)可以操作基本类型的数据
(2)流对象名称
DataInputStream
DataOutputStream
1 /* 2 * 读写基本数据类型的数据 3 * 4 * 数据输入流:DataInputStream 5 * DataInputStream(InputStream in) 6 * 数据输出流:DataOutputStream 7 * DataOutputStream(OutputStream out) 8 * 9 */ 10 public class DataStreamDemo { 11 12 public static void main(String[] args) throws IOException { 13 //写 14 write(); 15 16 //读 17 read(); 18 19 } 20 21 private static void read() throws IOException { 22 // DataOutputStream(OutputStream out) 23 //创建数据输入流 24 DataInputStream dis = new DataInputStream(new 25 FileInputStream("b.txt")); 26 27 byte b = dis.readByte(); 28 int i = dis.read(); 29 char c = dis.readChar(); 30 double d = dis.readDouble(); 31 float f = dis.readFloat(); 32 short s = dis.readShort(); 33 long l = dis.readLong(); 34 boolean bb = dis.readBoolean(); 35 36 System.out.println(b); 37 System.out.println(i); 38 System.out.println(c); 39 System.out.println(d); 40 System.out.println(f); 41 System.out.println(s); 42 System.out.println(l); 43 System.out.println(bb); 44 } 45 46 private static void write() throws IOException { 47 // DataOutputStream(OutputStream out) 48 //创建数据输出流对象 49 DataOutputStream dos = new DataOutputStream( 50 new FileOutputStream("a.txt")); 51 52 //写数据 53 dos.writeByte(10); 54 dos.write(122); 55 dos.writeChar('b'); 56 dos.writeDouble(13.68); 57 dos.writeFloat(11.23F); 58 dos.writeShort(1000); 59 dos.writeLong(100000); 60 dos.writeBoolean(false); 61 62 //释放资源 63 dos.close(); 64 65 } 66 67 }
3:内存操作流(理解)
(1)有些时候我们操作完毕后,未必需要产生一个文件,就可以使用内存操作流。
(2)三种
A:ByteArrayInputStream
ByteArrayOutputStream
B:CharArrayReader
CharArrayWriter
C:StringReader
StringWriter
1 /* 2 * 内存操作流:用于处理临时存储的信息,程序结束后数据就从内存中消失 3 * 4 * 字节数组:ByteArrayInputStream 5 * ByteArrayOutputStream 6 * 7 * 字符数据:CharArrayReader 8 * CharArrayWriter 9 * 10 * 字符串:StringReader 11 * StringWriter 12 */ 13 public class ByteArrayInputStreamDemo { 14 15 public static void main(String[] args) throws IOException { 16 //写数据 17 //ByteArrayOutputStream 18 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 19 20 //写数据 21 for(int x = 0; x < 10; x++){ 22 baos.write(("hello" + x).getBytes()); 23 } 24 //不需要释放资源 25 26 27 //public byte[] toByteArray()转换成自己数组再读取 28 byte[] bys = baos.toByteArray(); 29 30 //读数据 31 //ByteArrayInputStream 32 ByteArrayInputStream bais = new ByteArrayInputStream(bys); 33 34 int by = 0; 35 while((by = bais.read()) != -1){ 36 System.out.println((char)by); 37 } 38 39 } 40 }
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();
1 /* 2 * 将a.txt中的内容复制到b.txt 3 * 4 * 数据源:a.txt 读取数据 FileReader BufferedReader 5 * 目的地:b.txt 写出数据 FileWriter BufferedWriter PrintWriter 6 */ 7 public class PrintWriterDemo { 8 9 public static void main(String[] args) throws IOException { 10 //以前的版本实现 11 //封装数据源 12 // BufferedReader br = new BufferedReader(new 13 // FileReader("a.txt")); 14 // //封装目的地 15 // BufferedWriter bw = new BufferedWriter(new 16 // FileWriter("b.txt")); 17 // 18 // //读数据 19 // String line = null; 20 // while((line = br.readLine()) != null){ 21 // bw.write(line); 22 // bw.newLine(); 23 // bw.flush(); 24 // } 25 // 26 // bw.close(); 27 // br.close(); 28 29 30 //改进版本 打印流 31 //封装数据源 32 BufferedReader br = new BufferedReader(new 33 FileReader("a.txt")); 34 35 //封装目的地 36 PrintWriter pw = new PrintWriter(new FileWriter("b.txt"), true);//启用自动刷新功能 37 String line = null; 38 while((line = br.readLine()) != null){ 39 pw.println(); 40 } 41 pw.close(); 42 br.close(); 43 } 44 }
1 public class PrintWriterDemo { 2 3 public static void main(String[] args) throws IOException { 4 //作为Writer的子类使用 5 PrintWriter pw = new PrintWriter("a.txt"); 6 7 pw.write("hello"); 8 pw.write("java"); 9 10 pw.close(); 11 } 12 }
1 /* 2 * 操作任意类型的数据 3 * print() 4 * println() 5 * 启用自动刷新 6 * PrintWriter pw = new PrintWriter(new FileWriter("b.txt"), true); 7 * 这时应该调用println()方法才可以实现刷新和自动换行 8 * 9 * println()等价于bw.write(); 10 * bw.newLine(); 11 * bw.flush(); 12 */ 13 public class PrintWriterDemo2 { 14 public static void main(String[] args) throws IOException { 15 //创建打印对象 16 //PrintWriter pw = new PrintWriter("a.txt"); 17 //启用自动刷新 18 PrintWriter pw = new PrintWriter(new FileWriter("b.txt"), true); 19 //这时的Write()是不能实现任意类型的 20 //使用print() 21 //pw.print(true); 22 //pw.print("hello"); 23 //pw.print(100); 24 25 pw.println("hello"); 26 pw.println(100); 27 pw.println(true); 28 29 pw.close(); 30 } 31 }
5:标准输入输出流
(1)System类下面有这样的两个字段
in 标准输入流
out 标准输出流
(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:获取和改变文件指针的位置
7:合并流
(1)把多个输入流的数据写到一个输出流中。
(2)构造方法:
A:SequenceInputStream(InputStream s1, InputStream s2)
B:SequenceInputStream(Enumeration<? extends InputStream> e)
8:序列化流
(1)可以把对象写入文本文件或者在网络中传输
(2)如何实现序列化呢?
让被序列化的对象所属类实现序列化接口。
该接口是一个标记接口。没有功能需要实现。
(3)注意问题:
把数据写到文件后,在去修改类会产生一个问题。
如何解决该问题呢?
在类文件中,给出一个固定的序列化id值。
而且,这样也可以解决黄色警告线问题
(4)面试题:
什么时候序列化?
如何实现序列化?
什么是反序列化?
1 /* 2 * 序列化流:把对象按照流一样的方式存入文本文件或者在网络上传输。对象--流数据 3 * ObjectOutputStream 4 * 反序列化:把文本文件中的流对象数据或者网络中的流对象数据还原成对象。流数据--对象 5 * ObjectInputStream 6 */ 7 public class ObjectStreamDemo { 8 public static void main(String[] args) throws IOException, ClassNotFoundException { 9 //对对象进行序列化,首先自定义一个类Person 10 11 //序列化数据 即就是将对象写到文本文件 12 write(); 13 14 read(); 15 } 16 17 private static void read() throws IOException, IOException, ClassNotFoundException { 18 // 创建反序列化对象 19 ObjectInputStream ois = new ObjectInputStream(new 20 FileInputStream("b.txt")); 21 22 //还原对象 23 Object obj = ois.readObject(); 24 25 //释放资源 26 ois.close(); 27 28 //输出对象 29 System.out.println(obj); 30 } 31 32 private static void write() throws IOException, IOException { 33 //创建序列化流对象 34 ObjectOutputStream oos = new ObjectOutputStream( 35 new FileOutputStream("a.txt")); 36 //创建对象 37 Person p = new Person("张三", 20); 38 39 oos.writeObject(p); 40 41 //释放资源 42 oos.close(); 43 44 } 45 46 }
1 //没有任何方法 这种没有方法的接口称为标记接口 2 public class Person implements Serializable{ 3 private static final long serialVersionUID = 1L; 4 private String name; 5 private String age; 6 7 8 9 public Person() { 10 super(); 11 } 12 13 14 15 public Person(String name, int age) { 16 super(); 17 this.name = name; 18 this.age = age; 19 } 20 21 22 23 public String getName() { 24 return name; 25 } 26 27 28 29 public void setName(String name) { 30 this.name = name; 31 } 32 33 34 35 public String getAge() { 36 return age; 37 } 38 39 40 41 public void setAge(String age) { 42 this.age = age; 43 } 44 45 46 47 @Override 48 public String toString() { 49 return "Person [name=" + name + ", age=" + age + "]"; 50 } 51 52 }
注意:有时候一个类中有很多成员变量,有些是不需要被序列化的,这时采用transient关键字声明不需要被序列化的成员变量
1 public class Person implements Serializable{ 2 3 private static final long serialVersionUID = 1L; 4 5 private String name; 6 //private String age; 7 private transient int age; 8 //int age; 9 10 public Person() { 11 super(); 12 } 13 14 15 16 public Person(String name, int age) { 17 super(); 18 this.name = name; 19 this.age = age; 20 } 21 22 23 24 public String getName() { 25 return name; 26 } 27 28 29 30 public void setName(String name) { 31 this.name = name; 32 } 33 34 35 36 public int getAge() { 37 return age; 38 } 39 40 41 42 public void setAge(int age) { 43 this.age = age; 44 } 45 46 47 48 @Override 49 public String toString() { 50 return "Person [name=" + name + ", age=" + age + "]"; 51 } 52 53 }
9:Properties
(1)是一个集合类,Hashtable的子类
1 /* 2 * Properties:属性集合类,是可以和IO流相结合使用的集合类 3 * Properties可以保存在流中和从流中加载,属性列表中每个键及其对应值都是一个字符串 4 * 5 * 是Hashtable的子类,是一个Map集合 6 */ 7 public class PropertiesDemo { 8 9 public static void main(String[] args) { 10 Properties prop = new Properties(); 11 12 //添加元素 13 prop.put("ob001", "hello"); 14 prop.put("ob002", "world"); 15 16 //遍历集合 17 Set<Object> set = prop.keySet(); 18 for(Object key : set){ 19 Object value = prop.get(key); 20 System.out.println(key + "----" + value); 21 } 22 23 } 24 }
(2)特有功能
A:public Object setProperty(String key,String value)
B:public String getProperty(String key)
C:public Set<String> stringPropertyNames()
1 /* 2 * 特殊功能 3 * public Object setProperty(String key,String value) 添加元素 4 * public String getProperty(String key) 获取元素 5 * public Set<String> stringPropertyNames() 获取所有键的集合 6 */ 7 public class PropertiesDemo2 { 8 public static void main(String[] args) { 9 //创建集合对象 10 Properties prop = new Properties(); 11 12 //添加元素 只能添加字符串 13 prop.setProperty("张三", "20"); 14 prop.setProperty("李四", "30"); 15 prop.setProperty("王五", "50"); 16 17 18 //public Set<String> stringPropertyNames() 获取所有键的集合 19 Set<String> set = prop.stringPropertyNames(); 20 for(String key : set){ 21 String value = prop.getProperty(key); 22 System.out.println(key + "----" + value); 23 } 24 } 25 26 }
(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)
1 /* 2 * public void load(Reader reader) 将文件中的数据读取到集合中 3 * public void store(Writer writer, String comments) 把集合中的数据存储到文件 4 * 5 * 这里的集合必须是Properties集合 6 */ 7 public class PropertiesDemo3 { 8 9 public static void main(String[] args) throws Exception { 10 load(); 11 store(); 12 } 13 14 private static void store() throws Exception { 15 //创建集合 16 Properties prop = new Properties(); 17 //集合里面添加数据 18 prop.setProperty("张三", "24"); 19 prop.setProperty("李四", "34"); 20 prop.setProperty("王五", "26"); 21 22 //public void store(Writer writer, String comments) 把集合中的数据存储到文件 23 Writer w = new FileWriter("a.txt"); 24 prop.store(w, "hello");//"hello"对文件的描述 25 w.close(); 26 27 } 28 29 private static void load() throws IOException { 30 //创建集合 31 Properties prop = new Properties(); 32 33 // public void load(Reader reader) 将文件中的数据读取到集合中 34 //注意:这里读取的文件的数据必须是键值对形式 35 /* 36 * a.txt 37 * zhangsan=20 38 * wangwu=30 39 * lisi=40 40 */ 41 42 Reader r = new FileReader("a.txt"); 43 prop.load(r); 44 r.close(); 45 } 46 }
(4)案例:
A:根据给定的文件判断是否有键为"lisi"的,如果有就修改其值为100
1 /* 2 * 有一个a.txt文件 不知道里面的键值对形式 3 * 通程序判断是否含有"zhangsan"这样的键存在,如果有将其改变为"001" 4 * 5 * 将文件中的数据加载到集合中 6 * 遍历集合获取到每一个键 7 * 判断键是否有"zhangsan"的,如果有就修改其值为"001" 8 * 将集合中的数据重新存储到文件 9 */ 10 public class PropertiesTest { 11 12 public static void main(String[] args) throws IOException { 13 //将文件中的数据加载到集合中 14 Properties prop = new Properties(); 15 Reader r = new FileReader(".txt"); 16 prop.load(r); 17 r.close(); 18 19 //遍历集合获取到每一个键 20 Set<String> set = prop.stringPropertyNames(); 21 for(String key : set){ 22 //判断键是否有"zhangsan"的,如果有就修改其值为"001" 23 if("zhangsan".equals(key)){ 24 prop.setProperty(key, "001"); 25 break; 26 } 27 } 28 29 //将集合中的数据重新存储到文件 30 Writer w= new FileWriter("b.txt"); 31 prop.store(w, null); 32 w.close(); 33 } 34 }