Java的IO(Input/Output)是一个非常庞大和重要的主题,在任何一个Java程序中都会涉及到IO操作。IO操作是指程序与外部设备之间进行数据传输的过程,例如读取文件、发送网络请求、输出日志等等。

Java的IO操作可以分为两种类型:字节流和字符流。字节流是以字节为单位进行数据传输的操作,适用于处理二进制数据(如图像、音频、视频等)。而字符流是以字符为单位进行数据传输的操作,适用于处理文本数据(如文本文件、配置文件等)。

Java的IO操作为程序提供了灵活、丰富的数据传输方式,它包含了很多类和接口,可以实现各种不同的IO功能。本文将围绕Java的IO操作展开,全面详细地介绍Java中的IO机制。

一、字节流

字节流(Byte Stream)是Java中最基本的IO操作,它以字节为单位进行数据传输,可以用于处理二进制数据(如图像、音视频等)。Java中的字节流主要有两个抽象类:InputStream和OutputStream,它们是所有字节流的父类,提供了最基本的读取和写入功能。

  1. InputStream

InputStream是Java中所有字节输入流的父类,它定义了一些抽象方法,可以读取不同来源的字节数据,例如读取文件、读取网络数据、读取内存数据等。InputStream的主要方法如下:

public abstract int read() throws IOException;
public int read(byte[] b) throws IOException;
public int read(byte[] b, int off, int len) throws IOException;
public long skip(long n) throws IOException;
public int available() throws IOException;
public void close() throws IOException;
public void mark(int readlimit);
public void reset() throws IOException;
public boolean markSupported();

其中,read方法用于从输入流中读取一个字节的数据,并返回读取到的字节,如果已经到达流的末尾,则返回-1。read(byte[] b)和read(byte[] b, int off, int len)方法用于从输入流中读取指定长度的字节数据,并存储到byte数组中。skip方法用于跳过指定数量的字节数据。available方法用于返回可以从输入流中读取的剩余字节数。close方法用于关闭输入流并释放系统资源。mark和reset方法用于在输入流中标记和重置位置。markSupported方法用于判断当前输入流是否支持标记和重置操作。

  1. OutputStream

OutputStream是Java中所有字节输出流的父类,它定义了一些抽象方法,可以将字节数据写入到不同的目的地,例如写入文件、写入网络数据、写入内存数据等。OutputStream的主要方法如下:

public abstract void write(int b) throws IOException;
public void write(byte[] b) throws IOException;
public void write(byte[] b, int off, int len) throws IOException;
public void flush() throws IOException;
public void close() throws IOException;

其中,write方法用于将一个字节的数据写入输出流中。write(byte[] b)和write(byte[] b, int off, int len)方法用于从输出流中写入指定长度的字节数据,它们都是阻塞的方法,直到所有数据写入完成或者发生错误才会返回。flush方法用于强制将输出流中的数据写入目的地,而不是缓存在内存中等待下一次输出。close方法用于关闭输出流并释放系统资源。

  1. FileInputStream

FileInputStream是InputStream的子类,用于读取文件中的字节数据。FileInputStream的构造函数如下:

public FileInputStream(File file) throws FileNotFoundException;
public FileInputStream(String name) throws FileNotFoundException;
public FileInputStream(FileDescriptor fdObj);

其中,第一个构造函数用于创建一个与指定文件关联的FileInputStream对象,如果文件不存在则会抛出FileNotFoundException异常;第二个构造函数用于创建一个与指定文件名关联的FileInputStream对象,如果文件不存在也会抛出FileNotFoundException异常;第三个构造函数用于创建一个与指定文件描述符关联的FileInputStream对象。

FileInputStream的主要方法都是继承自InputStream,可以使用read、available、close等方法对文件进行读取和操作。

  1. FileOutputStream

FileOutputStream是OutputStream的子类,用于将字节数据写入到指定的文件中。FileOutputStream的构造函数如下:

public FileOutputStream(File file) throws FileNotFoundException;
public FileOutputStream(File file, boolean append) throws FileNotFoundException;
public FileOutputStream(String name) throws FileNotFoundException;
public FileOutputStream(String name, boolean append) throws FileNotFoundException;
public FileOutputStream(FileDescriptor fdObj);

其中,第一个构造函数用于创建一个与指定文件关联的FileOutputStream对象,如果文件不存在则会创建一个新文件,如果文件已经存在则会覆盖原有内容;第二个构造函数与第一个构造函数类似,但是可以指定是否在文件尾添加数据。第三个和第四个构造函数分别是以文件名为参数进行创建的,与前两个构造函数功能基本相同。

FileOutputStream的主要方法都是继承自OutputStream,可以使用write、flush、close等方法对文件进行操作和写入。

  1. ByteArrayInputStream

ByteArrayInputStream是InputStream的子类,可以将内存中的字节数组作为输入流来处理数据。ByteArrayInputStream的构造函数如下:

public ByteArrayInputStream(byte[] buf);
public ByteArrayInputStream(byte[] buf, int offset, int length);

其中,第一个构造函数用于创建一个新的ByteArrayInputStream对象,使用指定的字节数组作为输入源;第二个构造函数用于创建一个新的ByteArrayInputStream对象,使用指定的字节数组的一部分作为输入源。

ByteArrayInputStream的主要方法都是继承自InputStream,可以使用read、available、close等方法对字节数组进行读取和操作。

  1. ByteArrayOutputStream

ByteArrayOutputStream是OutputStream的子类,可以将输出流中的字节数据存储到内存中的一个字节数组中。ByteArrayOutputStream的构造函数如下:

public ByteArrayOutputStream();
public ByteArrayOutputStream(int size);

其中,第一个构造函数用于创建一个新的ByteArrayOutputStream对象,初始缓冲区大小为32个字节;第二个构造函数用于指定初始缓冲区大小。

ByteArrayOutputStream的主要方法都是继承自OutputStream,可以使用write、toByteArray、size等方法对字节数组进行操作和输出。

二、字符流

字符流(Character Stream)是Java中另一种重要的IO操作,它以字符为单位进行数据传输,可以用于处理文本数据(如文本文件、配置文件等)。Java中的字符流主要有两个抽象类:Reader和Writer,它们是所有字符流的父类,提供了最基本的读取和写入功能。

  1. Reader

Reader是Java中所有字符输入流的父类,它定义了一些抽象方法,可以读取不同来源的字符数据,例如读取文件、读取网络数据、读取内存数据等。Reader的主要方法如下:

public abstract int read() throws IOException;
public int read(char[] cbuf) throws IOException;
public int read(char[] cbuf, int off, int len) throws IOException;
public long skip(long n) throws IOException;
public boolean ready() throws IOException;
public boolean markSupported() ;
public void mark(int readAheadLimit) throws IOException;
public void reset() throws IOException;
public void close() throws IOException;

其中,read方法用于从输入流中读取一个字符的数据,并返回读取到的字符,如果已经到达流的末尾,则返回-1。read(char[] cbuf)和read(char[] cbuf, int off, int len)方法用于从输入流中读取指定长度的字符数据,并存储到char数组中。skip方法用于跳过指定数量的字符数据。ready方法用于测试输入流是否准备好进行读取。mark和reset方法用于在输入流中标记和重置位置。markSupported方法用于判断当前输入流是否支持标记和重置操作。

  1. Writer

Writer是Java中所有字符输出流的父类,它定义了一些抽象方法,可以将字符数据写入到不同的目的地,例如写入文件、写入网络数据、写入内存数据等。Writer的主要方法如下:

public abstract void write(int c) throws IOException;
public void write(char[] cbuf) throws IOException;
public void write(char[] cbuf, int off, int len) throws IOException;
public void write(String str) throws IOException;
public void write(String str, int off, int len) throws IOException;
public void flush() throws IOException;
public void close() throws IOException;
  1. FileReader

FileReader是Reader的子类,用于读取文件中的字符数据。FileReader的构造函数如下:

public FileReader(File file) throws FileNotFoundException;
public FileReader(String fileName) throws FileNotFoundException;

其中,第一个构造函数用于创建一个与指定文件关联的FileReader对象,如果文件不存在则会抛出FileNotFoundException异常;第二个构造函数用于创建一个与指定文件名关联的FileReader对象,如果文件不存在也会抛出FileNotFoundException异常。

FileReader的主要方法都是继承自Reader,可以使用read、close等方法对文件进行读取和操作。

  1. FileWriter

FileWriter是Writer的子类,用于将字符数据写入到指定的文件中。FileWriter的构造函数如下:

public FileWriter(File file) throws IOException;
public FileWriter(File file, boolean append) throws IOException;
public FileWriter(String fileName) throws IOException;
public FileWriter(String fileName, boolean append) throws IOException;

其中,第一个构造函数用于创建一个与指定文件关联的FileWriter对象,如果文件不存在则会创建一个新文件,如果文件已经存在则会覆盖原有内容;第二个构造函数与第一个构造函数类似,但是可以指定是否在文件尾添加数据。第三个和第四个构造函数分别是以文件名为参数进行创建的,与前两个构造函数功能基本相同。

FileWriter的主要方法都是继承自Writer,可以使用write、flush、close等方法对文件进行操作和写入。

  1. CharArrayReader

CharArrayReader是Reader的子类,可以将内存中的字符数组作为输入流来处理数据。CharArrayReader的构造函数如下:

public CharArrayReader(char[] buf);
public CharArrayReader(char[] buf, int offset, int length);

其中,第一个构造函数用于创建一个新的CharArrayReader对象,使用指定的字符数组作为输入源;第二个构造函数用于创建一个新的CharArrayReader对象,使用指定的字符数组的一部分作为输入源。

CharArrayReader的主要方法都是继承自Reader,可以使用read、close等方法对字符数组进行读取和操作。

  1. CharArrayWriter

CharArrayWriter是Writer的子类,可以将输出流中的字符数据存储到内存中的一个字符数组中。CharArrayWriter的构造函数如下:

public CharArrayWriter();
public CharArrayWriter(int initialSize);

其中,第一个构造函数用于创建一个新的CharArrayWriter对象,初始缓冲区大小为32个字符;第二个构造函数用于指定初始缓冲区大小。

CharArrayWriter的主要方法都是继承自Writer,可以使用write、toCharArray、size等方法对字符数组进行操作和输出。

三、转换流

转换流(InputStreamReader和OutputStreamWriter)是一种将字节流和字符流相互转换的机制,它们可以使得字节流按照指定的编码格式转换为字符流,或者将字符流按照指定的编码格式转换为字节流。转换流通常使用在需要处理文本文件的场景下,可以方便地完成文件编码的转换。

  1. InputStreamReader

InputStreamReader是一个包装类,可以将字节输入流转换为字符输入流。它的构造函数如下:

public InputStreamReader(InputStream in);
public InputStreamReader(InputStream in, String charsetName) throws UnsupportedEncodingException;

其中,第一个构造函数用于创建一个新的InputStreamReader对象,使用指定的字节输入流作为输入源;第二个构造函数用于指定输入流的字符编码格式,这样可以确保读取到正确的字符数据类型。

InputStreamReader的主要方法都是继承自Reader,可以使用read、close等方法对输入流进行操作和读取。

  1. OutputStreamWriter

OutputStreamWriter是一个包装类,可以将字节输出流转换为字符输出流。它的构造函数如下:

public OutputStreamWriter(OutputStream out);
public OutputStreamWriter(OutputStream out, String charsetName) throws UnsupportedEncodingException;

其中,第一个构造函数用于创建一个新的OutputStreamWriter对象,使用指定的字节输出流作为输出目的地;第二个构造函数用于指定输出流的字符编码格式,这样可以确保写入的字符数据类型正确。

OutputStreamWriter的主要方法都是继承自Writer,可以使用write、flush、close等方法对输出流进行操作和写入。

四、缓冲流

缓冲流(BufferedInputStream和BufferedOutputStream)是一种在字节流的基础上增加缓冲功能的机制,可以提高数据传输的速度。缓冲流一般用于读取和写入大文件时,可以减少IO操作的次数,从而提高性能。

  1. BufferedInputStream

BufferedInputStream是一个包装类,可以将字节输入流包装成带缓冲的输入流。它的构造函数如下:

public BufferedInputStream(InputStream in);
public BufferedInputStream(InputStream in, int size);

其中,第一个构造函数用于创建一个新的BufferedInputStream对象,使用指定的字节输入流作为输入源;第二个构造函数用于指定输入流的缓冲区大小,这样可以提高读取数据的效率。

BufferedInputStream的主要方法都是继承自InputStream,可以使用read、available、close等方法对输入流进行操作和读取。

  1. BufferedOutputStream

BufferedOutputStream是一个包装类,可以将字节输出流包装成带缓冲的输出流。它的构造函数如下:

public BufferedOutputStream(OutputStream out);
public BufferedOutputStream(OutputStream out, int size);

其中,第一个构造函数用于创建一个新的BufferedOutputStream对象,使用指定的字节输出流作为输出目的地;第二个构造函数用于指定输出流的缓冲区大小,这样可以提高写入数据的效率。

BufferedOutputStream的主要方法都是继承自OutputStream,可以使用write、flush、close等方法对输出流进行操作和写入。

五、总结

Java的IO操作非常庞大和重要,涉及到字节流、字符流、转换流、缓冲流等多种机制和类。这些IO操作可以实现各种不同的数据传输功能,包括读取文件、写入网络请求、输出日志等等。掌握Java的IO机制对于Java程序员来说至关重要,需要深入学习和理解其中的各种类和方法,才能更加熟练地使用它们来处理数据。