1. 什么是 I/O

java中 I/O 操作主要指使用 Java 进行输入,输出操作。Java所有的I/O 机制都是基于数据流进行输入输出,这些数据流表示了字符或者字节数据的流动序列。

Java的I/O 流提供了读写数据的标准方法。任何Java中表示数据源的对象都会提供以数据流的方式读写它的数据的方法。

Java.io 是大多数面向数据流的输入/输出类的主要软件包
此外,Java也对块传输提供支持,在核心库 java.nio 中采用的便是块 IO。

流IO 简单易用但效率较低。
块IO效率很高但编程比较复杂。

java IO模型:

java I/O 的设计使用到了 Decorator(装饰器)模式,按功能划分Stream, 您可以动态装配这些 Steam ,以获得您需要的功能。

比如,你需要一个具有缓冲的文件输入流,则应当组合使用FIleInputStream 和 BufferedInputStream。

2. 数据流的基本概念

数据流是一串连续不断的数据的集合,数据写入程序可以是一段、一段地向数据流管道中写入数据,这些数据段会按先后顺序形成一个长的数据流。

对数据读取程序来说,看不到数据流在写入时的分段情况,每次可以读取其中任意长度的数据,但只能先读取前面的数据后,再读取后面的数据。

不管写入时是将数据分多次写入,还是作为一个整体一次写入,读取时的效果都是完全一样的。

“ 流是磁盘或其他外围设备中存储的数据的源点或终点。”

在电脑上的数据有三种存储方式,一种是内存,一种是外存,一种是缓存

比如电脑上的硬盘,磁盘,U盘都是外存,在电脑上游内存条,缓存是在CPU里面的。

外存、内存、缓存的比较

存储量(依次递减); 外存 > 内存 > 缓存
  读取速度(依次递减),  缓存 > 内存 > 外存
	
对于内存和外存的理解,我们可以简单的理解为容器,即外存是一个容器,内存是另一个容器。
在 Java类库中,IO部分的内容是很庞大的,因为它涉及的领域很广泛:

标准输入输出, 文件的操作,网络上的数据流,字符串流,对象流,zip文件流等等,Java中将输入输出抽象称为流,就好像水管,将两个容器连接起来

将数据从外存中读取到内存中的称为输入流,将数据从内存写入外存中的称为输出流。

流是一个很形象的概念。

  • 当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数据源可以是文件,内存,或是网络连接
  • 类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流。

基本流:

一组有序,有起点和终点的字节的数据序列。包括输入流和输出流。

输入流:

程序从输入流读取数据源,数据源包括外界(键盘、文件、网络…)即是将数据源读入到程序的通信通道。

输出流:

程序向输出流写入数据,将程序中的数据输出到外界(显示器、打印机、文件、网络…)的通信通道。

为什么设计成数据流呢?
采用数据流的目的就是使得输出输入独立于设备,忽视设备种类的不同。

Input Stream 不关心数据来自何种设备(键盘,文件,网络)
Output Stream 不关心数据的目的是何种设备(键盘,文件,网络)

3. I/O 体系结构

java 接受输入的数 java的数据输入_Java


字节流: 后面是 Stream。

字符流: 后面是 Reader/Writer。

在整个Java.io包中最重要的是 5 个类和 1 个接口。

  • 五个类: File 、 OutputStream、 InputStream、 Writer、Reader;
  • 一个接口: Serializable.

3.1 Java I/O 层次——三个部分

  • 流式部分——I/O 的主体部分
  • 非流式部分 — 主要包含一些辅助流式部分的类, 如 File类,RandomAccessFile 类 和 FileDescriptor等类
  • 其他类—文件读取部分的与安全相关的类, 如 SerializablePermission类 ,以及与本地操作系统相关的文件系统的类,如 FileSystem类和 Win32FileSystem类和 WinNTFileSystem类。

3.1.1 流式部分主要类——I/O 主体类

Java中字符是采用Unicode 标准,一个字符是16位,即一个字符使用两个字节来表示。为此,Java中引入了处理字符的流。

  • 对文件进行操作
  • FileInputStream (字节输入流)
  • FIleOutputStream(字节输出流)
  • FileReader(字符输入流)
  • FileWriter(字符输出流)
  • 对管道进行操作
  • PipedInputStream(字节输入流)
  • PipedOutStram(字节输出流)
  • PipedReader(字符输入流)
  • PipedWriter(字符输出流)
    PipedInputStream的一个实例要和 PipedOutputStream的一个实例共同使用,共同完成写入操作,主要用于线程操作。
  • 字节/字符数组——在内存中开辟一个字节或字符数组
  • ByteArrayInputStream
  • ByteArrayOutputSteam
  • CharArrayReader
  • CharArrayWriter
  • Buffered缓冲流:
  • BufferedInputStream
  • BufferedOutputStream
  • BufferedReader
  • BufferedWriter
    是带缓冲区的处理流,缓冲区的作用是避免每次和硬盘打交道,提高数据访问的效率
  • 转化流
  • InputStreamReaderr
  • OutputStreamWriter
    把字节转化成字符
  • 数据流
  • DataInputStream,
  • DataOutputStream
  • 因为我们若是我们平时输出一个 8 个字节的 long类型或 4 个字节的 float 类型,可以一个字节一个字节输出,也可以转换成字符串输出,但是这样转换浪费时间。
    数据流可以直接输出 float 类型或 long类型,提高了数据读写的效率。
  • 打印流:
  • printStream
  • printWriter
    一般是打印到控制台,可以进行控制打印的地方。
  • 对象流:
  • ObjectInputStream
  • ObjectOutputStream
    把封装的对象直接输出,而不是一个个再转换成字符串再输出。
  • 序列化流:
  • SequenceInputStream
    对象序列化,把对象直接转换成二进制,写入介质中。

3.1.2 非流式部分主要类:

File类 (文件特征与管理): 用于文件或者目录的描述信息,例如生成新目录,修改文件名,删除文件,判断文件所在路径等。

在Java.io 包中, 由File 类提供了描述文件和目录的操作和管理办法。

但File 类不是 InputStream 、 OutputStream 或 Reader、Writer的子类,因为它不负责数据的输入输出,而专门用来管理磁盘文件与目录。

作用: File 类主要用于命名文件、查询文件属性和处理文件目录。

  • File类的构造函数

(1)File ( String pathname )

例: File f1 = new File("FileText1.txt"); //创建了一个文件对象 f1, f1 所指的文件是在当前目录下(默认目录,因为没有给绝对路径)下创建的FileTest1.txt。

(2)File (URI uri)
(3)File (String parent, String child)

例: File f2 = new File(" D:\\ dir1" , " FielTest2.txt") " // 注意 D:\\ dir1 目录必须提前定义好,否则异常。

(4)File (File parent , String child)

例: File f4 = new File(" E:\\ dir3");
	 File f5 = new File(f4, " FileTest5.txt"); //在如果 E: \\dir3 目录,则需要使用 f4.mkdir() 先创建。

一个对应于某磁盘文件或目录的File 对象一经创建,就可以通过调用它的方法来获得文件或目录的属性。

1)public boolean exists( ) 判断文件或目录是否存在
   2)public boolean isFile( ) 判断是文件还是目录 
   3)public boolean isDirectory( ) 判断是文件还是目录
   4)public String getName( ) 返回文件名或目录名
   5)public String getPath( ) 返回文件或目录的路径。
   6)public long length( ) 获取文件的长度 
   7)public String[ ] list ( ) 将目录中所有文件名和目录名保存在字符串数组中返回。 
   8)public File[] listFiles() 返回某个目录下所有文件和目录的绝对路径,返回的是File数组
   9)public String getAbsolutePath() 返回文件或目录的绝对路径
   ....
   File类中还定义了一些对文件或目录进行管理、操作的方法,常用的方法有:
   1) public boolean renameTo( File newFile );    重命名文件
 
   2) public void delete( );   删除文件
 
   3) public boolean mkdir( ); 创建目录
 
   4)public boolean createNewFile(); 创建文件

例子: 输出一个目录的所有文件名(目录可能是多级目录,如 a 目录中有 b、c目录。。。)
——FileUtils.java——

public class FileUtils {
 
    public static void listDir(String dir) throws IOException {
        File file = new File(dir);
        //传进来的可能不是一个目录
        if (!file.isDirectory()) {
            throw new IOException(dir+"不是目录");
        }
        //传进来的可能是一个错误的路径
        if (file == null) {
            throw new IOException("没有此路径");
        }
        File[] files = file.listFiles();
        for (File f : files) {
            //有可能是一个多级目录,递归调用
            if (f.isDirectory()) {
                listDir(f.getAbsolutePath());
                //是文件就直接输出该文件的绝对路径
            }else {
                System.out.println(f.getAbsolutePath());
            }
        }
    }
}

——Main.java——

public class Main {
 
    public static void main(String[] args) throws IOException {
        FileUtils.listDir("E:\\ssh");
    }
}