------- android培训、java培训、期待与您交流! ----------
IO 流
IO流用来处理设备之间的数据传输。Java对数据的操作是通过流的方式。Java用于操作流的对象都在IO包中。
输入流和输出流相对于内存设备而言。
将外设中的数据读取到内存中:输入。
将内存的数写入到外设中:输出。
字符流与字节流的联系:(按操作数据分)
字符流的由来:字节流读取文字字节数据后,不直接操作而是先查指定的编码表,获取对应的文字。再对这个文字进行操作。简单说:字节流+编码表。
字节流的抽象基类:InputStream,OutputStream。
字符流的抽象基类:Reader,Writer。
P.S.
由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如果要操作文字数据,建议优先考虑字符流。
而且要将数据从内存写到硬盘上,要使用字符流中的输出流:Writer。硬盘的数据基本体现是文件,希望找到一个可以操作文件的Writer:FileWriter。
P.S.
1. close方法只能用一次。
2. 流关闭以后不能,不能再调用write方法,否则会报异常错误:如果构造函数中加入true,可以实现对文件进行续写。
IO流的异常处理方式:为防止代码异常导致流无法关闭,因此在finally中对流进行关闭。
需求:读取一个文文件,将读取到的字符打印到控制台。(使用FileReader)
第一种读取方式:使用read()方法读取文本文件数据。
第二种读取方式:使用read(char[])方法读取文本文件数据
字符流缓冲区:
字符流的缓冲区:缓冲区的出现提高了对数据的读写效率。
对应类:BufferedWriter、BufferedReader
P.S.缓冲区要结合流才可以使用。
只有BufferedReader有读取一行readLine()方法
作用:在流的基础上对流的功能进行了增强。
写入换行使用BufferedWriter类中的newLine()方法。
读取一行数据使用BufferedReader类中的readLine()方法。
bufr.read():这个read方法是从缓冲区中读取字符数据,所以覆盖了父类中的read方法。
bufr.readLine():另外开辟了一个缓冲区,存储的是原缓冲区一行的数据,不包含换行符。
原理:使用了读取缓冲区的read方法,将读取到的字符进行缓冲并判断换行标记,将标记前的缓冲数据变成字符串返回。
LineNumberReader
跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。
装饰设计模式
装饰和继承都能实现一样的特点:进行功能的扩展增强。
区别:
首先有一个继承体系:
Writer
|--TextWriter:用于操作文本
|--MediaWriter:用于操作媒体
如果想要对操作的动作进行效率的提高,按照面向对象,可以通过继承的方式对具体的对象进行功能的扩展,那么就需要加入缓冲技术。
Writer
|--TextWriter:用于操作文本
|--BufferTextWriter:加入了缓冲技术的操作文本的对象
|--MediaWriter:用于操作媒体
|--BufferMediaWriter:加入了缓冲技术的操作媒体的对象
以上方式并不理想,如果这个体系需要再进行功能扩展,又多了更多流对象。这样就会发现只为提高功能,导致继承体系越来越臃肿,不够灵活。
Writer
|--TextWriter:用于操作文本
|--MediaWriter:用于操作媒体
|--BufferedWriter:用于提高效率
可见:装饰比继承灵活。
特点:装饰类和被装饰类都必须所属同一个接口或者父类。
字节流
基本操作与字符流类相同。但它不仅可以操作字符,还可以操作其他媒体文件。
FileOutputStream、FileInputStream的flush方法内容为空,没有任何实现,调用没有意义
流的操作规律:
1.明确源和目的
源:InputStream Reader
目的:OutputStream Writer
2.明确是否是纯文本
是:源: Reader目的:Writer
否:源:InputStream目的:OutputStream
3.明确具体设备
源设备:
键盘:System.in硬盘:File内存:数组 网络:Socket流
目的设备:
控制台:System.out硬盘:File内存:数组 网络:Socket流
4.是否需要额外功能
是否需要加缓冲区Buffered
转换流:字符流与字节流之间的桥梁
应用:字节流中都是字符时,转成字符流操作更高效
InputStreamReader:字节流转字符流,解码(读取文件等)
OutputStreamWriter:字符流转字节流,编码(输出文件等)
P.S.
获取键盘录入时,System类的setIn(),setOut()方法可以改变默认设备
System.setIn(new FileInputStream(“1.txt”));//将1.txt作为源
应用了缓冲区及转换流的输入输出:
BufferedReader buff=new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));
什么情况使用转换流:
1.源或目的对用的是字节流对象,操作却是文本
2.一旦操作涉及到指定编码表时,必须使用转换流
例:BufferedWriter bufw=new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(“a.txt”),charseNamegpp));
File类:
用来将文件或文件夹封装成对象,以方便对其属性信息的操作
File类对象可以作为参数传递给流的构造函数
P.S.:流只能操作数据,不能操作文件
File对象常用方法:
1.获取
getAbsoluteFile() 返回此抽象路径名的绝对路径名形式。 | |
getAbsolutePath() 返回此抽象路径名的绝对路径名字符串。 | |
getName() 返回由此抽象路径名表示的文件或目录的名称。 | |
getParent() 返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null。 | |
getParentFile() 返回此抽象路径名父目录的抽象路径名;如果此路径名没有指定父目录,则返回 null。 | |
getPath() 将此抽象路径名转换为一个路径名字符串。 |
2.创建和删除
boolean | createNewFile() 当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件。 |
boolean | delete() 删除此抽象路径名表示的文件或目录。 |
boolean | mkdir() 创建此抽象路径名指定的目录。 |
3.判断
boolean | isAbsolute() 测试此抽象路径名是否为绝对路径名。 |
boolean | isDirectory() 测试此抽象路径名表示的文件是否是一个目录。 |
boolean | isFile() 测试此抽象路径名表示的文件是否是一个标准文件。 |
boolean | isHidden() 测试此抽象路径名指定的文件是否是一个隐藏文件。 |
4.重命名
boolean |
5.系统根目录和容量获取
long | getFreeSpace() |
long | getTotalSpace() |
long | getUsableSpace() |
String[] | list() 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。 |
File[] | listFiles() 返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。 |
static File[] | listRoots() 列出可用的文件系统根。 |
递归
函数自身直接或者间接的调用到了自身。
一个功能在被重复使用,并每次使用时,参与运算的结果和上一次调用有关。这时可以用递归来解决问题。
P.S.
1、递归一定明确条件,否则容易栈溢出。
2、注意一下递归的次数。
Properties集合
Map
|--Hashtable
|--Properties
特点:
1. 该集合中的键和值都是字符串类型。
2. 集合中的数据可以保存到流中,或者从流中获取。
3. 通常该集合用于操作以键值对形式存在的配置文件。
IO包中的其他类
打印流
PrintWriter与PrintStream:可以直接操作输入流和文件。
PrintStream为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
与其他输出流不同,PrintStream永远不会抛出IOException。
PrintStream打印的所有字符都使用平台的默认字符编码转换为字节。
在需要写入字符而不是写入字节的情况下,应该使用PrintWriter类。
PrintStream:
1. 提供了打印方法可以对多种数据类型值进行打印,并保持数据的表示形式
2. 它不抛IOException
PrintWriter:字符打印流
序列流
SequenceInputStream:对多个流进行合并。
使用ArrayList将各序列流添加进去(或Vector枚举,效率稍低)
Enumeration :实现 Enumeration 接口的对象,它生成一系列元素,一次生成一个。
练习:文件切割器(Properties集合)。文件合并器(序列流)。
操作对象流 ObjectInputStream与ObjectOutputStream
P.S.
被操作的对象需要实现Serializable,即序列化。
类通过实现java.io.Serializable接口以启用序列化功能,Serializable只是一个标记接口。
Serializable:用于给被序列化的类加入ID号,用于判断类和对象是否是同一个版本。
writeObject方法不能写入类及其所有超类型的瞬态和静态字段的值。
RandomAccessFile
随机访问文件,自身具备读写的方法。
通过skipBytes(int x),seek(int x)等方法来达到随机访问。
特点:
1. 该对象即能读,又能写。
2. 该对象内部维护了一个byte数组,并通过指针可以操作数组中的元素。
3. 可以通过getFilePointer方法获取指针的位置,和通过seek方法设置指针的位置。
4. 其实该对象就是将字节输入流和输出流进行了封装。
5. 该对象的源或者目的只能是文件。通过构造函数就可以看出。
P.S.RandomAccessFile不是io体系中的子类。
管道流:
PipedInputStream和PipedOutputStream
输入和输出可以直接进行连接,通过结合线程使用
操作基本数据类型
DataInputStream与DataOutputStream
操作字节数组
ByteArrayInputStream与ByteArrayOutputStream
P.S.关闭字节数组输出输出流无效,因为它们没有调用底层资源,所有的操作都是在内存中完成的。
编码表
各个国家的文字用数字来表示,并一一对应,形成一张表,这就是编码表。
常见的编码表
ASCII:美国标准信息交换码,用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表,用一个字节的8位表示。
GB2312:中国的中文编码表。
GBK:中国的中文编码表升级,融合了更多的中文文字符号。
Unicode:国际标准码,融合了多种文字。
所有文字都用两个字节来表示,Java语言使用的就是unicode
UTF-8:最多用三个字节来表示一个字符。
......
如果编码编错了,解不出来。
如果编对了,解错了,有可能有救。
如果编对了,解错了,也可能没救了。
实验:联通乱码问题。
原因在于这两个字的编码以后的二进制都符合utf-8的解码需求,直接用了utf-8解码