大家好,这里是五彩石编程,我是军哥。打开JDk1.8的源码,我们会发现单单java.io包下面,就有87个文件,这些文件组合在一起,构成了JAVA操作IO的基础,但同时我们也会发现一个问题,大部分同学面对这么多的文件时,要么显得无从下手,要么很快就陷入了技术的细枝末节中迷失了方向,今天军哥就来带着大家,用10分钟的时间,一起把IO搞清楚。
第一步:用2分钟的时间,把87个文件,缩减为7个
开始
我们先花10秒钟的时间快速的把IO包下面的文件名浏览一遍,不需要细看,跟着思路走就行:
Bits
BufferedInputStream
BufferedOutputStream
BufferedReader
BufferedWriter
ByteArrayInputStream
ByteArrayOutputStream
CharArrayReader
CharArrayWriter
CharConversionException
Closeable
Console
DataInput
DataInputStream
DataOutput
DataOutputStream
DefaultFileSystem
DeleteOnExitHook
EOFException
ExpiringCache
Externalizable
File
FileDescriptor
FileFilter
FileInputStream
FilenameFilter
FileNotFoundException
FileOutputStream
FilePermission
FilePermissionCollection
FileReader
FileSystem
FileWriter
FilterInputStream
FilterOutputStream
FilterReader
FilterWriter
Flushable
InputStream
InputStreamReader
InterruptedIOException
InvalidClassException
InvalidObjectException
IOError
IOException
LineNumberInputStream
LineNumberReader
NotActiveException
NotSerializableException
ObjectInput
ObjectInputStream
ObjectInputValidation
ObjectOutput
ObjectOutputStream
ObjectStreamClass
ObjectStreamConstants
ObjectStreamException
ObjectStreamField
OptionalDataException
OutputStream
OutputStreamWriter
PipedInputStream
PipedOutputStream
PipedReader
PipedWriter
PrintStream
PrintWriter
PushbackInputStream
PushbackReader
RandomAccessFile
Reader
SequenceInputStream
SerialCallbackContext
Serializable
SerializablePermission
StreamCorruptedException
StreamTokenizer
StringBufferInputStream
StringReader
StringWriter
SyncFailedException
UncheckedIOException
UnsupportedEncodingException
UTFDataFormatException
WinNTFileSystem
WriteAbortedException
Writer
10秒钟时间到,通过统计我们可以发现以下规律:
关键字 | 文件数 |
---|---|
stream | 29 |
reader | 9 |
writer | 8 |
exception | 15 |
合计 | 61 |
减去上面占比最多的61个文件,还剩余26个文件,用5秒钟的时间,快速浏览一下文件名:
Bits
Closeable
Console
DataInput
DataOutput
DefaultFileSystem
DeleteOnExitHook
ExpiringCache
Externalizable
File
FileDescriptor
FileFilter
FilenameFilter
FilePermission
FilePermissionCollection
FileSystem
Flushable
IOError
ObjectInput
ObjectInputValidation
ObjectOutput
RandomAccessFile
SerialCallbackContext
Serializable
SerializablePermission
WinNTFileSystem
5秒钟时间到,再减去DataInput、DataOutput、ObjectInput、ObjectOutput这种接口级别的文件,剩余22个文件。
再减去带有Permission、Error、Validation、Serializable、Closeable、Externalizable、Flushable、Hook这类和IO功能关系并不十分密切的接口及类,还剩余11个文件,再用3秒钟的时间快速浏览一下:
Bits
Console
DefaultFileSystem
ExpiringCache
File
FileDescriptor
FileFilter
FilenameFilter
FileSystem
RandomAccessFile
WinNTFileSystem
3秒钟时间到,此时,文件量已经由87个减到了11个,根据经验,出现数量较多的,一般是比较重要的,而能通过多重过滤后仍然留下的,要么是精华,要么就是非常小众的功能,再来花1分钟的时间看一下剩余的这11个文件:
1. Bits 是一个把其它类型数据转为byte的工具类,和io关系不密切,忽略
2. Console 是用来读取和写入控制台,远程登录过linux的,都明白什么意思,没什么需要深入的,忽略
3. DefaultFileSystem 只有一个返回当前控制系统平台的静态方法,忽略。
4. ExpiringCache 在IO操作中,做缓存管理的工具类,只有5个简单的方法,忽略,
现在还剩余7个,全部是和File相关的,再花1分钟的时间来仔细看一下:
1.File 是对文件的抽象,IO操作大多和文件相关,所以保留
2.FileDescriptor 是文件描述符,和IO操作关系不大,忽略
3.FileFilter 是只有一个方法的接口,忽略
4.FilenameFilter 也是只一个方法的接口,忽略
5.FileSystem 对文件系统的抽象类,和文件强相关,保留,但不需要花过多时间研究
6.RandomAccessFile 可以随机读写文件的类,听着都很强大,保留
7.WinNTFileSystem 是FileSystem在当前平台的实现类,了解FileSystem即可,不需要研究,忽略
现在还剩余3个文件,加上数量比较多的stream、reader、writer、exception四个大类,每类研究1个文件,加起来只需要深入研究7个文件即可掌握整个IO。
第二步:逐个分析
1.stream
通过文件名,可以发现,stream分为两大类:inputStream和outputStream,也就是输入输出流,同时也发现inputStream中read的方法最多,并且没有write相关的方法,outputStream中write的方法最多,并且没有read的方法,所以,在这个抽象中,我们发现了,input即read(读),output即write(写),如果对"linux下一切皆文件"有点印象的话,这不就是明摆着要把所有的IO相关的对象,都抽象成文件吗?那么实现了对文件的读写,不就是实现了IO的全部功能了吗?呵呵,一个新的世界已经被我们发现了。
再来看一下inputStream中的read方法的参数,以及outputStream中write方法的参数,我们发现,都是byte,基于在硬盘中,一切都是二进制存储,8个二进制位合成1个byte,读文件就是读byte,这样的设计看起来非常合理,那就暂时不用深入研究了。
2.reader、writer
有了对stream的研究,reader和writer就放到一起来研究了。看一下reader中read方法的参数,发现大多是char[],writer中write方法的参数有char[]也有string,基于sting底层也是char[]的事实,所以可以认为write方法的参数本质上都是char[],这和stream就不一样了,那么为什么会不一样呢?
通过查看reader及writer文件头部的注释,我们可以发现,原来它们是为了读写character stream(字符流)的,看来java的开发人员,已经替我们想到了,只是读取字节,对于像图片、音乐
视频这样的文件来说肯定非常合适,但遇到都是字符串这样的文本时,还需要转换来转换去的,太麻烦了,所以直接设计了一个读写字符的类出来,这个思路比较妙呀!
3.exception
现在再来看exception相关的文件,随便打开几个,发现都是简单的异常相关的几个操作,不用再费心思了。
4.File
打开File文件,查看其方法列表,发现有如下规律:
- 有一堆怎么创建一个File对象的方法
- 有一堆和文件路径相关的方法
- 有一堆和文件属性相关的方法
- 有一堆和文件管理相关的方法
- 有一堆和子目录相关的方法
- 有一堆普通的任何一个对象都有的方法
完了,这基本上就是File文件的全部内容,好像和input及output关系不大,那就再来看一下找一下FileInputStream及FileOutputStream,发现全是和File相关的操作,原来用到了这里,那么顺着这个思路,ByteArrayInputStream中是不是也大量使用了Byte,查一下果然如此,好了,File相关的到此为止了。
5.RandomAccessFile
RandomAccessFile既然叫做随机读写文件,那么肯定少不了skip相关的方法,同时也发现有很多读写相关的方法,看来设计的很强大,用的时候能想到就可以了
好了,第二步已经结束了。
第三步:把知识串起来
现在对于java.io包,相信大家已经不陌生了,一个inputStream被玩出来了这么多的实现花样,java的典型特点:一个接口/抽象类,多个实现,在IO包中,也表现得淋漓尽致,相信对于具体的某个实现,大家已经不会感觉到为难了。
现在我们又遇到了一个问题,那就是:从开始到现在,一行代码也没有看到,现在让我们对一个文件进行读写,好像还是没有思路。所以接下来就开始把知识串到一起,形成思路,最终输出成代码。
开始了。
以读文件为例:
要读一个文件,首先需要知道文件在哪里吧,也就是文件的路径,有了路径,那不就可以实例化一个File对象了嘛,有了File对象,FileInputStream就可以使用了,或者直接通过文件路径,来实例化一个FileInputStream,那现在不就有inputStream了嘛,有了inputStream,直接调用里面的read方法,不就读出来了吗? so easy!
嫌一个字节一个字节读得慢?用bufferedInputStream,一次多读点不就可以了,还嫌慢?那么io包已经帮不了你了,用nio吧。
想了解nio的用法,请微信搜索并关注“五彩石编程”公众号,军哥的文章将会持续同步更新。
下课