IO流06
A.其他常用流
1)操作基本数据类型的流Data
1.DataOutputStream:数据输出流
import java.io.DataOutputStream; import java.io.FileOutputStream; public class Demo01 { public static void main(String[] args) throws Exception { // 创建数据输出流 DataOutputStream dos = new DataOutputStream(new FileOutputStream("dos.txt")); // 写数据 dos.writeByte(10); dos.flush(); dos.writeShort(100); dos.flush(); dos.writeInt(1000); dos.flush(); dos.writeLong(10000L); dos.flush(); dos.writeFloat(12.34F); dos.flush(); dos.writeDouble(12.56); dos.flush(); dos.writeBoolean(true); dos.flush(); dos.writeChar('A'); dos.flush(); // 释放资源 dos.close(); } }
最后输出txt里肯定是看不懂的乱码,但只要计算机能看懂就行了接下来读取到控制台上
2.DataInputStream:数据输入流
import java.io.DataInputStream; import java.io.FileInputStream; public class Demo02 { public static void main(String[] args) throws Exception { // 创建数据输入流对象 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(); boolean flag = dis.readBoolean(); char c = dis.readChar(); 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(flag); System.out.println(c); } }
2)内存操作流
用来存储内存中的临时信息,程序结束的时候,内存流就消失了!
1.字节数组操作内存流
ByteArrayInputStream
ByteArrayOutputStream
2.字符数组操作的内存流
CharArrayReader
CharArrayWriter
3.字符串操作的内存流
StringReader
StringWritwe
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; public class Demo01 { public static void main(String[] args) throws IOException { // 创建针对字节数组操作的内存输出流对象 ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 写一个for循环 for (int i = 0; i < 10; i++) { // 写数据 baos.write(("hello" + i).getBytes()); } // 关闭资源 // public void close() throws IOException {} // 通过查看API原码:发现该流的close方法没有任何 的操作,该流可以不用关闭: // 该流本身就是内存流,存储内存中临时信息,当程序结束,跟该流有关的资源也就自动消失了 // baos.close(); // 字节内存输入流:public ByteArrayInputStream(byte[] buf) // public byte[] toByteArray()创建一个新分配的 byte 数组 // 将字节数组内存操作输出流对象转换成字节数组 byte[] bys = baos.toByteArray(); // 创建字节数组内存操作输入流对象 ByteArrayInputStream bais = new ByteArrayInputStream(bys); // 既然是字节流:就可以使用基本字节流读数据的方法 // 一次读取一个字节 int by = 0; while ((by = bais.read()) != -1) { System.out.print((char) by); } } }
3)打印流Print
1.字节打印流
import java.io.IOException; import java.io.PrintWriter; public class Demo01 { public static void main(String[] args) throws IOException { // 创建打印流 PrintWriter pw = new PrintWriter("a.txt"); // 写数据 pw.write("hello"); pw.write("world"); pw.write("java"); pw.flush(); pw.close(); } }2.字符打印流
可以写任何数据类型:
PrintStream ps = System.out; 字节打印流
ps.println();
ps.print(数据类型);
字符打印流的一个构造方法:可以进行自动刷新
public PrintWriter(Writer out, boolean autoFlush)
如果想要是自动刷新,那么第二个参数的值为:true
换行还要使用字符打印流中的:println();
import java.io.FileWriter; import java.io.PrintWriter; public class Demo02 { public static void main(String[] args) throws Exception { PrintWriter pw = new PrintWriter(new FileWriter("pw.txt"), true); pw.println("hello"); pw.println(100); pw.print(12.34F); pw.close(); } }
该流:不能操作数据源,只能操作目的的数据:该流只能写数据,不能读数据
该流可以自动刷新
该流还可以针对文本数据进行操作
(只要构造方法中有File对象或者String类型的路径都是可以对文本进行操作的)
需求:将当前项目下的a.txt文件复制到当前项目下的b.txt文件中
import java.io.BufferedReader; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; public class Demo03 { public static void main(String[] args) throws IOException { // 数据源 BufferedReader br = new BufferedReader(new FileReader("a.txt")); // 目的 PrintWriter pw = new PrintWriter(new FileWriter("b.txt")); // 写数据 String line = null; while ((line = br.readLine()) != null) { pw.println(line); } pw.close(); br.close(); } }
4)标准流
1.标准输入流:public static final InputStream in
2.标准输出流:public static final PrintStream out
3.字节数如流:InputStream = System.in
4.字节输出流:PrintStream = System.out
直接使用标准输出流:和刚才使用字符缓冲输入流封装字输入流一样,输出数据import java.io.PrintStream; public class Demo01 { public static void main(String[] args) { // 我们一直使用的输出语句,其实就是采用流的一种进行:字节打印流进行输出 System.out.println("hello world"); PrintStream ps = System.out;// 返回的是字节打印流对象 ps.println("hello world"); ps.println(); } }需求:用字符缓冲输入流包装字节输入流,进行录入数据!(键盘录入)import java.io.BufferedOutputStream; import java.io.IOException; public class Demo02 { public static void main(String[] args) throws IOException { // 和刚才使用字符缓冲输入流封装字输入流一样,输出数据 BufferedOutputStream bos = new BufferedOutputStream(System.out); bos.write("hello".getBytes()); bos.write("world".getBytes()); bos.write("java".getBytes()); bos.close(); } }import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class Demo03 { public static void main(String[] args) throws IOException { // 1)使用输入流的方式将标准输入流包装起来,进行录入数据 // InputStream is = System.in; // 字节流对象: // 可以获取一行数据吗? // 可以:readLine()这个方法哪个流里面的?属于字符缓冲输入流里面的方法, // BufferReader():底层应该也是用字节流进行实现,所有可以用它封装一下 // BufferedReader br = new BufferedReader(is); // 字符缓冲流只能针对字符流进行操作,并不直接针对字节流操作 // 2)哪个流可以将字节流转换成字符流 // InputStreamReader isr = new InputStreamReader(is);// // 转换输入流=字节流+编码格式(gbk) // 3)在用字符缓冲输入流封装当前的转换流 // 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("请输入一个整数:"); String s = br.readLine(); int i = Integer.parseInt(s); System.out.println("整数是:" + i); } }
5)随机访问流RandomAccessFile
并不是实际意义的流
public RandomAccessFile(String name,String mode):
mode:里面的模式:只记住:常用的就:rw:既可以读,也可以写
读数据
写数据import java.io.IOException; import java.io.RandomAccessFile; public class Demo01 { public static void main(String[] args) throws IOException { RandomAccessFile raf = new RandomAccessFile("a.txt", "rw"); byte b = raf.readByte(); System.out.println(b); // public long getFilePointer(),返回此文件的偏移量 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()); // public void seek(long pos)throws IOException // 设置到此文件开头测量到的文件指针偏移量 // 从第四个字符开始 raf.seek(3); char c = raf.readChar(); System.out.println(c); raf.close(); } }import java.io.IOException; import java.io.RandomAccessFile; public class Demo02 { public static void main(String[] args) throws IOException { RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw"); raf.writeByte(100); raf.writeChar('A'); raf.writeUTF("中国"); raf.close(); } }
6)合并流SequenceInputStream
合并流,将一些输入流合并起来,对输出流没有作用,表示其他输入流的逻辑串联
复制文件:a.txt--->b.txt,c.txt--->d.txt
合并流:a.txt+b.txt---->c.txt中
1.public SequenceInputStream(InputStream s1,InputStream s2)
需求:将当前项目下的a.txt文件和b.txt文件中的内容复制到当前项目下的c.txt文件中
import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.SequenceInputStream; public class Demo01 { public static void main(String[] args) throws IOException { // 将数据源封装成合并流 SequenceInputStream sis = new SequenceInputStream(new FileInputStream("a.txt"), new FileInputStream("b.txt")); // 创建字节缓冲输出流对象 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("c.txt")); // 读写操作 byte[] bys = new byte[1024]; int len = 0; while ((len = sis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); sis.close(); } }
2.public SequenceInputStream(Enumeration e)
可以将两个以上文件合并
需求:将当前目录下的a.txt和b.txt和c.txt文件合并到d.txt文件中
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; public class Demo02 { public static void main(String[] args) throws IOException { // 观察合并流构造方法中有一个:Enumration这个类型,和Vecotr集合有关系 // 首先创建Vector集合对象 Vector<InputStream> v = new Vector<InputStream>(); InputStream s1 = new FileInputStream("a.txt"); InputStream s2 = new FileInputStream("b.txt"); InputStream s3 = new FileInputStream("c.txt"); 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("d.txt")); byte[] bys = new byte[1024]; int len = 0; while ((len = sis.read(bys)) != -1) { bos.write(bys, 0, len); bos.flush(); } bos.close(); sis.close(); } }
7)序列化流和反序列化流
序列化流:
将对象按照流的形式(在网络进行传输等等)封装成流数据:对象--->流数据:ObjectOutputStream
反序列化流:
将网络传输中的流数据又封装成了一个对象: 流数据-->对象 ObjectInputStream
Person类
若没有实现Serializable会怎样?java.io.NotSerializableException: xxx.Person
告诉我们:当前自定义的类并没有实现序列化接口
类通过实现 java.io.Serializable 接口以启用其序列化功能
未实现此接口的类将无法使其任何状态序列化或反序列化。
Serializable接口:
通过查看API:发现Serializable接口中没有字段,构造方法,成员方法
所有如果一个接口中没有任何的方法或者他的字段,将这种接口叫标记接口!
Person
import java.io.Serializable; public class Person implements Serializable { // 默认的:default srial Version ID:默认版本ID // Person有黄色警告线,点击,生成下面的代码,获取ID private static final long serialVersionUID = 1L; // 成员变量 private String name; private int age; // transient int age; public Person() { super(); // TODO Auto-generated constructor stub } 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 + "]"; } }
测试类
1.只进行序列化import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class Demo01 { public static void main(String[] args) throws Exception { // 序列化 ObjectOutputStream oot = new ObjectOutputStream(new FileOutputStream("oot.txt")); Person p = new Person("张三", 20); oot.writeObject(p); oot.close(); //反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("oot.txt")); Object obj = ois.readObject(); ois.close(); System.out.println(obj); } }2.将序列化注释掉,
3.修改Person类中的成员变量private int age ----> int age
4.再进行反序列化
结果:java.io.InvalidClassException:
local class incompatible: stream classdesc serialVersionUID = -3059867121192605950,
local class serialVersionUID = -1219396793646518298
原因:
序列化流和反序列化流
刚才已经手动写了,并且运行了一次
每一次在加载Person.class文件的时候,都会生成一个ID
比如:第一次没有修改Person类中文件:class文件
Person.class ---->ID = 100 ;
private String name --->ID =100
prvate int age ------->ID = 100
后面修改了class文件中的内容
Person.class------>ID= 200
private String name --->ID =100
int age ------->ID = 100
这样的话:ID版本号不匹配:就出现了刚才这个异常:
实际开发中,可能有时候需要用到以前的数据
所以就需要我们将当前的这个class文件要生成固定ID
这样的话就不会报异常了
当前的这个类有黄色警告线,点击黄色警告线生成ID
如果在一个类中,该类的成员变量比较多
有时候为了让成员变量不被序列化
加一个关键字:transient
这样:如果是 String name,输出的是null;int age,输出的是0
B.属性集合类Properties
1)概述
这个类是Hashtbale的子类,而Hashtable也Map下面的双列集合
注意:Properties:不带泛型!
import java.util.Properties; import java.util.Set; public class Demo01 { public static void main(String[] args) { Properties prop = new Properties(); prop.put("1001", "张三"); prop.put("1002", "李四"); prop.put("1003", "王五"); // 遍历 Set<Object> set = prop.keySet(); for (Object key : set) { Object value = prop.get(key); System.out.println(key + "---" + value); } } }
2)特殊功能
public Object setProperty(String key,String value):和添加相关的
public Set<String> stringPropertyNames():获取所有的键的集合
public String getProperty(String key):获取指定的属性集合中的键的值
import java.util.Properties; import java.util.Set; public class Demo02 { public static void main(String[] args) { Properties prop = new Properties(); prop.setProperty("张三", "20"); prop.setProperty("李四", "21"); prop.setProperty("王五", "22"); // 获取所有键集合 Set<String> set = prop.stringPropertyNames(); for (String key : set) { // 获取指定的值 String value = prop.getProperty(key); System.out.println(key + "---" + value); } } }
3)功能
public void load(Reader reader):将文本文件的数据读取集合中
public void store(Writer writer, String comments):将集合中的数据保存到文本文件中
comments:属性列表的描述
import java.io.FileReader; import java.io.FileWriter; import java.io.Reader; import java.io.Writer; import java.util.Properties; public class Demo03 { public static void main(String[] args) throws Exception { Properties prop = new Properties(); prop.setProperty("张三", "21"); prop.setProperty("李四", "22"); prop.setProperty("王五", "23"); // 将集合中的数据保存到文件中 Writer w = new FileWriter("name.txt"); prop.store(w, "Person"); // 将文件中的数据读取集合中 Reader r = new FileReader("name.txt"); prop.load(r); r.close(); w.close(); System.out.println(prop); } }
4)练习
我有一个文本文件(user.txt),我知道数据是键值对形式的,但是不知道内容是什么。
请写一个程序判断是否有“lisi”这样的键存在,如果有就改变其实为”100”
1.先将文件中的数据加载到集合中
2.获取键的集合,遍历键的集合
判断:如果"lisi"就是里面的key
是的话就修改
3.重新将集合中的数据保持到文件中
import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.Properties; import java.util.Set; public class Demo04 { public static void main(String[] args) throws IOException { Properties prop = new Properties(); prop.load(new FileReader("user.txt")); Set<String> set = prop.stringPropertyNames(); for (String key : set) { if ("李四".equals(key)) { prop.setProperty("李四", "100"); System.out.println("匹配到结果,并完成修改,请查看user.txt"); break; } } prop.store(new FileWriter("user.txt"), "user"); } }
本文深入讲解Java中的IO流,包括数据流操作、内存操作流、打印流等,并介绍如何使用这些流来处理基本数据类型、合并文件及序列化对象。
870

被折叠的 条评论
为什么被折叠?



