黑马程序员:IO流

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------


 IO流体系:


字符流:

Reader

|--BufferedReader:

|--LineNumberReader

|--CharArrayReader

|--StringReader

|--InputStreamReaer

|--FileReader

Writer

|--BufferedWriter

|--CharArrayWriter

|--StringWriter

|--OutputStreamWriter

|--FileWriter

|--PrintWriter

字节流:

InputStream

|--FileInputStream:

|--FilterInputStream

|--BufferedInputStream

|--DataInputStream

|--ByteArrayInputStream

|--ObjectInputStream

|--SequenceInputStream

|--PipedInputStream

OutputStream

|--FileOutputStream

|--FilterOutputStream

|--BufferedOutputStream

|--DataOutputStream

|--ByteArrayOutputStream

|--ObjectOutputStream

|--PipedOutputStream

|--PrintStream

RandomAccessFile:

File:

IO流:

IO流用来处理设备之间的数据传输

按照流向流可以分为:

输出:核心设备数据往外围设备走,核心设备需要写数据

输入:外围设备数据往核心设备走,核心设备需要读数据

对内存而言——输入和输出都是相对内存而言的

Input:硬盘数据——>内存

Output:内存——>硬盘

持久化存储——断电后数据还在

硬盘:外围设备,旋转——寻道,慢

内存:数据的临时运算区,寻址,快

Java对数据的操作是通过流的方式来完成

实现了数据的流动

Java用于操作流的对象都在IO包中

流按照操作数据分为两种:字节流与字符流

字符流是基于字节流+编码表,更便于操作文字数据(读两个字节,查表,获得对应的字符)

只要是操作字符数据,应该优先使用字符流

IO流常用基类

字节流的抽象基类

InputStream  , OutputStream

字符流的抽象基类

Reader  , Writer

子类的阅读技巧:

流体系中的子类对象们,都以自己所属的体系名作为子类的后缀名

前缀名都代表其功能,也可以称为设备名称

close()操作跟flush()操作的区别:

使用完了windows系统资源,需要关闭资源

fw.close();//关闭资源操作close(),会先刷新flush(),再释放资源

flush()和close都可以将缓冲区中的数据写入目的地

但是flush()刷新之后,流还在,close()刷新后,流关闭

读取的两种方式:

read();

readchar[] arr);比第一种方式高效

char[] buf=new char[1024];

int len=0;

whlie(len=fr.read(buf)!=-1){

System.out.println(new String(buf,0,len));

}


练习:将c盘的一个文本文件复制到d盘。

ctrl+c——>相当于把数据存进缓冲区,也就是循环读写操作

word是非纯文本文件,所以不能直接读写。

字符到字节是写,字节到字符是读!


缓冲区:

性能优化——>缓冲!

缓冲区的出现提高了对数据的读写效率。

——字符数组缓冲区,或者字节流数组缓冲区

缓冲区就是把对应的数组进行封装,对外提供方法!

缓冲区相当于中转站,起到全程加速的作用!本身不是流!

没有流对象,缓冲区是没有意义的!

高效的写入:写入硬盘是比较慢的,所以频繁写入硬盘是比较慢的。数组是在内存中的,所以写入数组较快!

BufferedWriter  BufferedReader

BufferedWriter bfw=new BufferedWriter(new FileWriter("c:\\Demo.txt"));

BufferedReader bfr=new BufferedReader(new FileReader("c:\\Demo.txt"));

BufferedReader的低层原理:

缓冲区中有一个数组,通过流对象把数据读到该数组之中,之后的BufferedReader读数据都是从数组之中读取数组——读单个字符,读行!

缓冲区原理对单个字符读入read()和行读入readline()有意义!对数组读入,缓冲意义不大!数组读入涉及到字节流的操作!

缓冲的存在可以使得进行更细致的操作成为可能!比如判断行分隔符——行读入

也可以进行其他的自定义操作,比如把所有的'S'字符换成'$s$'等等!

缓冲区用到的设计模式:

解决问题行之有效的办法!——设计模式

装饰设计模式:对一组对象进行功能的增强,职责的增强,还不改变原有对象!

在原有对象上增加新功能!

前期为了扩展功能,又不改变原来对象(改变定义好的类是很麻烦的),使用的是继承并复写方法来解决的。

————装饰相比于继承更加灵活

记住:装饰设计模式,装饰类和被装饰类必须属于一个体系

在原来基础上增强其功能,但功能本身不变

FileReader低层已经会存在字节缓冲区,那BufferedReader意义何在?

字节流:

InputStream   OutputStream

读写操作的思想是一致的!

字节流的缓冲区:

4种复制的方式:

1,用数组作为自定义缓冲区复制

2,获取文件大小,建立刚刚好的数组一次性复制

3,使用已有的缓冲区BufferedOutputStreamBufferedInputStream

4,不使用缓冲区,字节来复制——最慢

字符流操作的结果肯定是编码表编码过之后的数据,所以它不能操作媒体文件!

转换流:

字节流关联字符文件:

方式1

FileInputStream fis =new FileInputStream("d:\\1.txt");

byte[] buf=new byte[4];

fis.read(buf);

System.out.println(new Stri

ng(buf));

方式2

如果能使用字符流的read方法,就能解决问题!

InputStreamReader isr=new InputStreamReader(fis);

//查当前系统默认的编码表

int ch=isr.read();//得到字符

直接已知子类:

FileReader

public class InputStreamReader

extends Reader

InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。

每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。

为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。例如:

 BufferedReader in   = new BufferedReader(new InputStreamReader(System.in));

FileInputStream fis=new FileInputStream("d:\\1.txt");

InputStreamReader isr = new InputStreamReader(fis,"GBK");

FileInputStream fis=new 

父子有什么区别?

FileReader是一个操作文本文件的使用默认编码的便捷类,它将字节流跟编码表进行了封装!

如果操作的不是文件,或者使用的不是默认编码,就不能使用FileReader,只能使用转换流!因为转换流可以指定要用的编码表,操作的数据可以是字节流

字符流关联字节流

System.in

System.out作为数据源或者数据目的

流操作规律:——流可以处理数据,但是处理数据的流对象很多,都有各自的特点和功能!到底如何选择最合适的对象呢?操作规律来确定

流的操作无非读写,所以通过几个明确就可以具体确定该使用那个对象:

1,确定是源还是目的——确定读还是写!

源:InputStreamReader

目的:OutputStream Writer

2,处理的数据是否是纯文本数据——确定了具体体系

是纯文本,源:Reader

是纯文本,目的:Writer

不是纯文本——字节流

3,找体系中的具体对象——明确具体流对象

要确定的是数据所在的具体设备:

源:硬盘(File前缀的流对象),键盘(System.in),内存(数组),网络(Socket

目的:硬盘(File前缀的流对象),显示器/控制台(System.out),内存(数组)网络(Socket)

4,明确具体对象后,继续明确是否需要额外功能

高效:Buffered

转换编码:InputStreamReaderOutputStreamWriter桥梁


Unicode跟本地编码转换:

打开文件看到的是文字!!!???

这内部应该有自动转换,让显示出来的是字符形式!

File类:

数据最常见的形式——文件!

File类将文件或者文件夹封装成了对象,便于对文件或者文件夹进行操作

提供了n多种方法对其进行操作

既可以封装已经存在的文件也可以封装不存在的文件或者文件夹

文件类型是由解析软件来说明的!文件可以没有扩展名(标示其文件类型的)

属性,字段:

路径分隔符:File.pathseparator

文件分隔符:File.separator

行分隔符:System.getProperty("line.separator");

方法:

获取:名称,大小,路径

修改时间:判断文件在当前程序操作过程中是否被修改,单独一个线程来监视文件是否被修改(获取时间跟修改时间是否一致),修改了则加载

创建,删除

f1.renameTO(f2):剪切并重命名

如果File对象中封装的文件夹不存在,或者封装的是个文件,list返回的都是null,所以在使用该方法时,建议加上判断,exists()&&isDirectory()

String[] names=dir.list();//列出当前目录的所有文件和文件夹,包含隐藏,不包含子目录

File[] files=dir.listFiles();//把文件作为对象装到数组返回,常用

过滤器的原理:过滤名字FilenameFilter,过滤文件FileFilter

函数的递归:——列出一个目录下所有文件及文件夹,包含所有子文件和子文件夹

直接调用自己,间接调用自己

前提:

1,必须要定义结束条件——如果没有结束条件会导致栈内存溢出

2,一定要控制递归的次数——次数太多仍然会造成栈内存溢出

什么时候使用递归:当一个功能被重复使用,但是每次调用时,传入的参数都和上一次运算结果相关

Properties

IO技术跟map集合相结合

是可以持久化的属性值的集合,可以将集合中的数据存储到持久化设备中,所以需要IO技术

该集合中的键和值都是字符串类型

该集合可以把数据存储刀到持久化设备上,可以将持久化设备上的规范数据存储到集合中

配置文件有两种:

properties可以进行简单属性配置

xml可以进行复杂描述——DOM4JDOM for Java来解析配置文件

IO流之中的其他功能对象:——具备特定的功能

1,打印流:

PrintWriterPrintStream

可以直接操作输入流和文件

int read():一次读取一个字节,在转成int

write(97)将一个整数思维中的最低位字节写入目的地

记事本显示:a

print(97)——把数据的表示形式打印到目标中,目的的数据和打印时的数据表现形式一致。给的什么,打印出来就是什么

内部是写入的String.valueOf(97);

记事本显示:97'9','7'两个字节)

键盘录入和显示输出是系统的标准输入输出,System.inSystem.out在系统中是唯一的,在程序中关闭了该流之后,后面代码再也不能使用这两个流。除非再次启动程序。

想要保证数据值的表示形式时,使用该额外功能

2,序列流SequenceInputStream

有序排列 ——

多个源对应一个目的

内部封装了一个集合,也是在操作一个有序集合,多个流对象合并成一个流

序列流构造函数中需要枚举类型Enumeration,所以要用Vector来作为流对象的容器。但是这已经不用了,可以自己建立枚举对象,然后重写其中方法(必须先建立ArrayList的迭代器,用迭代器中的代码实现枚举中的功能);也可以用Collections之中的方法,把这个ArrayList转换成对应的枚举类型

练习:文件分割器

分割完之后再还原

3,对象的序列化和反序列化

操作对象ObjectInputStreamObjectOutputStream

bean数据模型,很多方法,很多属性,很多对象

对象序列化:将多个对象按照顺序进行排序并持久化,一个一个存进去序列化会在每一个对象之后添加一个结束标记,用来跟下一个对象进行区别。

对象在程序结束之后需要该对象还在,延长对象的生命周期,持久存储

反序列化:把存储的对象一个一个读出来

需要强转

Serializable接口就是个标记,内部没有自己的方法

数据签名:用来唯一标示(类或者对象)的标示符

要把对象持久化存储,该对象必须实现接口Serializable

对象中的数据是特有的,用class文件可以再次创建该类对象,但是属性就不一样了,就不是原来的对象了!

就比如你玩游戏的人物一样,你玩游戏玩快满级了,死机重启之后,如果没有原来对象的话,你进去就是0级!所以需要.class文件和对象文件才能得到原来的对象。

Serializable接口到底做了什么?

该接口目的就是给每一个需要序列化的类添加一个ID,防止反序列化的时候不匹配!每个类都有一个serialVersionUID,改变了类之中的内容,该序列号也就随之改变。

所以该ID号强烈建议自定义并私有!因为默认算法对类的内容敏感性很高,微小的变动就会导致该ID号不一致InvalidClassException,从而加载失败!

静态的数据不会被序列化,因为静态数据存在于方法区,它不属于对象;

对于非静态数据如果也不想被序列化,可以用transient(短暂的)来修饰,表示这个数据不是一个生命周期很长的数据,所以不要序列化来持久存储

文件中存储什么东西,就叫什么扩展名,存Object就叫.Object

练习:把多个类对象写入相同文件,读出来的时候,怎么读?

把不同类的对象写入相同文件,读出来怎么读?

4,管道流PipedInputStreamPipedOutputStream

以前输出和输入流之间需要中转站,

1,而管道流输入流和输出流可以连接

2,必须结合多线程技术,单线程容易造成死锁

5,操作基本数据类型

DataInputStream&&&DataOutputStream

6,操作字节数组

ByteArrayInputStreamByteArrayOutputStream

数据在内存中,读写没有用到底层资源,所以关闭无效,而且不会产生IOException

把数组封装,用流的思想来操作数组!

以字节数组作为源

相当于把一个数组中的内容写到另外一个数组之中。

7,操作字符数组

CharArrayReaderCharArrayWrite

不需要关闭资源

8,操作字符串

StringReaderStringWriter

不需要关闭资源

9RandomAccessFile——流的工具类

随机访问文件,自身具备读写的方法,随机访问就是用指针来记录要操作的数据位置:

1,该类不是流体系中的对象

2,用来操作文件的对象

3,可以进行读写操作

4,内部定义了一个大型的字节数组

5,封装了字节流的工具类,可读写,字节数组缓冲

6,操作的源和目的只有文件

从程序往记事本中写内容,打开记事本后,修改并保存记事本中的内容,则现在内存中的数据是从记事本中写入的!这会再从记事本输出,就是记事本的内容,可能编码就改变了,得到的内容不同!

把数组封装成对象,有了数组,操作指针,实现随机访问!要尽量保证数据有规律,才能用seek能设定步长;.

完成随机访问的原理?

seek()指定指针的位置——实现随机访问的根本方法

skipBytes()方法跳过指定的字节数

getFilePointer()获取指针的位置

只能操作文件,四种访问方式

应用场景:3G可用

能实现多线程同时往一个文件中写数据,指定开始和结束



----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值