关卡十四:IO流
一、File类
1.File概述
(1)它是文件名和目录路径名的抽象表示
(2)文件和目录是可以通过File封装成对象
(3)对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已。它可以是存在的,也可以是不存在的。将来是要通过具体的操作把这个路径的内容转换为具体存在的
2.File类的构造方法
File(String pathname);通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
File(String parent, String child);从父路径名字符串和子路径名字符串创建新的 File实例
File(File parent, String child);从父抽象路径名和子路径名字符串创建新的 File实例
3.File类的创建功能
public boolean createNewFile();当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件
public boolean mkdir();创建由此抽象路径名命名的目录
public boolean mkdirs();创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录
4.File类判断和获取方法
(1)判断方法
public boolean isDirectory();测试此抽象路径名表示的File是否为目录
public boolean isFile();测试此抽象路径名表示的File是否为文件
public boolean exists();测试此抽象路径名表示的File是否存在
(2)获取功能
public String getAbsolutePath();返回此抽象路径名的绝对路径名字符串
public String getPath();将此抽象路径名转换为路径名字符串
public String getName();返回由此抽象路径名表示的文件或目录的名称
public String[] list();返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
public File[] listFiles();返回此抽象路径名表示的目录中的文件和目录的File对象数组
(3)删除功能
public boolean delete();删除由此抽象路径名表示的文件或目录
删除目录时,注意:目录中有文件时,需删除目录中的文件
(4)递归
递归指的是方法定义中调用方法本身的现象
递归一定要有出口。否则内存溢出
递归虽然有出口,但是递归的次数也不宜过多。否则内存溢出
二、 IO流
1.概述:IO:输入/输出(Input/Output);流:是一种抽象概念,是对数据传输的总称。也就是说数据在设备间的传输称为流,流的本质是数据传输
2.IO流的分类
(1)按照数据的流向
输入流:读数据
输出流:写数据
(2)按照数据类型来分
①字节流
字节输入流
字节输出流
②字符流
字符输入流
字符输出流
3.IO流的使用场景
如果操作的是纯文本文件,优先使用字符流
如果操作的是图片、视频、音频等二进制文件。优先使用字节流
如果不确定文件类型,优先使用字节流。字节流是万能的流
(一)字节流
1.字节流的抽象类
OutputStream:这个抽象类是表示字节输出流的所有类的超类
InputStream:这个抽象类是表示字节输入流的所有类的超类
2.字节输出流:FileOutputStream(String name):创建文件输出流以指定的名称写入文件
3.使用字节输出流写数据的步骤
(1)创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
(2)调用字节输出流对象的写数据方法
(3)释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)
4.写数据的方法分类
void write(int b);将指定的字节写入此文件输出流 一次写一个字节数据
void write(byte[] b);将 b.length字节从指定的字节数组写入此文件输出流 一次写一个字节数组数据
void write(byte[] b, int off, int len);- | 将 len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流 一次写一个字节数组的部分数据
5.读数据
(1) 一次读一个字节
FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream ,该文件由文件系统中的路径名name命名
(2) 字节输入流读取数据的步骤
①创建字节输入流对象
②调用字节输入流对象的读数据方法
③释放资源
(3)一次读一个字节数组
public int read(byte[] b):从输入流读取最多b.length个字节的数据
返回的是读入缓冲区的总字节数,也就是实际的读取字节个数
6.字节缓冲流
(1)BufferOutputStream:该类实现缓冲输出流。 通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
(2)BufferedInputStream:创建BufferedInputStream将创建一个内部缓冲区数组。 当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节
(二)字符流
1.字符流 = 字节流 + 编码表
2.Reader输入字符流、wirte输出流字符串
3.字符串解码编码
byte[] getBytes(),使用平台的默认字符集将该 String编码为一系列字节
byte[] getBytes(String charsetName),使用指定的字符集将该 String编码为一系列字节
String(byte[] bytes),使用平台的默认字符集解码指定的字节数组来创建字符串
String(byte[] bytes, String charsetName),通过指定的字符集解码指定的字节数组来创建字符串
4.输入输出流解码编码
InputStreamReader(InputStream in),使用默认字符编码创建InputStreamReader对象
InputStreamReader(InputStream in,String chatset),使用指定的字符编码创建InputStreamReader对象
OutputStreamWriter(OutputStream out),使用默认字符编码创建OutputStreamWriter对象
OutputStreamWriter(OutputStream out,String charset),使用指定的字符编码创建OutputStreamWriter对象
5.字符流写数据
void write(int c),写一个字符
void write(char[] cbuf),写入一个字符数组
void write(char[] cbuf, int off, int len),写入字符数组的一部分
void write(String str),写一个字符串
void write(String str, int off, int len),写一个字符串的一部分
刷新和关闭的方法
flush(),刷新流,之后还可以继续写数据
close(),关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据
6.字符流读数据方法
int read(),一次读一个字符数据
int read(char[] cbuf),一次读一个字符数组数据
7.字符缓冲流
(1)BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。默认值足够大,可用于大多数用途
(2)BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途
(3)BufferedWriter(Writer out),创建字符缓冲输出流对象
(4)BufferedReader(Reader in),创建字符缓冲输入流对象
(5)字符缓冲流特有功能
①void newLine()写一行行分隔符,行分隔符字符串由系统属性定义
②String readLine()读一行文字。 结果包含行的内容的字符串,不包括任何行终止字符如果流的结尾已经到达,则为null
(三)特殊操作流
1.标准输入流
public static final InputStream in:通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源
2.标准输出流
public static final PrintStream out:通常该流对应于显示输出或由主机环境或用户指定的另一个输出目标
3.打印流
(1)字节打印流:PrintStream
PrintStream(String fileName):使用指定的文件名创建新的打印流
使用继承父类的方法写数据,查看的时候会转码;使用自己的特有方法写数据,查看的数据原样输出
可以改变输出语句的目的地:public static void setOut(PrintStream out):重新分配“标准”输出流
(2)字符打印流:PrintWriter
PrintWriter(String fileName);使用指定的文件名创建一个新的PrintWriter,而不需要自动执行刷新
PrintWriter(Writer out, boolean autoFlush);创建一个新的PrintWriter out:字符输出流 autoFlush: 一个布尔值,如果为真,则println , printf ,或format方法将刷新输出缓冲区
(3)打印流的特点
①只负责输出数据,不负责读取数据
②永远不会抛出IOException
③有自己的特有方法
4.对象序列化流
(1)对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象
(2)这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息
(3)字节序列写到文件之后,相当于文件中持久保存了一个对象的信息,反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化
(4)对象序列化流 ObjectOutputStream
①构造方法
ObjectOutputStream(OutputStream out)创建一个写入指定的OutputStream的ObjectOutputStream
void writeObject(Object obj)将指定的对象写入ObjectOutputStream
②注意事项
一个对象要想被序列化,该对象所属的类必须必须实现Serializable 接口
Serializable是一个标记接口,实现该接口,不需要重写任何方法
(5)对象反序列化流: ObjectInputStream
ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象
①构造方法
ObjectInputStream(InputStream in)- | 创建从指定的InputStream读取的ObjectInputStream
Object readObject()从ObjectInputStream读取一个对象
(5)对象序列化常见问题
①用对象序列化流序列化了一个对象后,假如我们修改了对象所属的类文件,抛出问题;
② 重新序列化
给对象所属的类加一个serialVersionUID ;private static final long serialVersionUID = 42L;
③如果一个对象中的某个成员变量的值不想被序列化
给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程
5.Properties作为Map集合的使用
(1)不能使用泛型,遍历集合默认为Object类型
(2)特有方法
Object setProperty(String key, String value);设置集合的键和值,都是String类型,底层调用 Hashtable方法 put
String getProperty(String key);使用此属性列表中指定的键搜索属性
Set<String> stringPropertyNames()从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串
6. Properties与IO流结合的方法
void load(InputStream inStream)从输入字节流读取属性列表(键和元素对)
void load(Reader reader)从输入字符流读取属性列表(键和元素对)
void store(OutputStream out, String comments)将此属性列表(键和元素对)写入此 Properties表中,以适合于使用 load(InputStream)方法的格式写入输出字节流
void store(Writer writer, String comments)将此属性列表(键和元素对)写入此 Properties表中,以适合使用 load(Reader)方法的格式写入输出字符流
(实践题)使用输入流读取试题文件,每次显示试题文件中的一道题目。读取到字符“*”时暂停读取,等待用户从键盘输入答案。用户做完全部题目后。程序给出用户的得分(10分一道题)。
1) 试题内容如下:
(1)英雄联盟S9全球总决赛是什么时间开幕的?
A.2018-08-08 B. 2018-08-01
C.2019-10-01 D. 2019-10-02
********************
(2)下列哪个英雄不属于《英雄联盟》?
A.卡特 B.盲僧 C.剑豪 D.后羿
********************
(3).以下哪一句不是疾风剑豪亚索的台词?
A.死亡如风,常伴吾身。B.面对疾风吧!C.真正的大师,永远都怀着一颗学徒的心。D.哈塞给!
********************
(4).英雄联盟世界S赛被OMG基地50血翻盘的战队是?
A.SKT B.Najin C.FNC D.G2
********************
(5)英雄联盟中,戏称最争气的英雄是?
A迅捷斥候 B蒸汽机器人 C德玛西亚之力 D疾风剑豪
********************
-------》程序运行如下:
(1)英雄联盟S9全球总决赛是什么时间开幕的?
A.2018-08-08 B. 2018-08-01
C.2019-10-01 D. 2019-10-02
输入选择的答案(A、B、C、D):D
(2)下列哪个英雄不属于《英雄联盟》?
A.卡特 B.盲僧 C.剑豪 D.后羿
输入选择的答案(A、B、C、D):D
...
...
完成试题,恭喜你 你最后的得分为:20 分。
*/
package IOliu;import java.io.BufferedReader;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.IOException;import java.util.Scanner;public class Char_2_4 { public static void main(String[] args) throws IOException { System.out.println("++++++++++++++++++++++++++"); System.out.println("++ ++"); System.out.println("++ 欢迎来到联盟小测试系统 ++"); System.out.println("++ ++"); System.out.println("++++++++++++++++++++++++++"); BufferedReader br = new BufferedReader(new FileReader("E:\\DELL\\后端关卡8-16\\关卡14_文件IO流\\03_字符流\\T4.txt")); String line; int in=0,index=0,in1=0; while ((line=br.readLine())!=null){ if (!line.equals("*")) { System.out.println(line); index++; if (index%3==0) { in1++; in = select(in, in1); } }else { continue; } } System.out.println("完成试题,恭喜你 你最后的得分为:"+in+"分"); br.close(); } public static int select(int in,int in1){ Scanner sc = new Scanner(System.in); System.out.print("输入选择的答案(A、B、C、D):"); String s; while (true){ s=sc.next(); if (s.equals("A")||s.equals("a")||s.equals("B")||s.equals("b")|| s.equals("c")||s.equals("C")||s.equals("D")||s.equals("d")){ break; }else { System.out.print("您输入的选择有误,请重新输入答案:"); } } switch (in1){ case 1: if (s.equals("D")||s.equals("d")){ in+=10; } break; case 2: if (s.equals("D")||s.equals("d")){ in+=10; } break; case 3: if (s.equals("D")||s.equals("d")){ in+=10; } break; case 4: if (s.equals("D")||s.equals("d")){ in+=10; } break; case 5: if (s.equals("D")||s.equals("d")){ in+=10; } break; } return in; }}