Java-IO,IO流,数据即是水流

Java-IO,IO流,数据即是水流
Arjen时人不识凌云木,直待凌云始道高
什么是IO
把数据的传输,可以看做是一种数据的流动,按照流动的方向,以内存为基准,分为输入input 和输出output ,即流向内存是输入流,流出内存的输出流。
Java中I/O操作主要是指使用java.io包下的内容,进行输入、输出操作。输入也叫做读取数据,输出也叫做作写出数据。
IO的分类
根据数据的流向分为:输入流和输出流。
- 输入流 :把数据从
其他设备上读取到内存中的流。 - 输出流 :把数据从
内存中写出到其他设备上的流。
格局数据的类型分为:字节流和字符流。
- 字节流 :以字节为单位,读写数据的流。
- 字符流 :以字符为单位,读写数据的流。
顶级父类
| 输入流 | 输出流 | |
|---|---|---|
| 字节流 | 字节输入流 InputStream | 字节输出流 OutputStream |
| 字符流 | 字符输入流 Reader | 字符输出流 Writer |
字节流
一切皆为字节
一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。文件字节输出流 FileOutputStream
java.io.FileOutputStream 类是文件输出流,用于将数据写出到文件。1 | package io; |
写数据的三种方式
1 | package io; |
写入数据的三个问题
换行写、续写1 | package io; |
文件字节输入流 FileInputStream
java.io.InputStream 抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。
public void close():关闭此输入流并释放与此流相关联的任何系统资源。public abstract int read(): 从输入流读取数据的下一个字节。public int read(byte[] b): 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。
1 | package io; |
文件拷贝1.0
1 | package io; |
一次读多个字节
注意:一次读取多个字节的数据(字节数组),当读取的数据不能填满字节数组的时候,就会出现错误
错误是:当字节数组读不满发生时,字节数组中的内容仍是上一次读满的数据,然后最后一次读不满的情况发生时,会将只读取一部分的数据替换到字节数组中,字节数组这时就变成了:最后一次读的部分数据+上一次读的未被覆盖的部分数据
细节:fis.read()方法 返回的是-1和读到的数据
而fis.read(bytes)方法 返回的是-1和读到的数据个数
其中-1都表示未读到数据
1 | package io; |
文件拷贝2.0
1 | package io; |
异常处理
IO异常的处理
之前一直把异常抛出,而实际开发中并不能这样处理,建议使用`try...catch...finally` 代码块,处理异常部分,代码使用演示:1 | public class HandleException1 { |
字符集
GBK
为了区分英文和中文的二进制编码,所以高位字节一定是以1开头
Unicode
为了节省空间,使用UTF-8编码方式
乱码
编码与解码
字符流
文件字符输入流 FileReader
1 | package io; |
1 | package io; |
原理解析
创建字符输入流对象的时候,底层会关联文件,并创建缓冲区(长度为8192的字节数组)
字符流也有缓冲区,read()先到缓冲区中判断是否有数据、读取数据,如果没有,就会从文件中读取数据,尽可能装满缓冲区,然后再从缓冲区中读取数据
缓冲区最多存放8192字节的数据,当读完缓冲区中的数据,会再去文件中获取数据覆盖到缓冲区
文件字符输出流 FileWriter
原理解析
拥有缓冲区,将数据写入到缓冲区- 当缓冲区写满,自动保存到目的地
- 当刷新的时候,会将缓冲区的数据写入目的地
- 当关流的时候,会将缓冲区的数据写入目的地
综合练习
拷贝文件夹
1 | public class Test01 { |
文件加密
1 | public class Test02 { |
数字排序
文本文件中有以下的数据: 2-1-9-4-7-8
将文件中的数据进行排序,变成以下的数据:
1-2-4-7-8-9
1 | public class Test03 { |
1 | public class Test04 { |
缓冲流
字节缓冲流
读写数据仍然用到基本流,缓冲流提高了读写效率默认缓冲区的大小是8192字节
不需要关闭基本流的原因是:缓冲流底层会关闭基本流
1 | // 一次读写一个字节 |
1 | // 一次读写一个字节数组 |
字节缓冲流提高效率的原理
缓冲区中的数据在内存中操作的时间非常快,节约了数据从硬盘到内存的时间
字符缓冲流
字符流底层自带了长度为8192的字符数组缓冲区提高性能,16KB
readLine()方法读取的时候,一次读取一整行,遇到回车换行结束,不会将回车读到内存当中
1 | package io; |
转换流
jdk11之前指定字符集需要用到转换流,jdk11以后字符流可以创建对象指定字符集
转换流java.io.InputStreamReader,是Reader的子类,是从字节流到字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。
在IDEA中,使用FileReader 读取项目中的文本文件。由于IDEA的设置,都是默认的UTF-8编码,所以没有任何问题。但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码。
作用:
- 字节流想要使用字符流中的方法
构造方法:
InputStreamReader(InputStream in): 创建一个使用默认字符集的字符流。
InputStreamReader(InputStream in, String charsetName): 创建一个指定字符集的字符流。
细节:
指定字符集淘汰(JDK11以后出现了替代方法),JDK11以后字符流创建对象的时候可以指定字符集,Reader和Writer相同
1 | public class ReaderDemo2 { |
将GBK编码的文本文件,转换为UTF-8编码的文本文件。
- 指定GBK编码的转换流,读取文本文件。
- 使用UTF-8编码的转换流,写出文本文件。
1 | public class TransDemo { |
序列/反序列化流
序列化流
Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的类型和对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。对象的数据、对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象。
一个对象要想序列化,必须满足两个条件:
- 该类必须实现
java.io.Serializable接口,Serializable是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException。 - 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用
transient关键字修饰。
1 | package io; |
反序列化
1 | package io; |
反序列化流
1 | package io; |
当序列化一个对象时,将Java进行修改,反序列化这个对象的时候,就会出现一个版本号报错。真实业务场景中,需求发生变更,需要修改javabean类,此时需要固定版本号。
打印流
平时我们在控制台打印输出,是调用print方法和println方法完成的,这两个方法都来自于java.io.PrintStream类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式。
字节打印流
字符打印流
打印流与System.out.println()关系
System是一个最终类,没有子类 .out是获取的打印流的对象,默认指向控制台System.out就是PrintStream类型的,只不过它的流向是系统规定的,打印在控制台上。不过,既然是流对象,我们就可以玩一个”小把戏”,改变它的流向。
1 | public class PrintDemo { |
解压缩流/压缩流
解压缩流
压缩包中的每一个文件都是一个ZipEntry对象
解压的本质:就是把每一个ZipEntry按照层级拷贝到本地另一个文件夹中
1 | public class ZipStreamDemo1 { |
压缩流
压缩的本质是:将每一个文件、文件夹看成一个ZipEntry对象放到压缩包中1 | public class ZipStreamDemo2 { |
1 | public class ZipStreamDemo3 { |
Commons-io
Commons是apache开源基金组织提供的工具包,里面有很多帮助我们提高开发效率的API比如:
StringUtils 字符串工具类
NumberUtils 数字工具类
ArrayUtils 数组工具类
RandomUtils 随机数工具类
DateUtils 日期工具类
StopWatch 秒表工具类
ClassUtils 反射工具类
SystemUtils 系统工具类
MapUtils 集合工具类
Beanutils bean工具类
Commons-io io的工具类
等等.....
使用方式:
- 新建lib文件夹
- 把第三方jar包粘贴到文件夹中
- 右键点击add as a library
IOUtils(数据相关)
拷贝方法:
copy方法有多个重载方法,满足不同的输入输出流IOUtils.copy(InputStream input, OutputStream output)
IOUtils.copy(InputStream input, OutputStream output, int bufferSize)//可指定缓冲区大小
IOUtils.copy(InputStream input, Writer output, String inputEncoding)//可指定输入流的编码表
IOUtils.copy(Reader input, Writer output)
IOUtils.copy(Reader input, OutputStream output, String outputEncoding)//可指定输出流的编码表
拷贝大文件的方法:
这个方法适合拷贝较大的数据流,比如2G以上
IOUtils.copyLarge(Reader input, Writer output) // 默认会用1024*4的buffer来读取
IOUtils.copyLarge(Reader input, Writer output, char[] buffer)//可指定缓冲区大小
将输入流转换成字符串
IOUtils.toString(Reader input)IOUtils.toString(byte[] input, String encoding)
IOUtils.toString(InputStream input, Charset encoding)
IOUtils.toString(InputStream input, String encoding)
IOUtils.toString(URI uri, String encoding)
IOUtils.toString(URL url, String encoding)
将输入流转换成字符数组
IOUtils.toByteArray(InputStream input)
IOUtils.toByteArray(InputStream input, int size)
IOUtils.toByteArray(URI uri)
IOUtils.toByteArray(URL url)
IOUtils.toByteArray(URLConnection urlConn)
IOUtils.toByteArray(Reader input, String encoding)
字符串读写
IOUtils.readLines(Reader input)
IOUtils.readLines(InputStream input, Charset encoding)
IOUtils.readLines(InputStream input, String encoding)
IOUtils.writeLines(Collection<?> lines, String lineEnding, Writer writer)
IOUtils.writeLines(Collection<?> lines, String lineEnding, OutputStream output, Charset encoding)
IOUtils.writeLines(Collection<?> lines, String lineEnding, OutputStream output, String encoding)
从一个流中读取内容
IOUtils.read(InputStream input, byte[] buffer)
IOUtils.read(InputStream input, byte[] buffer, int offset, int length) IOUtils.read(Reader input, char[] buffer)
IOUtils.read(Reader input, char[] buffer, int offset, int length)
把数据写入到输出流中
IOUtils.write(byte[] data, OutputStream output)
IOUtils.write(byte[] data, Writer output, Charset encoding)
IOUtils.write(byte[] data, Writer output, String encoding)
IOUtils.write(char[] data, Writer output)
IOUtils.write(char[] data, OutputStream output, Charset encoding)
IOUtils.write(char[] data, OutputStream output, String encoding)
IOUtils.write(String data, Writer output)
IOUtils.write(CharSequence data, Writer output)
从一个流中读取内容,如果读取的长度不够,就会抛出异常
IOUtils.readFully(InputStream input, int length)
IOUtils.readFully(InputStream input, byte[] buffer)
IOUtils.readFully(InputStream input, byte[] buffer, int offset, int length) IOUtils.readFully(Reader input, char[] buffer)
IOUtils.readFully(Reader input, char[] buffer, int offset, int length)
比较
IOUtils.contentEquals(InputStream input1, InputStream input2) // 比较两个流是否相等IOUtils.contentEquals(Reader input1, Reader input2)
IOUtils.contentEqualsIgnoreEOL(Reader input1, Reader input2) // 比较两个流,忽略换行符
其他方法
IOUtils.skip(InputStream input, long toSkip) // 跳过指定长度的流
IOUtils.skip(Reader input, long toSkip)
IOUtils.skipFully(InputStream input, long toSkip) // 如果忽略的长度大于现有的长度,就会抛出异常
IOUtils.skipFully(Reader input, long toSkip)
FileUtils(文件/文件夹相关)
复制文件夹
FileUtils.copyDirectory(File srcDir, File destDir) // 复制文件夹(文件夹里面的文件内容也会复制)
FileUtils.copyDirectory(File srcDir, File destDir, FileFilter filter) // 复制文件夹,带有文件过滤功能
FileUtils.copyDirectoryToDirectory(File srcDir, File destDir) // 以子目录的形式将文件夹复制到到另一个文件夹下
复制文件
FileUtils.copyFile(File srcFile, File destFile) // 复制文件
FileUtils.copyFile(File input, OutputStream output) // 复制文件到输出流
FileUtils.copyFileToDirectory(File srcFile, File destDir) // 复制文件到一个指定的目录
FileUtils.copyInputStreamToFile(InputStream source, File destination) // 把输入流里面的内容复制到指定文件
FileUtils.copyURLToFile(URL source, File destination) // 把URL 里面内容复制到文件(可以下载文件)
FileUtils.copyURLToFile(URL source, File destination, int connectionTimeout, int readTimeout)
把字符串写入文件
FileUtils.writeStringToFile(File file, String data, String encoding)
FileUtils.writeStringToFile(File file, String data, String encoding, boolean append)
把字节数组写入文件
FileUtils.writeByteArrayToFile(File file, byte[] data)
FileUtils.writeByteArrayToFile(File file, byte[] data, boolean append) FileUtils.writeByteArrayToFile(File file, byte[] data, int off, int len) FileUtils.writeByteArrayToFile(File file, byte[] data, int off, int len, boolean append)
把集合里面的内容写入文件
// encoding:文件编码,lineEnding:每行以什么结尾
FileUtils.writeLines(File file, Collection<?> lines)
FileUtils.writeLines(File file, Collection<?> lines, boolean append)
FileUtils.writeLines(File file, Collection<?> lines, String lineEnding)
FileUtils.writeLines(File file, Collection<?> lines, String lineEnding, boolean append)
FileUtils.writeLines(File file, String encoding, Collection<?> lines)
FileUtils.writeLines(File file, String encoding, Collection<?> lines, boolean append)
FileUtils.writeLines(File file, String encoding, Collection<?> lines, String lineEnding)
FileUtils.writeLines(File file, String encoding, Collection<?> lines, String lineEnding, boolean append)
往文件里面写内容
FileUtils.write(File file, CharSequence data, Charset encoding)
FileUtils.write(File file, CharSequence data, Charset encoding, boolean append)
FileUtils.write(File file, CharSequence data, String encoding)
FileUtils.write(File file, CharSequence data, String encoding, boolean append)
文件移动
FileUtils.moveDirectory(File srcDir, File destDir) // 文件夹在内的所有文件都将移动FileUtils.moveDirectoryToDirectory(File src, File destDir, boolean createDestDir) // 以子文件夹的形式移动到另外一个文件下
FileUtils.moveFile(File srcFile, File destFile) // 移动文件
FileUtils.moveFileToDirectory(File srcFile, File destDir, boolean createDestDir) // 以子文件的形式移动到另外一个文件夹下
FileUtils.moveToDirectory(File src, File destDir, boolean createDestDir) // 移动文件或者目录到指定的文件夹内
清空和删除文件夹
FileUtils.deleteDirectory(File directory) // 删除文件夹,包括文件夹和文件夹里面所有的文件
FileUtils.cleanDirectory(File directory) // 清空文件夹里面的所有的内容
FileUtils.forceDelete(File file) // 删除,会抛出异常
FileUtils.deleteQuietly(File file) // 删除,不会抛出异常
创建文件夹
FileUtils.forceMkdir(File directory) // 创建文件夹(可创建多级)
FileUtils.forceMkdirParent(File file) // 创建文件的父级目录
获取文件输入/输出流
FileUtils.openInputStream(File file)
FileUtils.openOutputStream(File file)
读取文件
FileUtils.readFileToByteArray(File file) // 把文件读取到字节数组
FileUtils.readFileToString(File file, Charset encoding) // 把文件读取成字符串
FileUtils.readFileToString(File file, String encoding)
FileUtils.readLines(File file, Charset encoding) // 把文件读取成字符串集合
FileUtils.readLines(File file, String encoding)
测试两个文件的修改时间
FileUtils.isFileNewer(File file, Date date)
FileUtils.isFileNewer(File file, File reference)
FileUtils.isFileNewer(File file, long timeMillis)
FileUtils.isFileOlder(File file, Date date)
FileUtils.isFileOlder(File file, File reference)
FileUtils.isFileOlder(File file, long timeMillis)
文件/文件夹的迭代
FileUtils.iterateFiles(File directory, IOFileFilter fileFilter, IOFileFilter dirFilter)
FileUtils.iterateFiles(File directory, String[] extensions, boolean recursive)
FileUtils.iterateFilesAndDirs(File directory, IOFileFilter fileFilter, IOFileFilter dirFilter)
FileUtils.lineIterator(File file)
FileUtils.lineIterator(File file, String encoding)
FileUtils.listFiles(File directory, IOFileFilter fileFilter, IOFileFilter dirFilter)
FileUtils.listFiles(File directory, String[] extensions, boolean recursive)
FileUtils.listFilesAndDirs(File directory, IOFileFilter fileFilter, IOFileFilter dirFilter)
其他
FileUtils.isSymlink(File file) // 判断是否是符号链接
FileUtils.directoryContains(File directory, File child) // 判断文件夹内是否包含某个文件或者文件夹
FileUtils.sizeOf(File file) // 获取文件或者文件夹的大小
FileUtils.getTempDirectory()// 获取临时目录文件
FileUtils.getTempDirectoryPath()// 获取临时目录路径
FileUtils.getUserDirectory()// 获取用户目录文件
FileUtils.getUserDirectoryPath()// 获取用户目录路径
FileUtils.touch(File file) // 创建文件
FileUtils.contentEquals(File file1, File file2) // 比较两个文件内容是否相同
FilenameUtils(文件名/后缀名相关)
FilenameUtils.concat(String basePath, String fullFilenameToAdd) // 合并目录和文件名为文件全路径
FilenameUtils.getBaseName(String filename) // 去除目录和后缀后的文件名
FilenameUtils.getExtension(String filename) // 获取文件的后缀
FilenameUtils.getFullPath(String filename) // 获取文件的目录
FilenameUtils.getName(String filename) // 获取文件名
FilenameUtils.getPath(String filename) // 去除盘符后的路径
FilenameUtils.getPrefix(String filename) // 盘符
FilenameUtils.indexOfExtension(String filename) // 获取最后一个.的位置
FilenameUtils.indexOfLastSeparator(String filename) // 获取最后一个/的位置
FilenameUtils.normalize(String filename) // 获取当前系统格式化路径
FilenameUtils.removeExtension(String filename) // 移除文件的扩展名
FilenameUtils.separatorsToSystem(String path) // 转换分隔符为当前系统分隔符
FilenameUtils.separatorsToUnix(String path) // 转换分隔符为linux系统分隔符
FilenameUtils.separatorsToWindows(String path) // 转换分隔符为windows系统分隔符
FilenameUtils.equals(String filename1, String filename2) // 判断文件路径是否相同,非格式化
FilenameUtils.equalsNormalized(String filename1, String filename2) // 判断文件路径是否相同,格式化
FilenameUtils.directoryContains(String canonicalParent, String canonicalChild) // 判断目录下是否包含指定文件或目录
FilenameUtils.isExtension(String filename, String extension) // 判断文件扩展名是否包含在指定集合(数组、字符串)中
FilenameUtils.wildcardMatch(String filename, String wildcardMatcher) // 判断文件扩展名是否和指定规则匹配

















































