小码笔记:IO流
一、File类
java.io.File
文件和目录路径名的抽象表示,主要用于文件夹和目录的创建、查找和删除等操作
-
java中八电脑的文件和文件夹(目录)封装成一个File类 我们可以使用File类对文件和文件夹进行操作
-
File类是和系统无关的一个类,任何操作系统都可以使用这个类的方法
-
file 文件
direatory文件夹
path路径
1.构造方法
1.public File(String pathname)
返回通过路径名字符串转换为抽象路径创建新的File实例
2.public File(String parent,String child)
从父路径名字符串和子路径字符串创建新的File实例
父路径和子路径可以单独书写,使用起来非常灵活;父路径和子路径都可以变化
3.public File(File parent ,String child) 从父抽象路径名和子路径名字符串创建新的
父路径和子路径可以单独书写,使用起来非常灵活;父路径和子路径都可以变化
父路径是File类型,可以使用File类的方法对路径进行一些操作再创建对象
2.常用成员变量
1.static String pathSeparator 与系统相关的路径分隔符,被表示为一个字符串
static char pathSeparatorChar 与系统相关的路径分隔符
2.static String separator 与系统有关的默认分隔符,被表示为一个字符串
static char separator 与系统相关的默认分隔符
3.操作路径
1.Windows C:/develop/a/a.txt
2.Linux C:\develop\a\a.txt
3.通用写法:
" C:"+File.separator+"develop"+File.separato+"a"+File.separato+"a.txt"
4.绝对路径和相对路径
1.绝对路径 完整路径
以盘符开始的路径
C:\\JAVA\\javaWorkSpace\\ecilpse\\12-1day\\src\\a.txt
2.相对路径 简化路径
相对指的是对于当前的根目录
a.txt
3.注意 1.路径不区分大小写
2.路径中中文文件名称分隔符windows使用两个反斜杠
3.常用方法
1.获取 1.String getAbsolutePath() 返回File的绝对路径字符串
2.String getPath() 将File转换成路径名字字符串
3.String getName() 获取File表示的文件或者目录名称
4.long length() 返回File表示的文件长度 //不存在返回0
2.判断 1. boolean exits() 判断此File表示的文件或者目录是否实际存在
2. boolean isDirectory() 判断此File类表示的是否为空
3.boolean isFile() 判断此File类表示的是否是文件 .
3.新建删除 1. boolean createNewFile() 当且仅当具有该名称的文件夹不存在时,创建一个新的空文件,返回是否成功
2.boolean delete() 删除File表示的文件或者目录 (File要存在),返回是否成功
3.boolean mkdir() 创建File表示的目录,返回是否成功
4.boolean mkdirs() 创建File表示的目录,包括任何必须但不存在的父目录 (多级文件夹),返回是否成功
4.遍历 1.String[] list() 返回一个String数组,表示File类目录中所有子文件或者目录
2.File[] listFile() 返回一个File数组 ,表示File类目录中所有子文件或者目录
注意事项
list()和listFile()遍历的是构造方法中给出的目录
如果构造方法中给出的目录路径不存在会报空指针异常
目录和构造方法中的目录不一致也会报空指针异常
4.递归
-
递归:指在当前方法中内调自己的这种现象
-
分类
- 直接递归 方法自身调用自己
- 间接递归 A方法调用B,B方法调用C,C方法调用A
-
注意事项
- 递归一定要有条件限制 递归要保证能够停下来 否则会发生堆栈溢出
- 在递归中有限定条件但是也不能递归次数太多,否则也会发生堆栈溢出
- 构造方法禁止递归
-
使用前提
当调用方法时,方法的主体不变,每次调用方法的参数不同,可以使用递归
5.文件过滤器
- 在File类中有两个和isFiles()重载的方法,方法的参数传递就是过滤器
File[] listFiles(FileFilter filter)
File[] listFiles(FilenameFilter filter)
-
1.过滤文件(File对象)
java.io.FileFilter接口
:
用于抽象路径名(File对象)的过滤器boolean accept(File pathname) 用于过滤文件的方法,测试指定抽象路径是否应该包含在某个路径名称中 File pathname :使用ListFiles方法遍历目录得到每一个文件对象
-
2.用于过滤文件名称
java.io.FilenameFilter接口
:
实现此接口的类实例可用于过滤器文件名boolean accept(File dir ,String name) 测试指定文件是否应该包含在某一文件列表中
-
3.案例
(FilenameFilter也可以)这里用FileFiter举例 1.定义一个方法 参数传递File类型的目录 方法对目录进行遍历 public static void FileFilterImpl() implements FileFilter{ @Override public boolean accept(File pathname){ return pathname.isDirectory()||pathname.getName().toLowerCase.endWith(".java"); } } public static void getAllFile(File dir ){ File[] files =dir.listFiles(new FileFilterImpl()) ; //传过滤器对象 for(File f :files) { if(f.isDirectory()){ getAllFile(f); }else{ System.out.println(f); } } } 2.使用匿名内部类版本 public static void getAllFile(File dir ){ File[] files =dir.listFiles(new FileFilter(){ @Override public boolean accept(File pathname){ return pathname.isDirectory()||pathname.getName().toLowerCase.endWith(".java"); } }) ; //传过滤器对象 for(File f :files) { if(f.isDirectory()){ getAllFile(f); }else{ System.out.println(f); } } } 3. 使用Lambda表达式优化省略版本 public static void getAllFile(File dir ){ File[] files =dir. listFiles(pathname->pathname.isDirectory()||pathname.getName().toLowerCase().endWith(".java")); }
二、IO流概述
- IO:输入/输出(Input/Output)
- 流: 是一种抽象概念,是对数据传输的总称。也就是说数据在设备间的传输称为流,流的本质是数据传输
- IO 流就是用来处理设备间数据传输问题的。常见的应用:文件复制;文件上传;文件下载
1.分类选择
-
按照数据的流向
- 输入流:读数据
- 输出流:写数据
-
按照数据类型来分
- 字节流
- 字节输入流
- 字节输出流
- 字符流
- 字符输入流
- 字符输出流
- 字节流
-
IO流的使用场景
- 如果操作的是纯文本文件,优先使用字符流
- 如果操作的是图片、视频、音频等二进制文件。优先使用字节流
- 如果不确定文件类型,优先使用字节流。字节流是万能的流
2.IO异常的处理
1.在JDK1.7之后可以增加一个(),在括号中定义流对象
那么这个流对象的作用域就在try中有效
try中代码制定完毕会自动把流释放,不用finally
2.格式try (定义流对象){
可能产生异常的代码
} catch(异常类变量 变量名){
异常处理逻辑
}
3.
try(FileWriter fw =new FileWriter(D:\\a.txt)){
for(int i=0;i<10;i++){
fw.write("你好"+"\n");
}
}catch(TOException e){
System.out.println(e);
}
3.Properties属性集
点击查看父类Hashtable
java.util.Properties
集合
-
上层父类:Hashtable
Properties类表示了一个持久的属性集。Properties可以保存在流中或者从流中加载 -
Properties是唯一一个和IO流结合的集合
可以使用Properties集合中的方法store()把集合中的临时数据持久化写入到硬盘中存储
可以使用Properties集合中的犯法load(),把硬盘中的文件(键值对),读取到集合中使用 -
使用
1.使用Properties集合中存储取出数据 Properties是一个双列集合,key和value默认是String 2.操作字符串的方法 Object setProperty(String key,String value ) 调用Hashtable中的方法put String getProperty(String key) 通过key找到值相当于Map集合中的get(Key key) set<String> stringPropertyNames() 返回此属性的键集,其中该键及其对应值是String 相当于Map集合中的keySet() 3.Properties遍历集合 Properties prop =new Properties(); prop.setProperty("姓名","张三"); prop.setProperty("性别","男"); prop.setProperty("年龄",18); Set<String > set =new prop.stringPropertyNames(); for(String key:set){ String value = prop.getProperty(key); System.out.println(key+"="+value); }
-
输出流应用store()
1.可以使用Properties集合中的方法store 把集合中的临时数据,持久化写入硬盘 void store(OutStream out,String comments) void store(Writer writer,String comments) 参数 OutputStream out 字节输出流,不能写中文 Writer writer 字符输出流, 能写中文 String comments 注释:用来说明保存的文件是做什么的用的(显示在目的地第一行), 不能用中文写,一般用""空字符串 2.使用步骤 1.创建Properties集合对象,添加数据 2. 创建字节/字符输出流,构造方法中绑定输出目的地 3.使用Properties集合中的方法store(),把集合中的临时数据,持久化写入硬盘 4.释放资源(关闭输出流) 3.案例 Properties prop =new Properties(); prop.setProperty("姓名","张三"); prop.setProperty("性别","男"); prop.setProperty("年龄",18); prop.store(new FileWriter("D:\\a.txt"),"");
-
输入流应用load()
1.可以使用Properties集合中的方法load 把硬盘中保存的文件(键值对),读取到集合中使用 void store(InputStream inputStream) void store(Reader reader) 参数 IutputStream inputStream 字节输入流,不能写中文 Reader reader 字符输入流, 能写中文 2.使用步骤 1.创建Properties集合对象 2.使用Properties集合中的方法load()读取保存键值对的文件 3.遍历Properties集合 3.注意事项: 1.存储在键值对的文件中,键与值连接符号可以使用 = 空格 (其他符号) 2.存储在键值对的文件中,可以使用#进行注释,不会再被读取 3.存储在键值对的文件中,键值都是默认字符串,不用再加引号
三、字节流
一切文件数据(文本、图片、视频等)在传输时,都是以二进制数字形式保存
字节流可以传输任意数据
- 字节流抽象类
InputStream
:表示字节输入流的所有类的超类
OutputStream
:表示字节输出流的所有类的超类
子类名特点:子类名称都是以其父类名作为子类名的后缀
1.字节输出流(OutputStream)
java.io.OutputStream
抽象类是表示字节输出流的超类 字节输出流
-
1.常用方法
1.void close() 关闭此输出流并释放相关的资源 有异常要抛出 2.void flush() 刷新输出流并强制任何缓冲的输出字节被写出 3.void write(byte[] b): 将B.length字节从指定的字节数组写入输出流 注意事项:1.如果第一个字节是正数:(0-127) 显示会查询ASCLL码表 2.如果第一个字节是负数:第一个字节会和第二个字节组成一个中文显示,查Unicode表 void write(byte[] b,int start,int len): 从指定的字节数组写入len字节 从start开始输出到此输出流。把字节数组的一部分写入到文件中 4.abstract void write(int b) 将指定的字节输出流
-
2.文件字节输出流( FileOutputStream )
java.io.FileOutputStream extends OutputStream
文件字节输出流
把内存的数据写入到硬盘的文件中 -
构造方法
1.FileOutputStream(String name):创建一个具有指定名称的文件写入数据的输出文件流 FileOutputStrem(File file) :创建一个向指定File文件对象表示的文件写入数据的文件输出流 2. 参数:写入数据的目的 String name:目的地是一个文件的路径 File file :目的地是一个文件 3. 构造方法的作用 1.创建一个FileOutputStrem对象 2.会根据构造方法传递的文件/路径创建一个空文件夹 3.会把FileOutputStream对象指向创建好的文件夹
-
使用
1.写入数据的原理(内存-->硬盘) java程序-->JVM-->OS(操作系统) -->OS调用写数据方法-->把数据写到文件中 2.字节输出流的使用步骤 1. 创建一个FileOutputStream对象,将构造方法中传递写入目的地 2.调用FileOutputStream对象中的方法write()将数据写入到文件中 3.释放资源(流使用会占用一定的内存,使用完毕后要把内存清空,提高程序的效率) 3.换行 写换行符号 windows : \r \n linux : /n mac : \r 4.举例: FileOutputStream fos =new FileOutputStream("D:\\a.text") //写一个 fos.write(48);//0 //写多个 byte[] bts = {65,66,67,68,69}//ABCDE fos.write(bts,1,2);//BC //写字符串 byte[] bts2 ="你好".getButes(); fos.write(bts2); fos.write() fos.close();
2.字节输入流(InputStream)
java.io.InputStream
抽象类
表示字节输入流的超类 字节输入流
-
常用方法
1.int read() 从输入流中读取数据的写一个字节并返回,读取完毕返回-1 2.int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中 3.void close() 关闭此输入流并释放相关的资源 有异常要抛出
-
文件字节输入流( FileInputStream )
java.io.FileInputStream extends InputStream
文件字节输入流
把硬盘中的文件数据读取到内存中使用-
使用
1.写入数据的原理(内存-->硬盘) java程序-->JVM-->OS(操作系统) -->OS调用读取数据方法-->读取数据文件 2.字节输出流的使用步骤 1. 创建一个FileIutputStream对象,将构造方法中传递读取目的地 2.调用FileIutputStream对象中的方法read()将数据读取文件 3.释放资源 3.字节流读取文本时,如果遇到中文字符可能不会显示完整的字符, 因为中文字符可能占用多个字节存储,导致乱码 此时建议用字符流读取 GBK :占用两个字节 UTF-8:占用三个字节 4.举例: FileIutputStream fis =new FileIutputStream("D:\\a.text") //读一个 int len =fis.read();//a-->97 System.out.print(char(len));//a //读多个 int len =fis.read(); while((len=fis.read())!=-1){//abc System.out.print(char(len));//abc } //自定义长度读取 1K byte[] byts =new byte[1024] int len =fis.read(); while((len=fis.read(byts))!=-1){//abc System.out.print(char(len));//abc } fis.close();
- 文件复制练习
public static void main(String[] args) throws IOException{ //创建流 FileIutputStream fos =new FileIutputStream("D:\\a.text") FileOutputStream fis =new FileOutputStream("E:\\a.text") //读取 int len =0; byte[] bytes =new byte[1024]; while ((len=fis.read(bytes))!=-1) { fis.write(len); } //释放资源 fis.close(); fos.close(); }
- 文件复制练习
-
四、字符流(和字节流用法基本一样)
以字符问单位进行读写数据,专门用于处理文本文件
- 字节流抽象类
- Reader:表示字符输入流的所有类的超类
- Writer:表示字符输出流的所有类的超类
- 子类名特点:子类名称都是以其父类名作为子类名的后缀
1.字符输入流(Reader)
java.io.Reader抽象类时表示用于输入字符流的所有类的超类 字符输入流
基本用法和方法跟字节流一样,不写了
- 文件字符输入流( FileReader )
java.io.FileReader
extends InputStreamReader extends Reader
把硬盘中的文件数据以字符的方式读取到内存中使用
用法同文件字节输入流
2.字符输出流(Writer)
java.io.Writer抽象类时表示用于读取字符流的所有类的超类 字符输出流
基本用法和方法跟字节流一样,不写了
- 文件字符输出流( FileWriter )
java.io.FileWriter
extends InputStreamWriter extends Writer
把内存的数据写入到硬盘的文件中
用法同文件字节输出流
五、其他流
1.缓冲流/高效流
缓冲流,也叫高效流,是对四个基本FileXX流的增强
- 分类
- 字节缓冲流
BufferedIuputStream
BufferedOutputStream - 字符缓冲流
BUfferedReader
BufferedWriter
- 字节缓冲流
用法类似详细了解请查看wqg_code的博客IO—转换流和缓冲流总结
2.转换流
- OutputStreamWriter
创建一个新的缓冲输出流,以数据写入指定的底层输出流 - IutputStreamReader
创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流
用法类似详细了解请查看wqg_code的博客IO—转换流和缓冲流总结
3.打印流
java.io.PrintStream
extends OutputStream
打印流
PrintStream为其他输出流添加了功能,使他们能方便的打印各种数据表示形式
-
打印流特点
- 只负责输出,不负责读取
- 与其他输出流不同,PrintStream永远不会抛出IOException
- 特有方法print,println
void print(任意类型的值) void println(任意类型的值并换行)
-
构造方法
PrintStream(File file):输出的目的地是一个文件 PrintStream(OutputStream out )输出的目的地是一个文件字节流 PrintStream(String fileName):输出的目的地是一个文件路径
-
注意事项:
如果使用继承自父类的方法写数据 那么查看数据的时候会查询编码表 97->a
如果使用自己特有的print/println方法会原样输出 97->97
六、字符编码
1.ASCLL码表
美国信息交换标准代码,是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要控制字符(回车、退格、换行)
等可显示字符(英文大小写字符、阿拉伯数字和西文符号)
基本ASCLL码字符集使用7(bit)表示一个字符,共128个字符。ASCLL扩展字符集使用8(bit)表示一个字符,共256字符方便支持欧洲常用字符
2.ISO-8859-1字符集
拉丁码表,别名Latin-1,用于显示欧洲常用的语言,比如荷兰、丹麦、德语、意大利语、西班牙语等
ISO-8859-1使用单字节编码,兼容ASCLL码表
3.GBK
GBXXX系列,国标,用于显示中文而设计的一套字符集
GBK:最常用的中文码表。实在GB2312基础上扩展规范使用了双字节编码放啊,共收录了21003个汉字。同时支持繁体中文、日文、韩文
4.Unicode字符集
Unicode编码自用是为了表达任意语言设计的业界标准的,统一码,万国码
它最多使用四个字节来表达每个字母、符号、或者问题。有三种编码方案,UTF-8、UTF-16、UTF-32。UTF-8最常用
七、序列化和反序列化
1.Java序列化的机制
-
序列化:用一个字节表示一个对象,该序列包含的对象的数据、对象的类型、对象存储的属性等信息
字节序列化写到文件后,相当于文件中持久保存了一个对象的信息 -
反序列化,从文件重构对象,反序列化。将对象的数据、对象的类型、对象存储的属性等信息用来在内存中创建对象
-
序列化和反序列化的时候会抛出
NotSerializableException 没有序列化异常
需要序列化的对象所在的类需要实现java.io.Serizlizable
接口以启动其序列化功能
2.Serializable接口
标记型接口
要进行序列化和反序列化的类必须实现Serializable
接口,就会给类加一个序列化标记
当继续进行序列化或者反序列化时,就是检测类上是否有这个标记
- 有,可以序列化和反序列化
- 没有,抛出没有序列化异常
3.ObjectOutputStream
java.io.ObjectOutputStream extends OutputStream
对象的序列化流
把对象以流的方式写入到文件中保存
1. 构造方法
ObjectOutputStream (OutputStream out):创建一个写入执行OutputStream的ObjectOutputStream
OutputStream out:字节输出流
4. 成员方法:
void writerObject(Object obj) 将指定的对象写入ObjectOutputStream
- 使用
1. 字节输出流的使用步骤
1.创建ObjectOutputStream,构造方法中将OutputStream作为参数传递进去
2.调用ObjectOutputStream对象中的方法writeObject()将数据写入到文件中
3.释放资源,默认先调用flush()
2. 举例:
FileOutputStream fos =new FileOutputStream("D:\\a.text")
ObjectOutputStream oos =new ObjectOutputStream(fos);
bos.writeObject(new Person("张三","18","男"));
//Person类必须实现Serializable接口,否则报没有序列化
bos.close();
3.ObjectInputStream
java.io.ObjectInputStream extends InputStream
对象的反序列化流
把文件中保存的对象以流的形式读取
成员方法:
void readObject() 将指定的对象写入ObjectOutputStream
其他地方用法一样,就这个方法不同。一个序列化方法,一个是反序列化方法
- 注意事项
1.readerObject方法中抛出了ClassNotFountException(文件找不到异常)
当不存在对象时抛出异常
反序列化前提:1.类必须实现Serializable接口
2.类必须存在类对应的class文件
2.当JVM反序列化时,能找到class文件但是序列化对象之后发生了修改,
反序列化失败抛出InvalidClassException
如何解决:手动添加序列号
3.手动写序列号
格式在Serializable接口规定:
可序列化类通过声明seriaIVersionUID的字段(必须 static final long修饰)显示声明其自己的序列号
static final long seriaIVersionUID=42L //常量 不能改变
4.transient关键字
-
static 关键字:静态关键字
静态优先于非静态加载到内存中(静态优先于对象进入到内存中)
被static 修饰的成员变量不能被序列化,序列化的都是对象 -
transient关键字 瞬态关键字
被transient修饰的成员变量不能被序列化