目录
6. 字符输出writer-------(OutputStream字节输出)
7.Filewriter-------(字节输出FileOutputStream)
8.字符流Reader读取输入)-----inputStream(字节流)
9.FileReader字符输入--------------FileInputStram(字节输入)
11.转换流InputStreamReader和OutputStreanmReader
11.1InputStreamReader(读取):字节输入转字符输入
11.2 OutputStreanmReader:字节输出转字符输出
15.1 ObjectOutputStream和ObjectInputStream
15.3.3.writerObject和readObject两方法,实现Serializble类里
16. Serializable VS Externalizable
一、File类
表示文件和目录路径名的抽象表示。
文件夹:
文件(名):
路径:路径表示文件夹:C:\Users\Administrator\Desktop\java笔记
也可以表示具体的文件:C:\Users\Administrator\Desktop\Hellow Word.docx
1.构造方法:
可实例化(new对象)
构造器 | 描述 |
File(File parent , String child) | 从父抽象路径名和子路径名字符串创建新的 File实例。 |
File(String pathname) | 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。 |
File(String parent , String child) | 从父路径名字符串和子路径名字符串创建新的 File实例。 |
File(URI uri) | 通过将给定的 file: URI转换为抽象路径名来创建新的 File实例。 |
File(String pathname):参数:文件路径--此对象只表示文件路径
File(File parent , String child):文件路径对象下创建
File(String parent , String child):文件路径创建
区别:
File parent:把路径封装成了对象
String parent :路径用字符串表达
2.方法:
2.1创建:
创建文件
boolean | 当且仅当具有此名称的文件尚不存在时,以原子方式创建由此抽象路径名命名的新空文件。 |
True,指定文件不存在并创建成功,false指定文件存在没有创建
如果磁盘受保护拒接访问,会抛出异常IO异常(受监测的)
1:使用编译器时用管理员身份运行
2:如果1不能解决换其他盘
创建文件夹
boolean | mkdir() | 创建此抽象路径名指定的目录。 |
创建的是最后一个haha,但是最后一个haha,没有其父haha,创建是失败的(中间的文件夹不存在)-------------------------------------即指定创建的文件夹的目录中间有些不存在
boolean | mkdirs() | 创建此抽象路径名指定的目录,包括任何必需但不存在的父目录。 |
创建的是最后一个haha,但是最后一个haha,没有其父haha,中间的文件夹不存在,创建时会自动补齐不存在的文件夹
2.2删除:
boolean | delete() | 删除此抽象路径名表示的文件或目录 |
表示删除路径下的内容可能是文件可能是文件夹具体看创建的file对象表示什么
2.3获取:
String | 返回此抽象路径名的绝对路径名字符串。 |
返回绝对路径字符串
String | getName() | 返回此抽象路径名表示的文件或目录的名称。 |
返回文件名
String | 返回此抽象路径名父项的路径名字符串,如果此路径名未指定父目录,则返回 null 。 |
返回null则表示到了盘符最开始,------D盘
File | 返回此抽象路径名父项的抽象路径名,如果此路径名未指定父目录,则返回 null 。 |
long | length() | 返回此抽象路径名表示的文件的长度。 |
表示文件的长度(文件大小)以字节为单位,最大只能获取2g的文件大小,因为返回值类型long使用4个字节大小来表示,最大为2的31次方也就是2G的大小
2.4判断:
boolean | exists() | 测试此抽象路径名表示的文件或目录是否存在。 |
是否是文件或文件夹
boolean | 测试此抽象路径名表示的文件是否为目录。 |
是否是文件夹
boolean | isFile() | 测试此抽象路径名表示的文件是否为普通文件。 |
是否是文件
2.5获取:
String[] | list() | 返回一个字符串数组,用于命名此抽象路径名表示的目录中的文件和目录。 |
获取文件夹里所有文件------所有文件指文件or文件夹返回一个String类型的数组---以路径形式存在
File[] | 返回一个抽象路径名数组,表示此抽象路径名表示的目录中的文件。 |
获取此路径下文件夹里所有文件------所有文件指文件or文件夹返回一个file类型的数组一对象为单位存储
File[] | listFiles(FileFilter filter) | 返回一个抽象路径名数组,表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。 |
获取传进来的,文件夹里的所有对象,返回一个数组
2.5修改:
boolean | renameTo(File dest) | 重命名此抽象路径名表示的文件 |
RenameTo:表示某个文件从所在路径目录下,剪切到 ,指定目录下并改名
注意是剪切!谁调用谁是被剪切的。参数表现新的地方新的名字即新路径
3.字段:
在不同系统中,表示文件路径的符号不一样,Java统一了。
static String | 与系统相关的路径分隔符,为方便起见,表示为字符串。 分号 ; | |
static char | 与系统相关的路径分隔符。 | |
static String | 系统相关的默认名称分隔符,为方便起见,表示为字符串。斜杠\ | |
static char | 系统相关的默认名称分隔符。 |
如何使用?都是静态的
4.文件夹遍历:
需要传入一个FIle数组类型
通过上面的方法可得到
判断这个数组不是空的,且有内容(大小)
遍历这个数组
判断是否是文件
是文件:
判断文件名是不是以.avi结尾的,是输出,文件所在的路径字符串
不是文件:
创建一个新数组,把不是文件的文件夹,通过listFiles()获取到里面的所有文件(可能有文件也可能有文件夹),递归调用自己------过滤不是文件的
如果是文件,也是以.avi结尾的,判断其大小。100*1024*1024 100KB
1*1024 = KB
1*1024*1024 = MB
5.文件过滤:(了解)接口FileFilter
String[] | list(FilenameFilter filter) | 返回一个字符串数组,用于命名由此抽象路径名表示的目录中的文件和目录,以满足指定的过滤器。 |
File[] | listFiles(FileFilter filter) | 返回一个抽象路径名数组,表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。 |
FileFilter:是一接口需要被实现
使用方式类似于Comparable比较器
通过Flie对象获取文件中的内容时,加入一个过滤器对象,在过滤器对象里描述过滤规则
1.写一个类去实现过滤器,类里面重写抽象方法
2.创建过滤器(多态的形式)
3.通过文件获取文件夹
此方法返回file所有文件,包括文件夹和文件
4.走过滤器,怎么走?
传入过滤器,返回到数组里的就是过滤后的
总结:
通过一个类去实现过滤器,并重写过滤规则。然后创建过滤器,通过过滤器的方法
List和listfiles,参数里传入过滤器,即可达到过滤的效果,返回过滤后的file[]
注意只是获取,而非过滤删除。需要其他操作后续判断调用其他方法
也可以使用匿名内部类使用一次的话
创建对象的时候以接口名创建,并在对象后面重写方法
还可以参考Compatator:
在需要传入过滤器的地方重写,new 一个过滤器并重写方法
6.相对和绝对路径:
绝对路径:从盘符号开始是一个完整的路径例如: c://a.txt有盘符
相对路径:相对?----在JAVA代码中是相对于项目目录路径,这是一个不完整的便捷路径,在JAVA开发中很常用。
例如:a.txt
盘符在哪?在你使用的程序包里
在项目文件夹里
创建的时候不加盘符,就是创建在你项目下的
相当于这里创建
二、IO流概述
什么是IO流?
In流入
Out就出
例如:复制从某个盘到另一个盘
下载文件到电脑中。
都是数据在传输,可以将这种数据传输的操作,看做数据的流动,从C盘到D盘,
按照流动的方向分为输入Input和输出Output
Input:输入到电脑
Output:从电脑输出
电脑只是举例的基点
c盘到d盘,具体分析,c是流出,d是流入,是相对的。
体现在数据流动
Java中io操作主要指的是java.io包下的一些常用类的使用,通过这些类,对数据进行读取(输入流input),写出输出output
IO流分类
按照流的方向:输入流和输出流
按照流动的数据类型分:字节流和字符流
字节流:(主要划分以类的结构划分)
--输入流:顶级的父类 inputStream
--输出流:顶级的父类outoutStream
字符流:(也是来自于字节流,不过是被处理后的)
--输入流:顶级的父类reader
--输出流:顶级的父类writer
1.OutputStream(字节流--输出流)抽象类
一切皆字节:计算机中的任何数据都是以字节存储的(文本、图片、视频、音乐等等)都是以二进制的形式存储的。
在数据传输时,也都是以二进制存储的。
任何流,在传输时,底层都是二进制。
1.1方法:
-
-
void
close()
关闭此输出流并释放与此流关联的所有系统资源。
void
flush()
刷新此输出流并强制写出任何缓冲的输出字节。
static OutputStream
nullOutputStream()
返回一个新的
OutputStream
,它丢弃所有字节。void
write(byte[] b)
将
b.length
字节从指定的字节数组写入此输出流。void
write(byte[] b, int off, int len)
将从偏移量
off
开始的指定字节数组中的len
字节写入此输出流。abstract void
write(int b)
将指定的字节写入此输出流。
-
Close:每次使用完流都要使用这个方法
write(byte[] b, int off, int len),将从偏移量 off开始的指定字节数组中的 len字节写入此输出流。
从某个下标开始写多少个,而不是从某个下标开始到某个下标结束
public abstract void write(int b) throws IOException
将指定的字节写入此输出流。 write的一般合同是将一个字节写入输出流。 要写入的字节是参数b的八个低位。 b的24个高位被忽略。
OutputStream子类必须提供此方法的实现。
要写入的字节是参数b的八个低位b的24个高位被忽略?
int = 4个字节b = 32bit
1个字节b = 8个比特位bit
前面是被忽略的只看后面8位 最大是 二进制 11111111 十进制 255 即int不能超过255
其子类无论哪一个写数据 就这3个write方法写完要关闭他!
2.FileOutputStream---常用
OutputStream的子类可实例化,但是还是用到其子类
文件输出流是用于将数据写入File或FileDescriptor的输出流。
每一个fileoutputStream对象就表示向某个文件的输出流管道
构造方法:
构造器 | 描述 |
FileOutputStream(File file) | 创建文件输出流以写入由指定的 File对象表示的文件。 |
FileOutputStream(FileDescriptor fdObj) | 创建要写入指定文件描述符的文件输出流,该文件描述符表示与文件系统中实际文件的现有连接。 |
FileOutputStream(File file, boolean append) | 创建文件输出流以写入由指定的 File对象表示的文件。 |
FileOutputStream(String name) | 创建文件输出流以写入具有指定名称的文件。 |
FileOutputStream(String name, boolean append) | 创建文件输出流以写入具有指定名称的文件。 |
常用的有4个2组
红色:file传入文件对象来建立这个输出流
蓝色:String传入文件路径来建立
boolean append:true表示是否接着原来的写,false表示清空后在写,运行2次
第一次添加后,在运行添加,默认清空
运行一次:
如果一个对象,添加2次是接着的直到关闭前都是append追加的
运行两次:
第二次不会接着第一次的写,只有true,才会表示追加上一次执行的写
字节流写的是byte字节,byte[]数组
方法:3个write方法
3.异常
文件没有(虽然会自己创建但是会有权限不允许的时候)
属于IOexception子类
65输出的是A------65是byte类型而不是Int
记住记住要关闭流
流关闭以后就不要再去写了,否则会报IO异常
4.InputStream字节输入流---常用
4.1方法:
abstract int | read() | 从输入流中读取下一个数据字节。 | ||||
int | read(byte[] b) | 从输入流中读取一些字节数并将它们存储到缓冲区数组 b 。 |
返回-1读完了 范围0-255子类fileinputStream
5.FileinputStream
5.1构造器:
FileInputStream(File file) | 通过打开与实际文件的连接来创建 FileInputStream ,该文件由文件系统中的 File对象 file命名。 |
FileInputStream(FileDescriptor fdObj) | 使用文件描述符 fdObj创建 FileInputStream ,该文件描述符表示与文件系统中实际文件的现有连接。 |
FileInputStream(String name) | 通过打开与实际文件的连接来创建 FileInputStream ,该文件由文件系统中的路径名 name命名。 |
5.2方法:
int | read() | 从此输入流中读取一个字节的数据。 |
int | read(byte[] b) | 从此输入流 b.length最多 b.length字节的数据读 b.length字节数组。 |
int | read(byte[] b, int off, int len) | 从此输入流 len最多 len字节的数据读入一个字节数组。 |
long | skip(long n) | 跳过并从输入流中丢弃 n字节的数据。 |
返回值是int,用byte表示需要强转过来 不然读取的就是int类型
Char + 数字 输出 数字对应ascii表里的字符
Byte + 数字 输出 数字
Char + 字符 输出 字符
Byte + 字符 输出 字符对应asci表里的数字
Char 输出字符 byte输出数字
字节流读取的是byte字节,需要转成字符char
5.2.1 Read()
第一次读第一个第二次读第二会自动读取下一个,超过长度会依旧循环只是读取不到返回-1
(不像迭代器,先判断)是个死循环!
怎么解决死循环?加入判断,在不考虑知道文件长度通过length()方法,记得关闭流!
5.2.2read(byte[] b)
参数是表示返回到byte数组
但是此方法每次读10个最后一次,自己补了4个qrst
为什么?
每一次读取,放在同一个数组里,相当于读取之后复制过去,而最后一次只有4个,也就只复制了前6个!
例如:有时候下载文件都会大一些,就是因为每一次读取不有关注实际读取的量有一小丢丢是旧数据
怎么办?
返回值是int,表示读取的数量(大小) -1表示读完了、
6. 字符输出writer-------(OutputStream字节输出)
由于字节读取文字,是拼接的存在读取一半的情况
所有需要字符流
本质上也是字节流,只是把他封装了,不会出现一半的情况
只用于操作文字
6.1构造方法:
protected | Writer() | 创建一个新的字符流编写器,其关键部分将在编写器本身上同步。 |
protected | Writer(Object lock) | 创建一个新的字符流编写器,其关键部分将在给定对象上同步。 |
6.2方法:
void | write(char[] cbuf) | 写一个字符数组。 |
abstract void | write(char[] cbuf, int off, int len) | 写一个字符数组的一部分。 |
void | write(int c) | 写一个字符。 |
void | write(String str) | 写一个字符串。 |
void | write(String str, int off, int len) | 写一个字符串的一部分。 |
7.Filewriter-------(字节输出FileOutputStream)
构造方法:
FileWriter(File file, boolean append) | 在给出要写入的 FileWriter下构造 File ,并使用平台的 default charset构造一个布尔值,指示是否附加写入的数据。 |
上面提到的append都是参数
Append()方法----追加一段文字(运行2次,不是基于源文件的内容追加)
方法的调用会返回调用方法的对象
强转,返回的是其父类writer
true
所以:
追加的原因也在,对象继续调用方法
8.字符流Reader读取输入)-----inputStream(字节流)
8.1构造方法:
protected | Reader() | 创建一个新的字符流阅读器,其关键部分将在阅读器本身上同步。 |
protected | Reader(Object lock) | 创建一个新的字符流阅读器,其关键部分将在给定对象上同步。 |
8.2方法:
abstract void | close() | 关闭流并释放与其关联的所有系统资源。 |
int | read() | 读一个字符。 |
int | read(char[] cbuf) | 将字符读入数组。 |
Int -1 表示尾部没有内容了,否则则是数据大小长度
9.FileReader字符输入--------------FileInputStram(字节输入)
Reader的子类filereader
可以通过循环输出读取完所有文字
读取数组
10. Flush刷新管道
字节不需要!
字符输出时以字符为单位输出(由字节包装),如果是半个字符就缓存起来,
从内存到硬盘有一个缓存(从流入in到流出out)
字符输出会加flush()强制把缓存的内容输出.
缓存:UTF-8编码下的中文并非两个字节,是三个字节计算机是以字节储存,字符输出要读满一个文字的3个字节,在输出。不同的编码所占字节不一样。不满3个字节,会缓存起来。
在关闭时会自己调用一次刷新即cloes()方法
11.转换流InputStreamReader和OutputStreanmReader
字节流‘装饰’为字符流:使用了装饰者设计模式。
11.1InputStreamReader(读取):字节输入转字符输入
构造方法:
参数1:1参:需要转换的字节流
参数2:两参:指定编码名称
11.2 OutputStreanmReader:字节输出转字符输出
字节输出转字符输出写出
12. Print与BufferedReader
12.1Print字符打印流
向指定文件输出
12.2字节流也可以转换为打印
以后往某个位置输出字符,建议转为打印流
12.3BufferedReader缓存读取流
在网上读取文本,
1把字节转成字符流在去读取,
2也可以创建字符流去读取
3缓冲读取流:将字符输入流转换为带有缓冲可以一次读取一行的缓冲字符读取流。只能用于字符流,字节流不可以!
本来是一个一个字符读取,通过缓存字符流,有个缓存,一行一行的读取
ReadLin()
多了一个读取一行的字符串方法,返回读取到的内容,null表示没有内容
之前只有一次读一个字符,或者读一个Byte数组,返回数组长度,-1表示没有内容
13.收集异常日志
打印字符流,没有append(参数里没有true)-----程序停止在启动会清空
14.Properties文件类
在把程序的内存保存到文件时,格式很难把控,所以会用到Properties类
后续还会有:XML,JSON
也属于Map集合体系下的内容
自己做了扩展。与IO有关
因为属于Map集合存储格式也是一对键值!
所以可以当做集合使用,不过是文件其添加与删除查找与Map集合方法一样。
用来与流建立关系。
文件里每一行都是一个建值对,
Load(一参)
传入一个字符流或字节流,输入
把properties文件内容加载成程序中的Map集合
Store(两参)
把Map集合变成properties文件并按照其格式进行存储
参数:properties文件集合,String表注释
1.创建了一个properties对象,其存储格式以Map集合一样一对键值对
2创建了字符输出流
格式:
#表示注释,参数里的String
存储的是以键=值的形式
因为Java使用Unicode表不允许使用中文
包括键值对也不建议是中文
为什么?
Properties继承自Hashtable ,所以put和putAll方法可以应用于Properties对象。 强烈建议不要使用它们,因为它们允许调用者插入其键或值不是Strings 。 应该使用setProperty方法。 如果在包含非String键或值的“受损” Properties对象上调用store或save方法,则调用将失败。 同样,如果在包含非String密钥的“受损” Properties对象上调用,则对propertyNames或list方法的调用将失败。
15.序列化和反序列化技术:
序列化:简单来说,就是把对象写入文件
反序列化:把对象从文件中读取到程序
------
在内存里创建对象,对象被垃圾回收就没了,就算是静态的程序关闭也就没了。
那能不能把对象存在文件里面,下次运行把对象拿过来?
序列化:就是把程序中的对象,以文件的形式存储。按照对象在内存中的字节序列存储的,是一堆乱码。指把Java对象转换为字节序列的过程。
反序列化:把对象从文件中读取回来是反序列化,指把字节序列恢复为Java对象的过
程。
通过序列化和反序列化实现网络传输、本地存储的目的。
场景:
安卓手机直接给服务器发一个对象,服务器拿过去就能使用。
服务器与服务器之间用对象交流会更方便。--分布式
但是在未来可能会被官方取消,因为从出现到现在官方收到了很多关于它的bug,准备不在使用。
----------------
如何使用?
15.1 ObjectOutputStream和ObjectInputStream
ObjectOutputStream序列化(输出)
这样会出bug
BOOK不能序列化异常,为什么?
官方有时候不想让所有的类进行序列化,就决定所有的类都不能被序列化。想要它能序列化,就加一个标记实现一个接口 SeriaLizable
15.2SeriaLizable(序列化接口--标记)
标记接口,没有提供任何抽象方法
序列化之后对象在文件中存储
反序列化:
在读取文件中的对象时,如果程序不存在或不匹配,读取这的个类是会抛出异常的,
readObject()读取后会返回一个Object对象
抛出的异常
完整:
同时接收的Object对象可以强转为book,得到Book对应的一个属性
注意:
1:Book里可能也有其他类
Book里包含了没有实现Serializable接口的Person,同样会报错,book和其属性都要实现这个接口。
2:如果文件存的不是一个对象,而是一个对象的集合,读取的也是集合。
16. Try-with-resources
这里的关闭不合理。为什么?
在输出前语句前的2行代码出现异常直接跳到了catch,并没有走close()
会想到finally,但是finally不能访问try语句块里创建的对象
可能会写成这样:但是很麻烦
-----------------------------------------------------------------------------------------------------------------------------
JDK1.7
可以在try(创建对象){}catch{},finally里的内容就会自动执行,自己会关闭流
Try()的括号里创建对象的类需要实现两个接口
里面有抽象方法,在执行时自动调用其实现类重写方法
但还是有不合理,如果这个new 的字符读取流对象是参数,是没办法关闭
JDK9进行了优化
补:SeriaLizable ID(序列化接口ID--标记)
在标记的实体类,如果序列化的A版本只有3个属性。
在系统升级为B版本时,需要添加新的属性此时直接添加是反序列化不出来的,系统不能运行,或者反序列化失败。
没有定义SerializableID或者SerializableID不一样了都会导致这个问题
怎么解决?
SeriaLizable ID
主要是让你这个对象有唯一的标识!就是说序列化和反序列话后要保持版本一致
15.3 部分属性的序列化和反序列化:
4种方式:
15.3.1.transient修饰词不参与序列化,在序列化的过程中
15.3.2.反序列化后,类中static型变量的值为当前JVM中对应static变量的值,这个值是JVM中的不是反序列化得出的
在序列化完成后修改static变量,反序列化出来的值是取的JVM的更改后的static变量。
所以static 修饰的变量,是不参与序列化的
15.3.3.writerObject和readObject两方法,实现Serializble类里
这两个方法,如果写了,在序列化和反序列化是自己会调用。需要序列化的就写在里面
15.3.4Externalizable实现序列化:
通过实现Eexternalizable接口。
Externalizable继承自Serializable,使用Externalizable接口需要实现readExternal方法和
writeExternal方法来实现序列化和反序列化
实现接口:
方法重写
16. Serializable VS Externalizable
Externalizable必须重写其抽象方法,并且实现Externalizable接口
而writerObject和readObject实现Sernalizable接口,不一定要重写方法。
---------------------------------------------------------------------------------------------------------------------------------
得多敲敲Demo才能记住。
Go for it