Java IO 的四个主要抽要基类
- 字节流的抽象基类
InputStream,OutputStream - 字符流的抽象基类
Reader,Writer
字符流
文件写 文件写的简单实例
在上个例子中,异常是直接抛的,这样显然不合适,IO异常的处理
如果使用
fw = new FileWriter("demo.txt");
则会覆盖原有的同名文件,如果想 续写 文件,就使用重载fw = new FileWriter("demo.txt",true);
文件读 的简单实例:
以上的方式效率都比较低,所以引入了 缓冲区:
BufferedWriter
和BufferedReader
。缓冲区对象没有空参数的构造函数。因为缓冲区的出现是为了提高流的操作效率而出现的。所以在创建缓冲区之前,必须要先有流对象。
练习:使用缓冲区复制文本文件
自定义MyBufferedReader 模拟缓冲区的实现过程
装饰设计模式:当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。那么自定义的该类称为装饰类。
装饰类通常会通过构造方法接收被装饰的对象。并基于被装饰的对象的功能,提供更强的功能。
前面提到的
BufferedReader
其实就是FileReader
的装饰。
字节流
InputStream
读
OutputStream
写
文件读写的简单例子 link1
自定义字节流缓冲区,演示缓冲区的工作原理(只需看懂就好,不需要自己写) link4
键盘录入
System.in; //标准输入,键盘(录入的是二进制数据) System.out; //标准输出,控制台
InputStream in=System.in; int by=in.read(); //by就是键盘录入的内容-->int
- 练习3:通过键盘录入数据。当录入一行数据后,就将该行数据进行打印。如果录入的数据是over,那么停止录入。 link5
在这个练习中录入一行数据就是之前的
readLine()
方法,但是readLine()
是字符流BufferedReader
类中的方法,而现在讨论的是字节流InputStream
的问题:那么能不能将 字节流转成字符流 再使用字符流缓冲去的readLine方法呢?在上一条中,输入输出的对象是键盘和控制台,如果想对文件操作的话,只需要做稍微的修改即可:
可以通过
System.setIn();
和System.SetOut()
修改设置默认输入输出设备(默认是键盘和控制台)。(了解即可,不常用)将异常信息保存到日志文件中 link10
获取系统信息link11
文件
将 文件或文件夹 封装成文件对象 link1
File类的常用方法 1
创建。
boolean createNewFile()
:在指定位置创建文件,返回true,如果该文件已经存在,则不创建,返回false。 link2
和输出流不一样,输出流对象一建立创建文件。而且文件已经存在,会覆盖。
boolean mkdir()
:创建文件夹。
boolean mkdirs()
:创建多级文件夹。link3删除。
boolean delete()
:删除失败返回false。如果文件正在被使用,则删除不了返回falsel。link4
void deleteOnExit()
;在程序退出时删除指定文件。判断。
boolean exists()
: 文件是否存在.
boolean isFile()
: 是否是文件,先判断文件是否存在
boolean isDirectory()
: 是否是目录,先判断文件夹是否存在
boolean isHidden()
: 是否隐藏
boolean isAbsolute()
: 时候绝对路径获取信息。
String getName()
:
String getPath()
: 封装的路径,文件本身可以不存在
String getAbsolutePath()
: 绝对路径,文件本身可以不存在
String getParent()
:该方法返回的是封装在File()中的目录中的路径,如果封装的是相对路径,至只返回相应的部分
long lastModified()
最够一次修改的时间
long length()
文件大小
等等
File类的常用方法——文件列表
- 文件列表方法
static File[] listRoots()
没有参数,返回文件根目录(盘符);
String[] list()
返回指定目录下的所有的文件和文件夹;
String[] list(FilenameFilter filter)
返回 过滤 之后的指定目录下的文件名称;link5
等等
- 文件列表方法
遍历某文件夹中的全部文件
删除文件夹:在windows中,要删除文件夹必须先删除其中的文件,使用递归删除 : link8
练习:将一个指定目录下的java文件的绝对路径,存储到一个文本文件中,建立一个java文件列表文件。link9
属性类Properties
Properties是hashtable的子类。也就是说它具备map集合的特点。而且它里面存储的键值对都是字符串。
它是集合和IO技术相结合的集合容器。可以用于键值对形式的配置文件。
那么在加载数据时,需要数据有固定格式:键=值
添加,修改,获取属性 link1
从文件中读取属性信息(通过“=”分割键值) link2
但是这种方法显然比较笨拙,Properties类为我们提供了一个load方法,可以加载流数据 link3
在第二条中,使用
setProperty()
修改属性信息只是修改了内存中的信息,而没有修改相应文件中的信息。如果想连同文件一起修改,可以使用store()
方法 link4练习:统计程序运行的次数:
在这个练习中,不能使用在程序中设置count计数器的方法,因为程序一旦结束,内存清理,count也就消失了。我们要建立一个程序外的计数器,即一个配置文件。(配置文件可以实现应用程序数据的共享) link5
其他
打印流对象:该流提供了打印方法,可以将各种数据类型的数据都原样打印。
字节打印流:PrintStream
构造函数可以接收的参数类型:- file对象。File
- 字符串路径。String
- 字节输出流。OutputStream
字符打印流:PrintWriter
构造函数可以接收的参数类型:- file对象。File
- 字符串路径。String
- 字节输出流。OutputStream
- 字符输出流,Writer。
简单实例 link1
合并流 link2
分割流,使用ArrayList合并流 link3
使用
ObjectOutputStream
直接存储对象,存储的对象只能使用ObjectInputStream
获取。link4RandomAccessFile
该类不是IO体系中子类,而是直接继承自Object。但是它是IO包中成员。它同时具备 读和写 功能。
内部封装了一个数组,而且通过指针对数组的元素进行操作。
可以通过getFilePointer
获取指针位置,
可以通过seek
改变指针的位置。其能完成读写的原理就是内部封装了 字节输入流和输出流 。
通过构造函数可以看出,该类 只能操作文件 ,分两种 模式:只读(“r”),读写(“rw”)
- 如果模式为只读 r。不会创建文件。会去读取一个已存在文件,如果该文件不存在,则会出现异常。
- 如果模式rw。操作的文件不存在,会自动创建。如果存在则不会覆盖。
该类相对于其他的 io 类的特点就是能够实现随机存取。
数据分段的前提是存储的数据本身有规律,可以使用 空 补位操作基本数据类型,可以使用
DataStream
link6操作字节数组
ByteArrayStream
ByteArrayInputStream
:在构造的时候,需要接收数据源,而且数据源是一个字节数组。ByteArrayOutputStream
: 在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。
这就是数据目的地。因为这两个流对象都操作的数组,并没有使用系统资源,所以不用进行close关闭。
类似的还有: 操作字符数组
CharArrayReader
,CharArrayWriter
操作字符串StringReader
,StringWriter
字符编码
在输入输出流中指定编码表 link1
在某些服务器中使用的是 IOS8859-1 编码表,不能识别中文,可以使用先编码再解码的方式解决 link2
但是这种方式不能解决 UTF-8 的乱码问题,因为 UTF-8 本身也识别中文,依然会产生乱码。练习:
有五个学生,每个学生有3门课的成绩,从键盘输入以上数据(包括姓名,三门课成绩),输入的格式:如:zhagnsan,30,40,60。计算出总成绩,并把学生的信息和计算出的总分数高低顺序存放在磁盘文件”stud.txt”中。- 描述学生对象。
- 定义一个可操作学生对象的工具类。
思想:
- 通过获取键盘录入一行数据,并将该行中的信息取出封装成学生对象。
- 因为学生有很多,那么就需要存储,使用到集合。因为要对学生的总分排序, 所以可以使用TreeSet。
- 将集合的信息写入到一个文件中。