11-IO流(Properties简述)
到这里IO中的基本对象我们已经学完了,接下来介绍一个单独的对象,当然前面也有接触过,就是:Properties。
Properties是hashtable的子类,也就是说它具备map集合的特点,而且它里面存储的键值对都是字符串,是集合中和IO技术组合的集合容器。
该对象的特点:可以用于键值对形式的配置文件。
那么在加载数据时,需要数据有固定格式:键=值。
举个例子,我们现在将文本颜色设置为红色:
我们将软件关闭,再重新打开,文本颜色依然是我们改动后的样子。
这是将配置信息进行了实体化存储导致的,它把这些信息存到一个文件中去了,每一次打开软件它都会加载这个文件。
我们可以找到这个文件看一看:
发现它都是以键值对的形式存在的,比如colors它的值是DDDDDD......。
为什么写成键值对的形式呢?
因为如果我们直接存储红色,这样就无法分辨它到底是文本颜色还是背景颜色了,所以以键值对形式存储非常直接明了。
可是很遗憾的是,这种键值对的信息通常都存在文件中,我们要想去获取这个信息,就要先找到这个文件,而且要操作这些数据要用到IO流技术,这就是Properties对象的由来,它的特点在于,不只可以操作键值对,而且可以操作硬盘上的键值对信息(集合中的数据都在内存中)。
12-IO流(Properties存取)
Properties中有一些特有的方法:
接下来我们对其中特有的方法进行演示。
设置元素:
获取元素值:
获取键集:
13-IO流(Properties存取配置文件)
刚刚只是演示了一下,用代码设置了一下键值对,实际中,键值对的数据一般已经存在在文件中了。
那如何将流中的数据存储到集合中呢?
步骤:
1,用一个流和info.txt文件关联。
2,读取一行数据,将该行数据用“=”进行切割。
3,等号左边作为键,右边作为值,存入到Properties集合中即可。
代码:
但是,如果每一次获取硬盘上的数据往里面存,用这个方法就太麻烦了。所以Properties结合为我们提供了一个load方法,可以直接加在一个字节流,或者字符流都行,但是加载字符流的load方法是1.6版本才有的,早期都是字节流:
load方法演示:
我们现在想要将其中wangwu的值改成39:
properties中改了:
可是文件中依然没有变:
setProperty方法只是改变了内存的数据,而下面我们要用到store这个方法,可以将内存中的数据保存到流中:
演示:
OK,文件中也保存了:
14-IO流(Properties练习)
做一个练习:做一个程序,用于记录应用程序运行次数,如果使用次数已到,那么给出注册提示。
很容易想到的是:计数器。
可是该计数器定义在程序中,随着程序的运行而在内存中存在,并进行自增。随着该应用程序的推出,该计数器也在内存中消失了。
下一次再启动该程序,又重新开始从0计数。这样不是我们想要的。
我们想要的效果是:程序即使结束,该计数器的值也在。下次程序启动会先加载该计数器的值并加1后再重新存储起来。
所以要建立一个配置文件,用于记录该软件的使用次数。该配置文件使用键值对的形式,这样便于阅读数据,并操作数据。键值对数据是Map集合,数据是以文件形式存储,使用IO技术。
那么Map+IO---->properties。
也就是说,配置文件可以实现应用程序数据的共享。
代码:
注意,操作文件要养成先将文件封装成对象的习惯,不要直接拿着文件名使用,封装成对象后,就可以对这个对象进行判断等操作了,比如上面的判断它是否存在,如果不存在则建立一个新的,就避免了一些报错。
上面的代码忘记写使用次数到了给注册提示的功能,补上:
了解内容:
配置文件中的信息要么是properties的,要么是xml的。它们有什么区别呢?
properties:
这种方式描述信息其实是有限的,数据关系不能太复杂,如果太复杂了,就无法描述了,即使能描述了,操作起来也费劲。
比如现在我们想要加入10个人的信息,这时候用xml是最方便的:
这时候用键值对描述就超麻烦,写一大堆还不利于区分,而用xml封装完之后则有利于区分。
那用xml封装之后怎么取呢?
Java本身具有专门取这个数据的对象:
可以通过这个对象来拿到文档中的数据,但是没想到还是好麻烦,Java想要拿到这个文档中的数据,要用到好多种对象和好多种方法来完成。
后来有一帮牛人们又做了一个更简单的工具:dom4j。
取名的含义就是:dom for java,因为four和for谐音,为了方便书写,就简写成了dom4j。
这个工具在开发xml的时候就会用到。
15-IO流(PrintWriter)
接下来说一下IO包中的其他流。
打印流:PrintWriter(字符流)和PrintStream(字节流)。可以直接操作输入流和文件。
我们先看一下字节流PrintStream:
我们看一下它的厉害:
它可以对这些基本数据类型进行直接操作。
我们看看字节打印流PrintStream的其中一个构造函数:
发现它可以直接操作文件。
凡是能和文件相关的流对象都是比较重要的流对象。
还有其他构造函数:
而我们再看一下字符输出流PrintWriter,这个对象确实非常的常用,到了Web开发的时候,都用这个对象,把数据一条一条的打到客户端去,让客户端的浏览器对它进行解析执行。
我们看一下它的构造函数,发现可以接收的参数类型比字节输出流还要多一个:
总结一下:
打印流:该留提供了打印方法,可以将各种数据类型的数据都原样打印。
它又分为两种:
字节打印流:PrintStream
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。注意只有OutputStream,其他类型不行哦。
字符打印流:PrintWriter
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
4,字符输出流。Writer
代码示例:
PrintWriter中有一个构造函数传了boolean类型的参数autoFlush,它有自动刷新的功能:
接下来我们不想将数据在控制台上输出,想存到文件中去。
代码:
运行,没有输入over之前txt文件中没有存入数据,输入over之后,txt文件中存入了数据:
之所以输入over之前文件中没有存入数据,是因为没有刷新。
我们想要有自动刷新,很简单,将文件封装到流中,就可以使用自动刷新了:
这样一来,就实现了边输入文件中边存入的功能了。
16-IO流(合并流)
说完了打印流,我们说序列流:SequenceInputStream。
这个对象没有对应的OutputStream。
这个对象表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾。接着从第二个输入流读取,以此类推,直到到达包含的最后一个输入流的文件末尾为止。
什么意思呢,可以将多个流对象拼接成一个流对象。
我们看看这个构造方法,可以进行两个流的合并:
而另一个构造方法就更厉害了,可以进行多个流的合并:
只要它是InputStream的子类就好了,这里用到了泛型的限定。
接下来我们练习一下,把这三个文件中的数据变成一个文件:
成功:
17-IO流(切割文件)
能合并自然也能切割。
演示:
这三个文件看不了了。。。因为一只鸭子被切成三块之后就不再是一只鸭子了。
再将这三个文件合并起来:
哦哦,这个方法还没有写完,续上:
注意抛出异常哦:
运行之后,出现了0.bmp文件:
除了bmp文件,我们切mp3也是没有问题的。
当然切更大的文件就需要分成多个流对象来操作了。