文章目录
Java中的IO
Java中的IO是一种用于读写文件、网络连接数据等功能的I/O(输入/输出)系统。它主要由java.io包提供,并且功能丰富,支持各种文件格式和网络协议。
在Java中,可以使用字节流和字符流来读写数据。字节流以字节为单位读写数据,而字符流以字符为单位读写数据,并且支持 Unicode 字符编码。Java中的I/O流可以分为输入流和输出流两种,输入流用于从文件或其他数据源读取数据,而输出流用于将数据写入文件或其他数据接收端。
Java IO 流的 40 多个类都是从如下 4 个抽象类基类中派生出来的。
InputStream
/Reader
: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。OutputStream
/Writer
: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
Java中的常用I/O类包括
File、FileReader、FileWriter、BufferedReader、InputStreamReader、PrintStream
等。例如,使用File
类可以方便地创建、删除或重命名文件和目录;BufferedReader
可以提高读取文件的效率;PrintStream
则可以将数据直接输出到控制台或文件中。
使用File创建的对象只可以获取计算机硬盘上的文件信息或者目录,创建文件,删除文件但是不能对文件中的数据进行操作
File常用方法
//通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
File fi = new File("C:\\Users\\qq\\Desktop\\demo.txt");
System.out.println(fi.canExecute());
System.out.println(fi.canRead())
System.out.println(fi.canWrite());
System.out.println(fi.exists());//文件是否存在
System.out.println("-----------------------------------------");
System.out.println(fi.getAbsoluteFile() );//返回此抽象路径名的绝对形式。
System.out.println(fi.getAbsolutePath() );//返回此抽象路径名的绝对路径名字符串
System.out.println(fi.getParentFile() );//返回此抽象路径名的父,或抽象路径名 null如果此路径名没有指定父目录
System.out.println(fi.getName());//返回由此抽象路径名表示的文件或目录的名称
System.out.println(fi.getParent());//返回此抽象路径名的父 null的路径名字符串,如果此路径名未命名为父目录,则返回null
System.out.println("------------------------------------------");
System.out.println(fi.isAbsolute());//路径名是否是绝对的
System.out.println(fi.isDirectory());//是否为目录/文件夹
System.out.println(fi.isFile());//是否为普通文件
System.out.println(fi.isHidden());//是否为隐藏文件
System.out.println("--------------------------------------------");
System.out.println(new Date(fi.lastModified()));//最后修改时间
System.out.println(fi.length());//文件内容长度
fi.mkdir();//创建单级文件夹
fi.mkdirs();//创建多级文件夹
fi.createNewFile();//创建一个文件
IO即Input/Output,也就是输入和输出。数据输入到计算机的过程,就是输入,反之输出到外部存储(数据库,文件,远程主机)的过程为输出。数据传输过程类似与水流,因此称为IO流。数据处理的方式分为字节流和字符流。
JavaIO流的40多个类都是从如下四个抽象类中派生出来的,
InputStream/Reader
: 所有的输入流的基类,前者是字节输入流,后者是字符输入流OutputStream/Writer
: 所有输出流的基类,前者是字节输出流,后者是字符输出流
InputStream(字节输入流)
用于从源头(通常是文件)读取数据(字节信息)到内存中,java.io.InputStream抽象类是所有字节输入流的父类
InputStream常用方法:
- read(),read(byte b[]), read(byte b[], int off, int len), skip(long n), available(), close(),
从Java9开始,InputStream新增了多个实用方法:
- readAllBytes(), readNBytes(byte[] b, int off, int len), transferTo(OutputStream out),
FileInputStream是一个比较常见的字节输入流对象,可直接指定文件路径,可以直接读取单字节数据,也可以读取至字节数组中。
FileInputStream通常配合BufferedInputStream(字节缓冲输入流)使用
- 通过readAllBytes()读取输入流所有字节并将其直接赋值给一个String对象。
DataInputStream
用于读取指定类型数据,不能单独使用,必须结合FileInputStream
//使用方式
FileInputStream fileInputStream = new FileInputStream("input.txt");
//必须将fileInputStream作为构造参数才能使用
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
//可以读取任意具体的类型数据
dataInputStream.readBoolean();
dataInputStream.readInt();
dataInputStream.readUTF();
ObjectInputStream
用于从输入流中读取 Java 对象(反序列化),ObjectOutputStream
用于将对象写入到输出流(序列化)。
OutputStream(字节输出流)
OutputStream
用于将数据(字节信息)写入到目的地(通常是文件),java.io.OutputStream
抽象类是所有字节输出流的父类
OutputStream
常用方法:
- write(int b), write(byte b[ ]), write(byte[] b, int off, int len), flush(), close(),
FileOutputStream
是最常见的字节输出流对象,可以直接指定文件路径,可以直接输出单字节数据,也可以输出指定的字节数组。
类似于 FileInputStream
,FileOutputStream
通常也会配合 BufferedOutputStream
(字节缓冲输出流)来使用。
FileOutputStream fileOutputStream = new FileOutputStream("output.txt");
BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream)
DataOutputStream 用于写入指定类型数据,不能单独使用,必须结合 FileOutputStream
// 输出流
FileOutputStream fileOutputStream = new FileOutputStream("out.txt");
DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
// 输出任意数据类型
dataOutputStream.writeBoolean(true);
dataOutputStream.writeByte(1);
ObjectInputStream
用于从输入流中读取 Java 对象(ObjectInputStream
,反序列化)ObjectOutputStream
将对象写入到输出流(ObjectOutputStream
,序列化)。
为什么I/O流操作要分为字节流操作和字符流操作?
字节流操作是以字节为基本单位进行操作的,在数据传输过程中,不考虑字符编码和字符集,只是简单地传输二进制数据。因此,字节流操作适用于任何类型的数据,包括图片、声音、视频等二进制文件,以及文本文件等。但是在处理文本数据时需要做字符编码和字符集的转换,如果操作不当,就可能会出现乱码等问题。
而字符流操作是以字符为基本单位进行操作的,会考虑字符编码和字符集的影响。不同的字符编码会导致不同的字节序列表示同一个字符,因此使用字符流操作可以更好地处理字符数据,如文本文件等。
Reader(字符输入流)
Reader
用于从源头(通常是文件)读取数据(字符信息)到内存中,java.io.Reader
抽象类是所有字符输入流的父类。
Reader
用于读取文本, InputStream
用于读取原始字节。
Reader
常用方法:
read()
: 从输入流读取一个字符。read(char[] cbuf)
: 从输入流中读取一些字符,并将它们存储到字符数组cbuf
中,等价于read(cbuf, 0, cbuf.length)
。read(char[] cbuf, int off, int len)
:在read(char[] cbuf)
方法的基础上增加了off
参数(偏移量)和len
参数(要读取的最大字符数)。skip(long n)
:忽略输入流中的 n 个字符 ,返回实际忽略的字符数。close()
: 关闭输入流并释放相关的系统资源。
InputStreamReader
是字节流转换为字符流的桥梁,其子类 FileReader
是基于该基础上的封装,可以直接操作字符文件。
Writer(字符输出流)
Writer
用于将数据(字符信息)写入到目的地(通常是文件),java.io.Writer
抽象类是所有字符输出流的父类。
Writer
常用方法:
write(int c)
: 写入单个字符。write(char[] cbuf)
:写入字符数组cbuf
,等价于write(cbuf, 0, cbuf.length)
。write(char[] cbuf, int off, int len)
:在write(char[] cbuf)
方法的基础上增加了off
参数(偏移量)和len
参数(要读取的最大字符数)。write(String str)
:写入字符串,等价于write(str, 0, str.length())
。write(String str, int off, int len)
:在write(String str)
方法的基础上增加了off
参数(偏移量)和len
参数(要读取的最大字符数)。append(CharSequence csq)
:将指定的字符序列附加到指定的Writer
对象并返回该Writer
对象。append(char c)
:将指定的字符附加到指定的Writer
对象并返回该Writer
对象。flush()
:刷新此输出流并强制写出所有缓冲的输出字符。close()
:关闭输出流释放相关的系统资源。
OutputStreamWriter
是字符流转换为字节流的桥梁,其子类 FileWriter
是基于该基础上的封装,可以直接将字符写入到文件。
字节缓冲流
字节缓冲流是以字节为单位读写数据,它们内部维护了一个缓冲区,从而能够提高IO操作的效率。
当我们使用
BufferedInputStream
读取数据时,它不会一个字节一个字节读取,它会一次性从底层InputStream
中读取一部分数据到内部缓存中,并从内部缓存中单独读取字节,这样可以减少访问磁盘的次数,提高读取效率。
BufferedInputStream
内部维护了一个缓冲区,这个缓冲区实际就是一个字节数组。
使用
BufferedOutputStream
写入数据时,它不会一个字节一个字节的写入,它也会将数据缓存到内部的缓存区中,等到缓冲区满了之后从内部缓冲区中单独写入字节。这样可以减少写入操作的次数,提高写入效率。
字符缓冲流
字符缓冲流(字符缓冲输入/输出流) 类似于字节缓冲流,内部都维护了一个字节数组作为缓冲区。不过字符缓冲流主要是用来操作字符信息。
字符缓冲流是以字符为单位读写数据,它们同样也内部维护了一个缓冲区。
BufferedReader
和BufferedWriter
在读写数据时都会使用内部缓存区,从而减少IO操作次数,提高读写效率。当使用BufferedReader
读取数据时,它会一次性读取一定量的字符到缓冲区中,然后逐个读取,直到缓冲区中数据全部读取完毕,这样可以减少访问数据源的次数提高读入效率。当BufferedWriter
写数据时,它的操作类似,会先将数据写入缓冲区,等到缓冲区写满之后再一次性写出到目标文件中,这样可以减少写操作次数,提高写入效率。
打印流
System.out.print("Hello!");
System.out.println("Hello!");
System.out
实际是用于获取一个PrintStream
对象,PrintStream
对象的write
方法。
PrintStream
属于字节打印流,与之对应的是PrintWriter
(字符打印流)。PrintStream
是OutputStream
的子类,PrintWriter
是Writer
的子类。