文章目录
1. 数据输入输出流
-
概述
- 用来对Java中的基本数据类型进行操作
- 可以写基本数据类型,也可以读基本数据类型
-
分类
- 数据输入流
- DataInputStream
- 数据输出流
- DataOutputStream
- 数据输入流
-
练习
- 使用数据输入输出流
public class Test {//数据输入输出流演示 public static void main(String[] args) throws IOException { DataOutputStream output = new DataOutputStream(new FileOutputStream("Info.txt"));//创建数据输出流 output.writeUTF("123456");//写入字符串 output.writeChar('你');//写入字符 byte[] bytes = {9, 8, 7, 6, 5}; output.write(bytes);//写入字节数组 output.close();//关闭数据输出流 DataInputStream input = new DataInputStream(new FileInputStream("Info.txt"));//创建数据输入流 String s = input.readUTF();//读取字符串 System.out.println(s); char c = input.readChar();//读取字符 System.out.println(c); byte[] bytes1 = new byte[5]; input.read(bytes1);//读取字节数组 System.out.println(bytes1); input.close();//关闭数据输入流 } }
-
注意
- 写入的数据类型顺序与读出的数据类型顺序应保持一致
2. 内存操作流
- 概述
- 针对内存进行操作的流
- 分类
- 操作字节数组
- ByteArrayOutputStream
- ByteArrayInputStream
- 操作字符数组
- CharArrayWrite
- CharArrayReader
- 操作字符串
- StringWriter
- StringReader
- 操作字节数组
3. 打印流
-
概述
- 向文本输出流打印对象的格式化表示形式,将数据打印到某个文件或设备,能直接对文件及逆行操作
-
打印流特点
- 只能操作目的地,不能操作源数据,也就是不能读取数据,但是可以写入数据
- 可以写入任何数据类型的数据,调用print() 方法
- 可以启动自动刷新,启动后当调用println、printf、format方法中的一个时,会自动进行刷新
- 可以直接对文件进行操作
-
PrintWriter
- 构造方法
- public PrintWriter(OutputStream out,boolean autoFlush)
- public PrintWriter(Writer out,boolean autoFlush)
- 构造方法
-
练习
- 使用打印流实现文本文件复制
public class PrintFileCopy {//使用字符打印流复制文件 public static void main(String[] args) throws IOException { BufferedReader buffReader = new BufferedReader(new FileReader("Student.java")); PrintWriter printWriter = new PrintWriter(new FileWriter("Student-副本.java", true)); //创建高效字符流与打印流,并打开打印流的自动刷新 String result; while ((result = buffReader.readLine()) != null) { printWriter.println(result); } buffReader.close(); printWriter.close(); } }
4. 标准输入输出流
-
概述
- 在System类中有两个静态成员变量,分别对应键盘的录入与显示器的输出
- public static final InputStream in
- 标准输入流,对应的是键盘的输入
- public static final PrintStream out
- 标准的输出流,对应的是显示屏的输出
-
两种方法实现键盘录入
-
in和out的类型
- System.in
- 是InputStream类型
- System.out
- 是OutputStream的子类型
- System.in
-
使用Scanner录入
public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入你的姓名"); String name = scanner.next(); }
-
使用BufferedReader的readLine方法
public class InOutDemo {//使用高效字符输入输出流关联键盘与屏幕 public static void main(String[] args) throws IOException { //System.in是InputStream下的子类 //System.out是OutputStream下的子类 BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));//将高效字符输入流与键盘关联 System.out.println("请输入你的姓名"); String name = reader.readLine();//获得键盘输入 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));//将高效字符输出流与显示屏关联 writer.write(name);//将姓名打印到显示屏上 writer.flush();//字符流需要刷一下 } }
-
5. 随机访问流
-
概述
- 支持对文件的读和写操作,内部含有一个文件指针,在读文件时,随着对字节的写入指针也在后移,可以记录某一时刻指针的位置,使得下一次读取文件从指定位置开始。常用于缓存暂停等场景
- 不属于流,是Object类的子类,但是有InputStream和OutputStream的功能
-
构造方法
- RandonAccessFile(File file,String mode)
- 创建一个可读可写的随机的访问文件流,后面的参数是r表示可读,是rw表示可读可写
- RandomAccessFile(String name,String mode)
- 创建一个可读可写的随机访问文件流,参数二同上
- RandonAccessFile(File file,String mode)
-
方法
- read系列
- 可以从文件中读取某一类型的数据
- write系列
- 可以向文件中写入某一类型的数据
- void seek (long pos)
- 设置文件指针的位置,
- long getFilePointer()
- 得到当前文件指针的位置,使得下一次的读取操作从此位置开始
- read系列
-
练习
- 使用RandomAccessFile复制文件
public class MusicCopies {//使用RandomAccessFile将歌曲复制三份 public static void main(String[] args) throws IOException { RandomAccessFile inputFile = new RandomAccessFile("许巍 - 曾经的你.mp3", "rw");//创建随机访问输入流,与原文件关联 RandomAccessFile outputFile = null;//创建随机访问输出流 for (int i = 0; i < 3; i++) { int len = 0; byte[] bytes = new byte[1024 * 8]; outputFile = new RandomAccessFile(i + "许巍 - 曾经的你.mp3", "rw"); while ((len = inputFile.read(bytes)) != -1) { outputFile.write(bytes, 0, len); } inputFile.seek(0);//每复制一次,将指针置为0 outputFile.close(); } inputFile.close(); } }
6. 序列化流与反序列化流
-
概述
- 用来对对象和基本数据类型进行读写,序列化是将对象通过流的方法写入文件中,反序列化是将对象从文件中读取出来
- 序列化流
- ObjectOutputStream
- 将对象序列化转换为字节流
- ObjectOutputStream
- 反序列化流
- ObjectInputStream
- 将对象字节流反序列化转换为对象
- ObjectInputStream
-
ObjectOutputStream和ObjectInputStream特有方法
- ObjectOutputStream: void writeObject(Object obj)
- 将对象写入
- ObjectInputStream:Object readObject()
- 从文件中读取到对象
- ObjectOutputStream: void writeObject(Object obj)
-
自定义类序列化
- 只有类实现了Serializable接口,这个类的对象才能被序列化
- 序列化以后,在序列化文件中还存在一个标记serialVersionUID,在进行反序列化之前,程序会验证当前的标记与序列化文件中的标记是否一致,如果一致会进行序列化,不一致会报错(不一致是因为在序列化后又修改了类)
- 解决标记不一致报错的方案
- 将这个标记显式的给出来,这样子这个标记就不会变了
- private static final long serialVersionUID =-6150L;
- 可以强制提示给出标记
-
如何让成员变量不被序列化
- 使用transient关键字,加上关键字的成员变量将不会被序列化
-
练习
- 使用ObjectOutputStream与ObjectInputStream对自定义类的对象序列化与反序列化
public class Student implements Serializable {//自定义学生类 public static final long serialVersionUID = 42L;//给定标记 private String name = ""; private int age = 0;//成员变量 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; } public Student() { } public Student(String name, int age) {//有参构造 this.name = name; this.age = age; } } public class ObjectStreams {//对自定义类的对象序列化与反序列化 public static void main(String[] args) throws IOException, ClassNotFoundException { Student zhangSan = new Student("张三", 23);//创建自定义类对象 ObjectOutputStream outStream = new ObjectOutputStream(new FileOutputStream("student.txt"));//创建序列化流 outStream.writeObject(zhangSan);//将对象写入 outStream.flush(); outStream.close();//关闭序列化流 Object o = new ObjectInputStream(new FileInputStream("student.txt")).readObject();//创建反序列化流并得到其中存储的对象 zhangSan = (Student) o; System.out.println(zhangSan.getName()); System.out.println(zhangSan.getAge());//打印对象的成员变量 } }
7. Properties集合
-
概述
- Properties集合是双列集合,父类是Hashtable,集合中的元素以键值对的形式存储,可以从键值对文件中直接获取键值对到集合中,也可以将集合中的元素以键值对的形式写入关联文件中
-
特有方法
- public Object setProperty(String key,String vaule)
- 将元素以键值对的形式存入集合中
- public String getproperty(String key)
- 根据键得到元素的值
- public Set stringPropertyNames()
- 得到集合中所有的键的集合
- void load(Reader reader)
- 将关联文件中的键值对元素加载进集合中
- void store (Writer writer,String comments)
- 将集合中的元素以键值对的形式存储进关联文件中
- public Object setProperty(String key,String vaule)
-
练习
- 判断指定文件中是否有指定的键,如果有,修改文件中该键所对应的值
public class ReviseVaule {//判断文件中是否有指定的键,如果有,改变键对应的值 public static void main(String[] args) throws IOException { /*需求:我有一个文本文件file.txt,我知道数据是键值对形式的,但是不知道内容是什么。 请写一个程序判断是否有 "lisi" 这样的键存在,如果有就改变其实为 "100" file.txt文件内容如下: zhangsan = 90 lisi = 80 wangwu = 85*/ Properties personInfo = new Properties();//创建双列集合,用来存储键值对 personInfo.load(new FileInputStream("file.txt"));//将集合与键值对文件关联 for (String name : personInfo.stringPropertyNames()) {//得到所有键的集合并遍历 if (name.equals("lisi")) {//如果键等于"lisi",就将该键所对应的值改为100 personInfo.setProperty("lisi", "100"); } } personInfo.store(new FileOutputStream("file.txt"), "修改过后的值");//将修改过后的值重新写入文件中 } }
8. SequenceInputStream
-
概述
- 可以将其他的流逻辑串联起来,实现文件的合并
-
构造方法
- SequenceInputStream(InputStream s1, InputStream s2)
-
练习
- 将两首歌曲合并
public class MusicCopy {//将两首歌曲合并 public static void main(String[] args) throws IOException { SequenceInputStream inputStream = new SequenceInputStream(new FileInputStream("许巍 - 蓝莲花.mp3"), new FileInputStream("许巍 - 曾经的你.mp3"));//将两个歌曲文件合并,得到合并后的字节 FileOutputStream outputStream = new FileOutputStream("C:\\Users\\北风\\Desktop\\歌曲合并.mp3");//创建字节输出流 byte[] bytes = new byte[1024 * 8]; int len; while ((len = inputStream.read(bytes)) != -1) {//将合并后的字节写出 outputStream.write(bytes, 0, len); } inputStream.close(); outputStream.close();//关闭流 } }
9. 压缩流与解压流
- ZipOutputStream
- 压缩流
- void putNextEntry(ZipEntry e)
- 开始写入新的 ZIP 文件条目并将流定位到条目数据的开始处。
- ZipInputStream
- 解压流
- ZipEntry getNextEntry()
- 读取下一个 ZIP 文件条目并将流定位到该条目数据的开始处。
- ZipEntry类
- 此类用于表示 ZIP 文件条目。
- String getName()
- 返回条目名称
- boolean isDirectory()
- 如果为目录条目,则返回 true