Java IO基础从这里开始(上)

  我计划写三篇比较长的博客,来详细梳理一下java中的IO操作,大致内容是:第一篇介绍相关的类,第二篇整理相关的面试题,第三篇计划使用这些类和方法完成一个小项目。

  每篇文章都不是以往的风格,不在单纯的将其作为自己的笔记瞎写,而是认真的对自己的学习情况整理一下,达到复习的目的,同时如果这些东西可以帮助的一些初学者(好吧,其实我也是),那我将十分的开心。


写作目的
  基本掌握Java IO部分的类,了解IO操作的大致面貌,梳理和整理各种类的关系。


写在前面
  java的IO操作给我的第一感觉就是涉及的类太多了,自己看书的时候感觉根本无从下手,但是只要弄清楚了每个类的关系,其实学起来并不是很难。

  我们首先得建立起一个概念,流。什么是流呢,我们可以举一些生活中的例子,水流,电流等等。水流是从一个地方流向另一个地方的水,而电流则是从正极流向负极的电子。凡是涉及流的东西,都有一个共同的特点,那就是一定是什么东西从一个地方到另一个地方。

  那么把这个概念放在计算机中理解一下,首先,流的对象是什么,水流的对象是水,电流的对象是电子,而在我们文件操作中,流的对象自然就是文件的内容,这些内容就是一个一个字符,但是站在计算机的角度来看,这些字符在计算机中其实就是一个一个字节存储的对象。所以我们可以按照对象来讲流分成两种,字节流和字符流。前面说到了流的特征是从一个地方流向另一个地方,那么对于文件流来说,就是从一个文件向另一个文件。
这里写图片描述

  其实从上面我们可以得到两概念:流出和流入,这两个词对应两个概念(output,input),后面我们会经常看到这两个词。


一.java中的文件对象
  java有一句话叫做“万物皆对象”,这句话java的确体现的淋漓尽致,对于磁盘中的文件来说,java中也有相应的类与之对象,这个类就是下面要讲的File类。通过File类实例化出来的对象实际上就对应着磁盘中的某个文件,这常常就是我们希望操作的文件对象(ps,这里不区分目录与普通文件的概念,因为目录也是一种文件,所以本文所说的文件,指的就是普通文件和目录)。通过File创建出来的对象,就与某个磁盘文件相对应,我们可以简单的认为操作这个File对象就是操作相关的文件。

这里写图片描述

File类的简介:
1. File是一个类。可以创建其对象,该对象对应着一个文件或者目录
2. File中的方法仅涉及到如何创建,删除,重命名等。
3. File类对象与平台无关
4. File对象经常作为io流的构造器形参

下面是File类实例化的一种方式
File file1=new File("test.txt");

  File类的构造函数拥有一个参数,这个参数就是文件的路径,有可能是相对路径,也有可能是绝对路径。但这里要特别注意一下对于windows系统,由于路径的分割符是’\’,二这个符号恰好是转义字符,所以应该替换成‘\’,比如’C:\Users\zeng\Desktop’应该写成’C:\\Users\\zeng\\Desktop’,或者使用’/’代替’\’.

还有其他构造方式,这里不做介绍。

  到这里为止我们可以获取到一个需要操作的磁盘文件了,下面将说明File类的一些常用方法。在此之前,我先将这些方法进行分类。

  1. get相关
      get开头的方法的特点就是获取文件的一些相关信息,如文件名,文件路径,文件的上一级目录是什么等等
    这里写图片描述
  2. set相关
      set开头的方法涉及给文件设置某种属性
    这里写图片描述
  3. is相关
      以is开头的方法的返回值一般是boolean型,这些方法通常用来判断对象的状态。
    这里写图片描述
  4. can相关
       以can开头的结尾通常用来判断文件是否具有某种权限(读,写,执行等)
    这里写图片描述

  5. 创建与修改
      很多时候我们所创建的File类对象在磁盘中并没有这样一个文件存在,我们可以选择创建。同时如果存在我们也可以进行删除操作。
    这里写图片描述

  6. 其他方法
      这些方法同样十分重要,之所以归为其他方法只是笔者实在无法将他们归类
    这里写图片描述

  最后,特别要注意的是,凡是与文件本身有关的东西,如名字,状态,属性等等,都需要用到File类,File类无法对文件的内容作出任何动作,可以理解为在你的windows桌面里有一个文件,你不可以去打开它,但是你可以删除他,查看他的属性,设置他的属性等等。File类也是其他IO类的基础。这里我并没有去详细介绍每个方法,而是将其分类简单的描述了一下他们的功能,因为日后用的时候总能体会到他们的用处,这里只简单的告诉你有什么即可。


二.FileInputStream和FileOutputStream
  下面介绍两个类,这两个类的中文名称分别是文件输入流和文件输出流。注意这里的输入与输出是对于程序来说的,输入就是将文件的内容输入到程序(也就是读),输出就是将程序中的内容输出到文件(也就是写),我们站在上面角度上去理解十分重要,切记,输入输出都是站在程序的角度。
这里写图片描述
  我们的FileInputStream与FileOutputStream类就是建立在文件与程序之间的一座桥梁。有了这些,我们可以先来看看这两个类的构造方法。
FileInputStream f1=new FileInputStream(new File(filePath));
FileOutputStream f2=new FileOutputStream(new File(filePath));

  通过这两个类各自都构造方法就分别将一个文件与一个流对应起来了,以后如果要从文件中读内容,只需要从FileInputStream对象中读取,将内容写入文件,只需将内容写入FileOutputStream中就可以了。
这里写图片描述

他们各自的方法很简单
1.FileInpustream对应着读操作
这里写图片描述

2.FileOutputStream对应着写操作
这里写图片描述

  为了安全起见,文件流在使用完成后是需要进行关闭的,虽然java的垃圾回收机制可以回收程序所不使用的资源,但是注意垃圾回收机制觉得不会回收一个不再使用的流,因此需要我们手动关闭,他的方法很简单
这里写图片描述

下面使用这两个类的方法写一个复制的小程序。

这里写图片描述

本小节最后的一个小问题:上面的byte数组 buf在程序中起的是什么作用?


三.BufferedInputStream类和BufferedOutputStream类
  首先来回答上面一小节中的问题,buf的作用是什么。在上面的那个程序中程序将读取的东西放在buf数组中,接着又从buf’数组中取出内容,放入另一个文件对应的流。这里的buf起的就是缓冲作用,仔细分析一下缓冲区的作用,如果缓冲区过小,那么不断读取的次数将会变多,相应的效率就有可能降低,而如果缓冲区过大,则会浪费内存空间,所以合适的缓冲区将会影响程序运行的效率。之前提到过,java中万物皆对象,那么缓冲区是否对应有对象呢,还真有,这就是下面要讲的BufferedInputStream类和BufferedOutputStream类;

这里写图片描述
  上面这幅图描绘了这两个类的作用,他们只是在程序与输出输入流中建立相应的缓冲区,此后程序读写文件都将与缓存区打交道,有了缓存区的加入,程序的相应效率就会变高。

下面是这两个类的用法,将相应的文件输入输出流作为构造函数的参数即可创建缓冲流对象

这里写图片描述

缓冲流的关闭
这里写图片描述
一旦相应的缓冲流被关闭,其对于的输入输出流也会被关闭,则不需要再去关闭输入输出流。


四.FileReader类与FileWriter类

  最开始我们说过,水流的对象是水,电流的对象是电子。对于IO流来说,数据可以分为字节和字符。前面所涉及到的类,无论读取还是写入的都是字节。但很多我们的工作时与文本文件有关的,使用字节的形式的效率并不高,这是我们希望IO流中流动的是字符,怎么办?

本小节索要讲的就是与字符流有关的类,这两个类分别从InputStream和OutputStream类继承而来的。

下面是具体用法
这里写图片描述

  这两个类也分别用于read和write方法,但是注意此时读取写入的就已经不是字节了(不需要byte数组),而是字符串形式(String)。
基于之前的讲解这里不进行单个方法的介绍。

注意:字符流与字节流的方法其实基本差不多,不同的那个方法readline指的是读取一行字符。特别特别要注意的是,这两个类只能处理纯文本内容,视频音频二进制文件是不能他们处理的。之所以存在这么两个类是因为,对于纯文本文件的操作来说字符流的确比字节流要高效。

五.InputStreamReader类和OutputStreamWriter类
这两个类用来将字节流转化为字符流。

  这一节的内容比较简单,当我们需要将字节流转换成字符流的时候可以使用这两个类的方法。在此之前我们需要了解一些小知识。

  计算机存储的最小单位是字节,计算机内部是不存在字符这种东西的,之所以我们可以看到屏幕上显示的数字字母汉字都是因为提前将相应的字节进行了编码,当需要显示的时候之需将其解码。那么这就一定涉及到某种编码方式了,学过C语言一定知道一个将ascii码的东西,其实编码不只这么一种,还有ASCC,ISO8859-1,GB2312,GBK,Unicode,UTF-8等,这里不讨论各种编码的不同之处,但是要记住的是以什么方式编码就应该以什么方式解码。

字符流转换成字节流的过程就是编码,字节流转化为字符流的过程就是解码。

具体用法,这里以GBK编码为准,实际编程应以实际情况为准。
这里写图片描述

  这时候的到InputStreamReader类对象inputStreamReader和OutputStreamWriter类的对象outputStreamWriter与FileReader与FileWriter类的对象的用法是一样的,这里不做详细介绍。

对象流
  通过前面的学习,各位对Java的IO流有了一定的了解,下面要介绍的内容是我觉得Java IO部分最炫酷的东西,那就是对象流,那么什么是对象流呢。

  我们都知道java实例出来的对象都存在于堆内存中,如果程序结束,对象就会消失。对于普通的数据来说,比如说字符串数字,我们可以把它写入文件中,下次要使用时只需重新读取文件即可,这样这些数据就得到了永久保存,那么对象是否也可以进行这样的操作呢,将对象写入文件中,下一次从文件中读取出这个对象继续使用它。答案是肯定的,java中存在一种序列化和反序列化的机制。
什么是序列化?
序列化是将内存中的对象转化为二进制流,存储在硬盘文件中
什么是反序列化?
序列化是将文件中的数据转化为对象,加载进内存。
这里写图片描述

我们先来看序列化的代码
这里写图片描述

再来看看反序列化的代码
这里写图片描述

  这两个类的使用对于看到现在的读者来说应该是非常熟悉了,他们与普通的文件流的区别在于,构建对象流的时候是以普通文件流作为参数的。而写入的操作,其参数是一个实例化了的对象。而读取的也是一个对象,野人需要一个对象引用来接受。

注意事项:
并不是每个类都可以被序列化,可以被序列化的类应该满足一下条件:

  1. 该类实现了Serializable接口
  2. 该类是所有成员变量都需要实现了Serializable接口

  以上两个条件缺一个都将导致序列化失败,同时不要被这个Serializable接口吓跑,我们来看看这个接口要我们实现什么吧。
这里写图片描述
什么都没有,开不开心,这个接口的实现更像是一种声明。


RandomAccessFile类
  前面所提到的类,都与在不同的文件中读写有关,下面要介绍的这个类则是专注于文件的内容,这个类就是RandomAccessFile类。首先从名字出发,这个类大概可以翻译为“随机访问文件”。随机的意思就是指可以访问文件的不同的位置,就如同我们修改word一样,我们的光标是可以随机移动的,而访问则代表着读写操作,文件指的是文件内容。一句话简述这个类的作用就是:可以在任何位置读写文件内容的类。有了以上的感性的认识将会有助于我们对该类的理解。

1.获取一个文件
这里写图片描述
  这个类的构造函数由两个参数,第一个是需要获取的文件路径,可以以字符串的形式传入,也可以使用前面讲到的File对象。第二个参数是打开方式,r是read的首字母,w是write的首字母。r代表以可读的方式打开,w以可写的方式打开,可以使用的打开模式有:

  • rw
    可读可写这样打开的文件,我们可以做写操作也可以做读操作。
  • r
    以只读的方式打开,这样打开问文件只能读而不能写
      特别要注意w不能单独作为打开模式,并且指定的模式不能超过文件所拥有的权限,也就是还说如果一个文件只可以读,那么就不能以rw的形式打开。

2.写方法
这里写图片描述
3.读方法

这里写图片描述

  其实读与写的方法远远不止这么一点,这里只是列举出来一些常用的方法,其他的方法可以在编程中阅读jdk源码得到。

  下面讲的一些方法和读写没有关系,但是确实非常重要的。

  首先我想在这里问一个问题,在前面的读写方法中,程序是如何直到每次是从哪里开始读写,读完以后,下次读写时又怎么知道上次读写的位置呢?这就涉及到文件指针的东西了。
这里写图片描述
  文件打开后,指针默认指向开头的位置,读和写的过程将会是文件指针向后移动一个单位,如图,如果读取一个字符,则最先读出的是a,然后文件指针向后移动一个单位,下次读的就是b。假如是写的话,则会将该位置原有的内容覆盖掉,然后向后移动一个位置,比如说我想写入1,则a就变成了1,而文件指针将会移动到b。
如何判断文件结尾呢。
  文件的结尾有一个特殊的标志,这个特殊的标志就是EOF,也就是end of file的缩写,意思就是文件结尾。当出现读取到了这个字符就会返回EOF或者-1,只要我们通过返回值就可以判断是否读取完毕。

  以上介绍的内容与下面的知识有关,既然我们开头说过了,该类可以随机的访问文件,可是通过现在的介绍,即使有了指针,指针也不过能向后移动而已,而且还是程序自己的行为,现在要说的是文件指针可以随便控制,达到随机读写的目的。
这里写图片描述

  通过这是三个方法就可以随意控制文件指针的位置了,同时这也是对文件内容操作的关键,并且切记不要超过文件的范围。

其他方法:
这里写图片描述

这一部分是后来补充的,之前竟然忘记了,现在终于完整了,图书馆外面下着雨,我还能再战一会

写在后面
  这篇博客自认为是自己所有博客中质量最高的了,因为恰好大学星期五的课不上很多,所以我有充足的时间来撰写着篇博客,我希望这篇博客可以高质量的记录我的学习过程,同时如果可以顺便帮助的有需要的同学,那我就更加开心了。

下一篇文章搜集了博主做过的面试题(不定期更新)