1. file类的使用
1) 概述
在现实中
1. 目录(directory): 目录指的是文件夹,用来存放文件。
2. 文件(File): 文件,用来保存一些数据。
3. 路径(Path):指的是计算机的一个位置,可以是文件的位置,也可以是文件夹的位置。
在java中
1. 有一个类,可以表示计算机中的文件和文件夹,这个类叫File类。
2. 虽然File的本义是文件,但是在java中,File类既可以表示文件,也可以表示文件夹。
3. 也就是说,我们可以调用File类的一些方法,来完成对文件或者是对文件夹的操作。
4. java.io.File类是文件和文件夹路径名的抽象表示,所指向的路径对应的文件或者文件夹不一定真实存在。
2) 构造方法
1. file(String pathName)
参数是一个路径名称,这个路径名称可以是文件,也可以是文件夹。
2. file(String parent,String child)
参数是2个路径(父路径+子路径),根据父路径和子路径组合构造成一个File对象。父路径和自路径都是字符串。
比如:
现在有一个文件路径为: D:\it\aa\bb\cc\dd.txt
那么: 对应的父路径 parent : D:\it\aa\bb\cc
对应的子路径 child : dd.txt
3. File(File parent,String child)
根据父路径和子路径组合构造一个File对象 。
父路径是 File 类型,子路径是 String 类型。
因为父路径是File类型,所以等于是先用构造方法构造一个父路径,再去拼接一个子路径,因为还有子路径,所以这样构造的父路径一般是文件夹,而不是文件。
注意点:
使用构造方法可以创建出一个File对象,这个File对象表示的是计算机中的一个文件或者文件夹,
并且表示的这个文件或者文件夹,可以在计算机中是实际存在的,也可以是不存在的。
3) 相对路径和绝对路径
1. 相对路径
一个不是特别详细的路径,没有从盘符开始。
没有从盘符开始的路径就是: 相对路径,在idea中,相对路径相对的是当前项目。
2. 绝对路径
是一个非常详细的路径,绝对路径都是从盘符开始的。
从盘符开始书写的路径就是绝对路径。
4)File类的获取方法
1. String getAbsolutePath()
获取此file对象表示的绝对路径(从盘符开始)。
如果创建的时候使用的是相对路径,那么创建时的相对路径表示的是该项目下的相对路径。
获取到的还是从盘符开始的绝对路径。
2. String getPath()
获取此file对象表示的路径。
在创建file对象的时候给的是什么,获取到的就是什么。
如果创建file对象的时候,使用的是相对路径,那么获取到的就是相对路径。
如果创建file对象的时候,使用的是绝对路径,那么获取到的就是绝对路径。
3. String getName()
获取此file对象表示的文件或者是文件夹的名字。
这个方法不在乎这个文件或者文件夹是否真实存在,只要给一个路径,就能获取到对应的名称。
其本质是截取的最后一个分隔符(\) 后的内容返回。
4. Long lenth()
获取此File对象表示的文件的字节数大小。
只能准确的获取文件的字节数大小,如果是文件夹,获取的是一个不固定的值(没法准确获取).
如果要获取的File对象表示的文件不存在,那么结果为 0 。
5)File类的判断方法
1. Boolean exists()
判断此file对象表示的文件或者文件夹是否真实存在。
2. Boolean isDirectory()
判断此file对象表示的 是否是一个真实存在的文件夹。
如果这个File对象表示的 确实是一个文件夹,并且真实存在,那么返回true,
如果不是文件夹或者是文件夹,但是不存在,返回的都是false。
3. Boolean isFile()
判断此File对象表示的是否是一个真实存在的文件。
如果这个File对象表示的是一个真实存在的文件,那么返回true,
如果不是文件或者是文件但不是真实存在的,那么返回的都是false。
6)File类的创建方法
1. Boolean createNewFile()
创建一个文件,如果文件已经存在,那么创建失败。
如果创建文件时,对应的上级目录不存在,那么会报异常。
eg:
File file = new File(“D:\\test\\aa.txt“);
file.creatNewFile() ; //true
2. Boolean mkdir()
创建一个文件夹,如果文件夹已经存在,那么创建失败。
如果创建文件夹时上级目录不存在,那么会创建失败 ,但是不会报错。
3. Boolean mkdirs()
创建一个文件夹,如果文件夹已经存在,那么创建失败。
如果创建文件夹时上级目录不存在,那么会先自动创建上级目录,再创建指定文件目录。
eg: File file = new File(“D:\\test\\aa\bb\cc”);
file.mkdirs() ; //true
注: mkdir()只能创建单级目录,mkdirs()可以创建多级目录,使用的时候一般用mkdirs()比较多,用mkdir()较少。
7)File类的删除方法
1. Boolean delete ()
删除一个文件或者是文件夹。
注意点:
a. 如果delete删除的是一个文件夹,那么这个文件夹必须是空文件夹,否则删除失败,不能删除。
b. 调用delete()方法删除时,不会走回收站,而是直接彻底删除,所以需要特别注意,小心误删。
8)File类的遍历方法
1. String[ ] list()
获取指定目录下的所有文件和文件夹,返回字符串数组。
数组里面放的是所有文件和文件夹的名字(跟getName()方法获取的一样)。
2. File[ ] listFiles()
获取指定目录下的文件和文件夹,返回的是File数组。
可以直接对File数组进行其他操作。
3. File[ ] listFiles(FileFilter fileFilter)
传递一个文件过滤器接口的子类实现,可以按照指定的规则对文件进行过滤,返回符合要求的文件或者文件夹。
注意点:
1. 如果File对象表示的是一个文件,而不是文件夹,那么调用listFiles()方法,得到的是 null,如果遍历,会报空指针异常 。
2. 如果File对象表示的是一个空的文件夹,那么调用listFiles()方法,得到的是一个空的数组{ },遍历时没有内容,但不会报错。
4. static File[ ] listRoots()
列举出操作系统的根目录。
9)File类的递归方法
1. 概念
递归指的是: 方法直接或者间接的调用方法本身。
2. 包括的内容
直接递归: A-->A
间接递归: A-->B B-->C C-->A
3. 可能产生的问题
内存溢出:内存不够用的情况。
内存泄漏:有些对象虽然没有用了,但是却不能够被回收,这种现象就是内存泄漏。 内存泄漏会导致内存溢出。
4. 递归注意点
a. 递归要有结束的条件
b. 因为递归比较占用栈内存,所以递归的循环次数不能太多,否则会造成栈内存溢出。
10)文件过滤器
1. 定义
文件过滤器接口,涉及的类为: java.io.FileFilter 。
2. 可以作为listFiles()方法的 传入参数。
3. 接口中有且只有一个抽象方法 : boolean accept (File file ) 。
4. 重写抽象方法,确定文件保留的原则,比如: 要么是.java文件,要么是文件夹再次遍历。
5. 本质:就是一个文件过滤器 ,可以过滤不符合要求的文件,而只留下符合要求的文件。
eg:
File dir = new File("D:\\qqq");
public static void printDir2(File dir){
File[ ] fileList = dir.listFiles(new FileFilter(){
@Override
public Boolean accept(File file){
return file.getName().endWith(".java")|| file.isDirectory();
}
})
也可以用lambada表达式
File[] fileList = dir.listFiles(file ->
file.getName().endsWith(".java") || file.isDirectory()
);
//循环打印
for(File file fileList){
if(file.isFile(){
sout("这是个文件,文件名称:" +file.getAbsolutePath())
})else{
//递归文件夹,重新便利
printDir2(file);
}
}
2. IO流
1) 概述
1. 计算机中一般用来存储的设备有2个: 内存和硬盘。
内存: 用来运行程序, 所有的程序都是在内存中运行的,也可以临时存储数据,但是当程序关闭后,保存的数据会丢失。
硬盘:用于持久化的存储数据。 只要不删除,一直存在。
2. IO流
I:input ,输入,读取, 将数据从其他设备(硬盘)读取到内存中。
O:output, 输出,写出,将内存中的数据写出到硬盘或其他设备中。
流: 数据传输的通道,可以传输数据。
注: IO流的输入和输出都是依照内存为参照物进行的。
输入是读取到内存中,输出是从内存中写出到外面。
作用: IO流主要用来传输数据,像:文件拷贝,上传,下载 等等。
图示:

2)字节与字符
字节:
计算机存储的基本单位,8位二进制(0~255)
主要处理二进制数据(文件,网络传输)
直接操作原始数据
字符:
人类可读的文本单位(如:字母,数字,符号)
主要处理文本数据(字符串,文档内容)
需要编码/转码 转换成字节。
字节与字符可以相互转化,但是需要一定的转化规则。
字节---> 字符: 需要指定字符编码(如 UTF-8, GBK)进行解码。
解码:将存储在计算机中的二进制数按照某种规则解析显示出来。
字符---> 字节: 通过编码规则转换为字节序列。
编码:按照某种规则,将字符以二进制的形式存储到计算机中。
常见的编码规则:
ASCII:1 字节表示 1 字符(英文字符)。
UTF-8:变长编码(1~4 字节),兼容 ASCII。
GBK:中文编码,1~2 字节。
注意:
在计算机中,一切文件数据(文本,图片,视频等)在存储时,都是以二进制数字的形式保存的,都是一个一个的字节,数据传输的时候也是这样。
也就是说最基本的结构都是通过字节构成的,只不过是因为通过不同的方式(不同的解码规则)打开,才展示出我们想让它展示的效果。
3) IO流顶层分类
1. 从流向上分:
输入流:
字节输入流 InputStream
字符输入流 Reader
输出流
字节输出流 OutputStream
字符输出流 Writer
2. 从数据类型上分
字节流
字节输入流 InputStream
字节输出流 OutputStream
字符流
字符输入流 Reader
字符输出流 Writer
注意:
这4个顶层父类都是抽象类,实际上一般使用的是他们的子实现类。
4) 字节输入流
1. 概述
a. InputStream是字节输入流,主要是将硬盘中的文件写入到内存中。可以将文件中的内容写入到java程序中 。
b. InputStream是所有字节输入流的顶层父类,并且是一个抽象类,我们需要用它的子类才可以。一般用的比较多的是它的一个子实现类:FileInputPutStream 。
2. FileInputPutStream
1) 构造方法
FileInputPutStream (File file ) : 参数需要传递一个File类型的文件,表示从这个文件中读取数据到内存。
FileInputStream (String name) : 参数需要传递一个String类型的文件路径,表示从这个文件路径中读取数据到内存。
2) 读取方法
int read( ) : 从该文件中读取一个字节(只能是1个字节)到内存,并且返回读取到的字节。如果读取结束,返回-1 。
int read(byte [ ] bArr) : 从该文件中读取数据到指定的字节数组中。
返回的是读取到的有效的字节个数,如果读取结束,返回-1。
int read ( byte [ ] bArr, int off, int length) : 从文件中读取数据到指定的字节
数组,返回的是读取到的有效的字节个数,如果读取结束,返回-1。
注意:
byte [ ] bArr : 字节数组。
off : 从哪个位置开始读取。
length: 每次读取的字节个数。
3) 关闭资源的方法
void close( ) ; 关闭流,释放资源。
4) 使用实例
a. 创建一个字节输入流 FileInputStream,绑定一个获取文件数据的数据源。
InputStream in = new FileInputStream(“aa.txt”);// 文件内容:abcde
//相对路径,表示的是本项目下的地址,如果绑定的数据源不存在,那么会抛出 FIleNotFoundException 。
注意: 这一步骤做了2件事情
1. 创建一个字节输入流对象。
2. 将要绑定的数据源(aa.txt)绑定到这个字节输入流(in)上,以后通过这个字节输入流操作的就是这个绑定的数据源文件的内容,如果数据源不存在,会抛出异常。
b. 读取数据【read()方法一次读取一个字节,read(byte[ ] byteArr) 方法一次读取一个字节数组】
int i = in.read(); //一次读取一个字节,当没有读取结束时,返回的是读取到的内容,当读取结束时,返回的是 -1 。
byte[ ] byteArr = new byte[1024] ;
int length = in.read(byteArr) ; //
c. 判断是否读完
While((len= in.read(byteArr) ) != -1){
// 说明还没有读完,可以对数组中的数据进行操作
}
注意: 该条件判断做了如下事情:
1. 调用了输入流的read()方法,将数据读取到byteArr数组中。
2. 返回了读取到的有效个数,并且将这个有效个数的值赋值给len。
3. 判断len是否不等于-1,如果不等于-1,表示读取到了内容,那么就在循环中对数据进行处理,读取到的数据在byteArr数组中存储着。
4. 如果len等于-1,表示数据已经读取结束。
5. 这里不能直接读取或者打印byteArray[ ]数组的内容,因为可能会有上次读取的残留。需要使用:Syste.out.println(new String(byteArr,0,len)) ;
d. 关闭资源
5)注意点
a. 采用字节数组的方式比采用单字节的方式要快很多,一般用的字节数组的大小是 1024的整数倍,最快的是1024的8倍。
b. 通过字节输入流读取数据,如果采取一次读取一个字节数组的方式进行读取,那么会将数据读取到参数byteArr数组中,
参数byteArr数组的长度是几,那么就一次读取几个字节。如果读取的是UTF-8的文件,而一次读取字节数组的长度又不是3的倍数,
那么还是会出现把中文拆开的情况,导致错误。哪怕长度是3的倍数,但是读取的文字中如果既有中文,又有字符,还是会出现错误。
所以不能用字节流来读取/写出 文本数据。
5) 字节输出流
1. 概述
a. OutPutStream是字节输出流,主要是将内存中的文件写出到硬盘中。可以将java程序中的数据写到文件中。
b. OurPutStream是所有字节输出流的顶层父类,并且是一个抽象类,我们需要用它的子类才可以。一般用的比较多的是它的一个子实现类: FileOutPutStream 。
2. FileOutPutStream
1) 构造方法
FileOutPutStream(File file ) 参数需要传递一个File类型的文件,表示向这个文件中写出数据。
FileOutPutStream(String name) 参数需要传递一个String类型的文件路径,表示向这个文件路径中写出数据。
FileOutPutStream(File file,Boolean append )
File file : 需要进行写出的文件
Boolean append :是否进行追加写
FileOutPutStream(String name,Boolean append )
String name : 一个String类型的文件路径,表示向这个文件路径中写出数据。
Boolean append : 是否进行追加写。
注意:
如果FileOutPutStream没有加第二个参数true,那么后面执行的会覆盖前面执行的,每次都会新创建一个文件,再把内容写入,
如果加了true,那么不会新创建文件,而是在原文件的基础上追加写入。
2) 写出的方法
void write( int b) : 将指定的字节写出到文件中。每次只能写出一个字节!
void write(byte [ ] bArr) : 将指定的字节数组写出到文件中。
void write( byte [ ] bArr, int off, int length) : 将指定字节数组的一部分字节写出到文件中。
byte[ ] bArr: 指定的字节数组
off : 从哪个位置开始写出。
length: 写出几个字节。
3) 关闭资源的方法
void close( ) ; 关闭流,释放资源。
void flush() ; 刷新该输出流,并强制任何缓冲的输出字节被写出,不是强制使用。
4) 使用实例
a. 创建一个输出流FileOutPutStream,参数传递一个写出的文件路径。
OutPutStream os = new FileOutPutStream(“D:\\aa\\bb.txt”);
注意:这一步骤做了3件事情:
1. 调用系统资源,在D盘的aa文件夹下创建文件bb.txt,如果这个文件已经存在,那么会新建一个新文件,覆盖之前的文件。
2. 创建一个字节输出流对象。
3. 将创建的文件(bb.txt)绑定到这个字节输出流(os)上,以后通过这个字节输出流操作的就是这个文件的内容。
b. 向路径中写出数据。
write(int b)
注意:
1. 使用write(int b) 方法,每次只能写出一个字节,如果超过一个字节,写出时会进行截取,导致写出时有问题。
2. 数字可以安全写出: 如果传入的是一个数字,那么会先将这个数字转换成ASCII码上对应的字符,再将字符写出。
3. 字符也可也安全写出:在java中,一个字符是占两个字节,但是如果这个字符是ASCII码表上的字符,那么这个字符在操作系统中是占用一个字节的,所以这个字符用一次写一个字节的方式也是可以安全写出的。
4. 中文不可以安全写出,会有问题:中文在操作操作系统中是大于一个字节的(如果采用的是GBK,那么占用两个字节,如果采用的是UTF-8,那么占用3个字节),所以如果用一次写一个字节的方式来写出中文,那么会造成字节溢出,产生问题。
write(byte [ ] bArr)
write( byte [ ] bArr, int off, int length)
注意:
1. 也可以使用字节数组的方式进行写出。
2. 字节数组和字符串可以进行相互转化,
字节数组---> 字符串(直接构造方法)
String (byte[ ] bytes) : 将整个字节数组转换成String .
String (byte[ ] bytes, int offset, int length ):将指定字节数组的一部分转换成字符串。
参数: bytes : 要转换的byte数组
offset : 从哪个位置开始转换(索引位置)
length: 转换几个字节
例: String ss2 = new String(byteArr,1,2) ; byteArr:abcde
System.out.println(“ss2”) ; // bc
字符串----> 字节数组
byte[ ] getBytes( ); 使用平台默认的编码格式(开发环境),将字符串转换成字节数组。
byte[ ] getBytes(String s ) ; 使用指定的编码格式,将字符串转换成字节数组。
例:
String s2 = “中国” ;
byte [ ] byteArr2 = s2.getBytes();
System.out.println(Ayyays.toString(byteArr2)) ; // [-28,-72,-83,-27,-101,-67]
3. 因为一个中文占用3个字节,那么很可能因为开始的位置不是中文的第一个字节位置,或者length不是3的倍数,而导致写出文本失败。
c. 续写/换行写
续写: 使用带有 append 参数的多参数构造。
FileOutPutStream(File file,Boolean append )
FileOutPutStream(String name,Boolean append )
换行写:
windows : \r\n
linux : \n
macOs : \r
eg:
OutPutStream os1 = new FileOutPutStream(“aa.txt”);
os1.write(“床前明月光\r\n ”.getBytes());
d. 关闭流
os.close() ;
6) 字符输入流
1. 概述:
a .字符输入流的顶层父类是 Reader,可以将文件中的数据读取到程序中,Reader也是一个抽象类,一般用的是它的子类: FileReader 。主要用来读取文本文件。
2. FileReader
1) 构造方法
FileReader(File file) : 传递一个File类型的文件,作为用来获取数据的数据源。
FileReader(String name ) : 传递一个String类型的文件路径,作为获取数据的数据源。
2) 读取数据的方法
int read() ; 一次读取一个字符,并返回读取到的字符,如果读取结束,返回-1。不管是中文还是字母还是数字,都是一个字符。
int read(char[ ] charArr); 一次读取一个字符数组,返回的是读取到的字符数组的长度,如果读取结束,返回-1。
3) 关闭资源的方法
void close( ) ; 关闭流,释放资源。
7) 字符输出流
1. 概述:
a . 字符输出流的顶层父类是 Writer, 可以将内存(程序)中的数据写出到文件中。Writer是一个抽象类,一般用的是它的子类 FileRwiter 。
2. 2) FileWriter
1) 构造方法
FileWriter(File file) : 传递一个File类型的文件,表示向这个File文件中写出数据。
FileReader(String name ) : 传递一个String类型的文件路径,表示向这个文件路径中写出数据。
FileWriter(File file ,Boolean append) : 向file文件中追加写出数据。
File file :表示向这个File文件中写出数据 。
Boolean append : 是否追加写出数据,true表示追加写。
FileWriter(String name,Boolean append) :向给出的文件路径中追加写数据。
String name :String类型的文件路径,表示向这个文件路径中写出数据。
Boolean append : 是否追加写出数据,true表示追加写。
2) 写出数据的方法
void write(int c) : 向指定文件中写出一个字符。
void write(char[ ] charArr) : 向指定文件中写出一个字符数组。
void write(char[ ] charArr, int off , int len) : 向指定文件中写出一个字符数组的一部分内容。
char[ ] charArr : 指定的字符数组。
int off: 开始写出的位置(索引位置)
int len: 写出的长度(多少个字符)
void write(String str) : 向指定文件中写出一个字符串内容。
void write(String str, int off , int len) : 向指定文件中写出一个字符串内容的一部分。
String str: 指定的字符串。
int off: 字符串开始写出的位置(索引位置)
int len: 写出的长度(多少个字符)
3) 资源处理相关的方法
void flush() : 刷新,仅仅是刷新操作,而且刷新后还可以向文件中再写出数据。
void close( ) ; 先刷新,再关闭,关闭之后不能再向文件中再写出数据,否则会直接报错。
4)注意点
a. 调用write()方法只是把数据写出到了内存缓冲区中,并没有放入到文件中,要想把写出的内容放到文件中,必须要进行fluch()刷新操作才可以。
b. 仅仅字符输出流写完数据后要刷新,其他流不需要该操作。
8) 字节流和字符流的区别
字节流:
1. 以单个字节为处理单位,每次读取或者写入一个字节(或者字节数组)。
2. 不能操作中文,更适合处理二进制文件,如:图片、视频、音乐等。
3. 不进行任何编码转换,读入的是原始字节,写出的是原样字节。如果用字节流读文本文件,容易出现乱码。
4. 本身没有内置缓冲区,但是可以通过BufferedInputStream 装饰。一般调用read会直接请求系统。
字符流:
1. 以2个字节的Unicode字符为处理单位,每次读取或者写入一个字符(或者字符数组)。
2. 适合处理文本文件(用记事本打开能看懂的文件就是文本文件),比如:.txt、.java、.xml、.json等。
3. 内部使用字符集编码器/ 解码器,读到几个字节,先去查找编码表,再将查到的字符返回。
总结:
如果操作文本文件,就用字符流,如果操作的是非文本文件,就用字节流。
9) IO流的异常处理操作
1. JDK1.7之前,需要手动try...catch...finally ,然后在finally中手动关闭流。
2. JDK1.7及以后处理方式:直接将要创建的流 放到 try 代码块中。
代码:
try( 创建流对象1 ;创建流对象2 ){
//操作流的代码
} catch (IOException e){
e.printStackTrace();
} ------这种格式称为: try…with…resource
注: 小括号内也可以创建多个对象,多个对象之间用分号隔开。
这种方式不需要我们自己去调用close()方法关闭流,系统会自动调用方法帮我们关闭流,而且不管程序有没有异常,都可以关闭流。
原因: try后面小括号中创建的对象,必须实现AutoCloseable接口。这个接口中有重写的close()方法,不管有没有异常,这个方法都会执行,作用就是关闭流或者关闭其他资源,相当于try…catch的语法糖。
3. 如果要释放处理try外面的流资源,
jdk1.7以及之前需要将外面的流赋值给新的流
FileWriter fw = new FileRwiter("file1.txt");
try(FileWriter fw2 = fw){
fw2.write("你好")
}catch(IOException e){
}
jdk1.9以及之后,直接将流放到try后面
try(fw2){
fw2.write("你好")
}catch(IOException e){
}
10) IO流总结

11) IO流分类
1. BIO: 同步阻塞IO,线程在执行IO操作的时候会阻塞等待,不能做其他事情。
2. NIO(用的较多): 同步非阻塞IO,线程在执行IO操作的时候,会去干别的事情。并且会实时的去看IO操作有没有结束,如果结束了就会回来继续io后的操作。
3. AIO: 异步非阻塞IO ,找别人帮我完成一些事情。
3. 缓冲流
1)分类
字节缓冲流
字节输入缓冲流: BufferedInputStream
字节输出缓冲流: BufferedOutputStream
字符缓冲流
字符输入缓冲流: BufferedReader
字符输出缓冲流: BufferedRwiter
2)特点
a. 缓冲流的特点就是:快。可以提高读写的速率;
b. 缓冲流本身并不具备读或者写的功能,它的作用只是给其他流提供加速。
缓冲流效率高的原因是因为: 它的内部有一个缓冲区,缓冲区的大小是1024*8;
3)使用步骤
1. 创建缓冲流对象;
2. 调用方法进行读或者写操作;
3. 关闭流。
4)字节输入缓冲流
构造方法:
BufferedInputStream(InputStream in ) : 将一个普通的字节输入流作为入参,转换为字节输入缓冲流,默认字节数组大小为1024*8 ;
BuffredInputStream(InputStream in, int size ) : 将一个普通的字节输入流和一个字节数组(缓冲区)大小作为入参,转换为字节输入缓冲流。
5)字节输出缓冲流
构造方法:
BufferedOutputStream(OutputStream out) : 将一个普通的字节输出流作为入参,转换为字节输出缓冲流,默认字节数组大小为1024*8 ;
BufferedOutputStream (OutputStream out, int size ) : 将一个普通的字节输出流和一个字节数组(缓冲区)大小作为入参,转换为字节输出缓冲流。
示例:

6)字符输入缓冲流
BufferedReader(Reader in) : 将一个普通的字符输入流作为入参,转换为字符输入缓冲流,默认字符数组大小为1024*8 ;
BufferedReader (Reader in, int size ) : 将一个普通的字符输入流和一个字符数组(缓冲区)大小作为入参,转换为字符输入缓冲流。
7)字符输出缓冲流
BufferedWriter(Writer out) : 将一个普通的字符输出流作为入参,转换为字符输出缓冲流,默认字符数组大小为1024*8 ;
BufferedWriter (Writer out, int size ) : 将一个普通的字符输出流和一个字符数组(缓冲区)大小作为入参,转换为字符输出缓冲流。
示例:

8) 字符缓冲流的特殊方法
字符输入缓冲流:
BufferReader中有一个方法,可以一次读取一行数据。
String readLine() ; 读取一行数据并返回,读取结束时,返回 null 。
注意:readLine()方法不会读取换行符,需要自己手动换行(println)。
字符输出缓冲流:
BufferWriter有一个方法,可以实现跨平台换行。
void newline() : 实现一个跨平台的换行。
示例:

4. 转换流
1)编码表
1. 计算机中存储的数据都是二进制的,但是我们在屏幕上看到的文字却是各式各样,这些都是二进制转换过后的结果。
编码:按照某种规则,将字符以二进制的形式存储到计算机中,称为编码;
解码:将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码。
2. 字符编码:指的是自然语言的字符和二进制数之间的对应规则。
3. 字符集: 又叫做编码表。
是一个系统支持的所有字符的集合,包括各个国家的文字,标点符号,图形符号,汉字等。
编码表指的是计算机中的字节和我们看到的字符的对应关系表。
4. 在windows操作系统中,默认的是gbk编码,在 gbk 编码中, 一个中文占用两个字节。
在idea中,默认的是utf-8编码,在utf-8 编码中,一个中文占用3个字节。

2)转换流的作用
在windows系统中,文本文件默认使用的是 gbk编码,一个中文占用两个字节。
但是在java程序(idea)中,文本文件默认使用的是utf-8编码,一个中文占用3个字节。
那么当用idea 读取windows系统下的文本文件时,就会因为中文占用的字节数不同而导致乱码。
这时候就需要用到转换流,来指定统一的编码格式。
3) InputStreamReader
1. 介绍
InputStreamReader 是将(硬盘中的)文件读取到java程序中。
在文件中,所有的数据都是以字节的形式保存,读取到java后,以字符的形式展示。
所以 InputStreamReader是字节到字符的桥梁。
InputStreamReader的本质:先查询码表,再进行转换。
2. 构造方法
InputStreamReader (InputStream in ): 传递一个字节输入流。
InputStreamReader (InputStream in ,String charName)
InputStream in : 传递一个字节输入流
String charName:一个字符串类型的编码格式,表示要通过这种编码格式进行读取。
3. 使用
a. 创建流。
b. 读取。
c. 释放资源。
4. 示例
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("file.txt"), "StandardCharsets.UTF_8)"));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
4) OutputStreamWriter
1. 介绍
OutputStreamWriter其实就是将内存中的数据写出到硬盘中。
OutputStreamWriter可以指定编码格式,来向硬盘中写出数据。
2. 构造方法
OutputStreamWriter(OutputStream out ): 传递一个字节输出流,会按照idea默认的编码格式向文件中写出数据。
OutputStreamWriter(OutputStream out ,String charsetName):
OutputStream out : 传递一个字节输出流
String charsetName: 设置一个编码格式,使数据按照指定的编码格式向文件中写出数据。
3. 使用步骤
a. 创建流。
b. 写出。
c. 释放资源。
4. 具体示例
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("file.txt"), "StandardCharsets.UTF_8)"));
bw.write("1111");
bw.close();
}
5) 关系
InputStreamReader: 从文件中读取的是字节,在idea中看到的是字符;
OutputStreamWriter: 在idea中写出的是字符,保存到文件中的是字节。

5. 序列化流
1) 序列化流:ObjectOutputStream
1. 定义:
ObjectOutputStream: 是一个处理流(包装流),主要负责把java对象写出(序列化成字节序列)。写出的具体位置,是由它包装的底层输出流决定的,
FileOutputStream --》写出到硬盘
ByteArrayOutputStream --》写出到内存
Socket.getOutputStream()--》写出到网络
2. 构造方法
ObjectOutputStream (OutputStream out ) :传递一个字节输出流。
3. 写对象的方法
void writeObject(Object obj) : 向文件中写出一个对象。
4. 使用步骤
a. 创建一个序列化流。
b. 调用writeObject()方法,向文件中写对象。
c. 释放资源。
5. 示例:
public class test{
public static void main (String[ ] args){
ObjectOutputSream os = new ObjectOutputSream (new FileOutputStream("aa.txt"));
Person p = new Person("张三",18);
os.writeObject(p);
os.close();
}
}
6. 注意点
a. 只有实现Serializable接口的类的对象才能够被序列化。
b. Serializable接口中没有任何方法,它只是做一个标记,表示实现该接口的类的对象可以被序列化。
2) 反序列化流:ObjectInputStream
1. 定义:
ObjectInputStream: 将之前序列化写出的对象,重新反序列化,读入到内存(java程序)中。
2. 构造方法
ObjectInputStream(InputStream out ) :传递一个字节输入流。
3. 读取对象到内存(java程序)的方法
Object readObject() : 将之前序列化的对象进行反序列化,读入内存(java程序)中。
4. 使用步骤
a. 创建一个反序列化流。
b. 调用readObject()方法进行读取操作。
c. 释放资源。
5. 示例:
public class test{
public static void main (String[ ] args){
ObjectInputSream os = new ObjectInputSream (new FileInputStream("aa.txt"));
Object obj = os.readObject();
Person p =(Person) obj;
Sout(p.getName+p.getAge);
os.close();
}
}
6. 注意点
a. 要读取的文件必须是之前序列化生成的文件。
b. 如果读取的文件时候,这个类不存在,那么会抛出classNotFoundException异常。
c. 如果读取文件的时候,类存在,但是由于类发生了改变,版本号也发生改变,导致版本号不一致而无法反序列化时,会抛出InvalidClassException异常。
3) 序列化中的static
1. 被static修饰的成员变量不能被序列化。
2. 被static修饰的成员变量会变为静态变量,其值或者引用将不能被改变。
如果希望一个变量不被序列化,又不想用static修饰,那么可以用transient修饰,被transient修饰的成员变量不会改变其原来属性,而且不会被序列化。
4) 序列化版本问题
1. 当一个类的对象先进行序列化写出到文件中,然后对类进行了修改(不包括加空格,加注释等),再对之前序列化的文件进行反序列化读取时,就会因为类的修改,而导致这个类的版本号发生改变,序列化文件中类的版本号和现在类的版本号对应不上,而导致反序列化失败。
2. 解决方法: 给类分配一个固定的版本号,不管类是否进行修改,版本号都不会发生改变。
3. 给类分配固定版本号方法:
提供一个静态成员变量,这个静态成员变量的内容为:
private static final Long serialVersionUID = 1L; // 1 也可以是其他数,只要固定就可以。
5)什么是序列化
1.定义
序列化是一种用来处理对象流的机制,对象流就是将对象的内容进行流化,并可以对流化后的对象进行读写、传输于网络之间等操作。序列化是为了解决对对象流进行操作时引发的问题。
2. 实现
将需要被序列化的类实现Serializable接口。该接口没有需要实现的方法,只是起到一个标记作用。
6. 打印流
1) 特点
输出数据非冲方便,但是打印流只能输出数据,不能输入数据。
2) 分类
字节打印流:PrintStream ;
字符打印流:PrintWriter
3) 构造方法
PrintStream (File file ) :传递一个file类型的文件
PrintStream (String fileName) :传递一个字符串类型的文件路径
PrintStream (OutputStream out) : 传递一个字节输出流
4) 其他方法
Print() ; 输出不换行
Println(); 输出并换行
Write() ; 写出
5) 调用write()方法写出和调用print()方法写出的区别
调用write()写出数字时,会对照ASCII码表,转换成字符;
而调用print()方法不会对照码表,会直接输出数字。
6) 标准输出流
System.out.println() 里面的System.out 是一个打印流,也叫做标准输出流。
我们可以调用System的setOut(PrintlnStream out) 方法,来改变打印流的走向,使打印流不是打印到控制台,而是打印到指定的文件目录。
eg:
PrintStream() ps = new PrintStream("aa.txt");
System.setOut(ps); //打印到指定目录
7. Properties集合
1) 介绍
Properties是一个双列集合,里面是以键值对的形式存放数据的。
特点:
1. Properties实现了Map接口,拥有Map中的所有功能,并且是一个双列集合。
2. Properties键值对没有泛型,键和值都是String类型的。
3. Properties支持对流的操作,可以从流中加载键值对。(使用的主要原因)
2) 常用方法
1. Properties(); 无参构造
2. object setProperty(String key , String value) ; 向Properties集合中添加键值对。
3. String getProperty( String key) ; 根据key获取value值。
4. Set<String> stringPropertyNames(); 获取所有存放key的集合,相当于keySet。
5. void load(InputStream inputStream) ; 从字节流(文件)中加载键值对。
6. void load (Reader reader) ; 从字符流(文件)中加载键值对。
3)使用步骤
1. 创建一个Properties集合。
2. 创建一个输入流对象,绑定一个数据源文件,表示要从这个文件中读取数据。
3. 调用Properties集合的load()方法,传递刚才创建的输入流对象,就可以将输入流绑定的文件中的键值对加载到Properties对象中。
要读取的文件的要求:
1. 一般文件以.properties 结尾,这种后缀的文件是配置文件。
2. 文件的内容是键值对,而且必须按照以下方式存储
key = value
key = value
key = value
注: 1)不能有分号,如果有分号,会当做value值的一部分获取
2)value 如果是中文,用字节流读会产生乱码,需要指定解码规则。
如果使用的是idea,那么需要修改配置中的编码规则,修改步骤为:
File—settings--Editor--Code Style---File Encodinds------
项目编码:UTF-8 ; properties默认编码:ISO-8859-1 ; 勾选自动转换为UTF-8。
4)具体示例



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



