共计 7147 个字符,预计需要花费 18 分钟才能阅读完成。
何为 IO?
首先,咱们看看百度给出的解释。
I/ O 输出 / 输入(Input/Output),分为 IO 设施和 IO 接口两个局部。
i 是写入,Input 的首字母。o 是输入,Output 的首字母。
IO 也称为 IO 流,IO = 流,它的外围就是对文件的操作,对于 字节、字符类型的输出和输入流。
IO 分类
IO 流次要分为两大类,字节流和字符流。而依照作用分类,能够分为输出流和输入流。
流?
在电脑上的数据有三种存储形式,一种是外存,一种是内存,一种是缓存。比方电脑上的硬盘,磁盘,U 盘等都是外存,在电脑上有内存条,缓存是在 CPU 外面的。外存的存储量最大,其次是内存,最初是缓存,然而外存的数据的读取最慢,其次是内存,缓存最快。这里总结从外存读取数据到内存以及将数据从内存写到外存中。对于内存和外存的了解,咱们能够简略的了解为容器,即外存是一个容器,内存又是另外一个容器。那又怎么把放在外存这个容器内的数据读取到内存这个容器以及怎么把内存这个容器里的数据存到外存中呢?
咱们能够将这个整个看成一个水池。水池外面连贯了出水口管与注水管。出水相当于咱们的输入流。注水相当于咱们的输出流。
File(文件类)
首先咱们如果须要用 IO 流的话,咱们必定是须要创立一个咱们所谓的 “水池” 的。
怎么创立呢?咱们间接创立一个 File 类对象。
package IoDemo;
import java.io.*;
public class IoDemo {
public static void main(String[] args) {
// 创立 File 对象
File file = new File("D:\\test.txt");
}
}
实际上这个对象,说白了就是用来贮存一个 IO 流的文件地址的。
创立了对象后,它也没有任何什么操作,操作得应用这个对象调用办法。
咱们先应用 createNewFile()办法创立咱们下面那个门路的文件。
file.createNewFile();
留神定义文件门路时,能够用“/”或者“\”。
并且在创立一个文件时,如果目录下有同名文件将被笼罩。
因为有时候,可能咱们的门路下曾经存在了绝对应的同名文件,所以咱们要应用 exists()办法判断文件是否曾经存在。
// 创立 File 对象
File file = new File("D:\\test.txt");
// 创立文件
try {
// 判断文件是否存在
if(!file.exists()){file.createNewFile();
}
} catch (IOException e) {e.printStackTrace();
}
其实,File 类外面还存在许多办法,用法都是能够间接调用的,作为一个合格的程序员,咱们能够间接浏览相干阐明而在适合的时候应用对应办法。
上面列举一些罕用办法。
①、创立办法
1.boolean createNewFile() 不存在返回 true 存在返回 false 2.boolean mkdir() 创立目录,如果上一级目录不存在,则会创立失败 3.boolean mkdirs() 创立多级目录,如果上一级目录不存在也会主动创立
②、删除办法
1.boolean delete() 删除文件或目录,如果示意目录,则目录下必须为空能力删除 2.boolean deleteOnExit() 文件应用实现后删除
③、判断办法
1.boolean canExecute()判断文件是否可执行 2.boolean canRead()判断文件是否可读 3.boolean canWrite() 判断文件是否可写 4.boolean exists() 判断文件或目录是否存在 5.boolean isDirectory() 判断此门路是否为一个目录 6.boolean isFile() 判断是否为一个文件 7.boolean isHidden() 判断是否为暗藏文件 8.boolean isAbsolute()判断是否是绝对路径 文件不存在也能判断
④、获取办法
1.String getName() 获取此门路示意的文件或目录名称 2.String getPath() 将此路径名转换为路径名字符串 3.String getAbsolutePath() 返回此形象路径名的相对模式 4.String getParent()// 如果没有父目录返回 null 5.long lastModified()// 获取最初一次批改的工夫 6.long length() 返回由此形象路径名示意的文件的长度。7.boolean renameTo(File f) 重命名由此形象路径名示意的文件。8.File[] liseRoots()// 获取机器盘符 9.String[] list() 返回一个字符串数组,命名由此形象路径名示意的目录中的文件和目录。10.String[] list(FilenameFilter filter) 返回一个字符串数组,命名由此形象路径名示意的目录中满足指定过滤器的文件和目录。
字节流的应用
咱们当初曾经建好这个 “水池”了,同时还能够应用办法来获取到“水池” 的一些信息。
那接下来,咱们能够试着创立一套流。
字节流,相当于一滴滴的水在一个管道里运输。这个管道咱们能够形象的称之为流。
咱们还是先看看知乎上,某些大佬的解释。
大佬的解释
图中蓝色为次要对应局部,红色为不对应局部,彩色的虚线局部代表这些流个别须要搭配应用。从下面的图中能够看出 Java IO 中的字节流是十分对称的。咱们来看看这些字节流中不对称的几个类。
LineNumberInputStream 次要实现从流中读取数据时,会失去相应的行号,至于什么时候分行、在哪里分行是由改类被动确定的,并不是在原始中有这样一个行号。在输入局部没有对应的局部,咱们齐全能够本人建设一个 LineNumberOutputStream,在最后写入时会有一个基准的行号,当前每次遇到换行时会在下一行增加一个行号,看起来也是能够的。如同更不入流了。
PushbackInputStream 的性能是查看最初一个字节,不称心就放入缓冲区。次要用在编译器的语法、词法剖析局部。输入局部的 BufferedOutputStream 简直实现相近的性能。
StringBufferInputStream 曾经被 Deprecated,自身就不应该呈现在 InputStream 局部,次要因为 String 应该属于字符流的范畴。曾经被废除了,当然输入局部也没有必要须要它了!还容许它存在只是为了放弃版本的向下兼容而已。
SequenceInputStream 能够认为是一个工具类,将两个或者多个输出流当成一个输出流顺次读取。齐全能够从 IO 包中去除,还齐全不影响 IO 包的构造,却让其更“纯净”――纯净的 Decorator 模式。
PrintStream 也能够认为是一个辅助工具。次要能够向其余输入流,或者 FileInputStream 写入数据,自身外部实现还是带缓冲的。实质上是对其它流的综合使用的一个工具而已。一样能够踢出 IO 包!System.out 和 System.out 就是 PrintStream 的实例。
对于不齐全学透的认识
听起来有些难度哈,这些高级用法咱们先不论。咱们先来看看它到底怎么用的。
那有人又说了,那如果不去学残缺,当前要是不会用怎么办?
答:其实只须要把握次要办法就能够,因为你如果须要实现一个十分用的货色,你必定是当时就须要去查阅相干材料,而日常开发中,罕用的也就能够信手拈来啦。
OutputStream(字节输入流)
这个抽象类是示意输入字节流的所有类的超类。
!!!这里的输入可不是咱们失常的输入,它反而想法,是将字节写入到文件,能够了解为将字节输入到文件。
看看外面有些啥罕用办法。
咱们先演示一下,字节输入流如何应用?
// 定义一个 String 值
String str = “Hello World”;
等下咱们利用字节流将这个 String 写入咱们的文件外面。
等等!这里是字节流,我怎么能够间接写入String?
嘿嘿,咱们应用 String 类中的 getBytes()办法将 String 转换成字节数组。
// 将 String 值转换成字节数组
byte[] bytes = str.getBytes();
整个代码是这样的:
package IoDemo;
import java.io.*;
public class IoDemo {
public static void main(String[] args) {
// 创立 File 对象
File file = new File("D:\\test.txt");
// 创立文件
try {
// 判断文件是否存在
if(!file.exists()){file.createNewFile();
}
} catch (IOException e) {e.printStackTrace();
}
// 定义一个 String 值
String str = "Hello World";
// 创立字节流
FileOutputStream fos = null;
try {
// 将 File 对象(即地址)给到 FileInputStream
fos = new FileOutputStream(file);
// 将 String 值转换成字节数组
byte[] bytes = str.getBytes();
// 循环将字节数组写入到文件中
for (int i = 0; i < bytes.length; i++) {
// 将 bytes 写入文件
fos.write(bytes[i]);
}
} catch (FileNotFoundException e) {e.printStackTrace();
} catch (IOException e) {e.printStackTrace();
}
}
}
咱们进咱们的文件看看输入成果。
就曾经写入了咱们的 String 外面的内容了。
InputStream(字节输出流)
这里我也就不解释了,他这个输出不是将内容输出到文件,而是将文件外面的内容输出到咱们的代码中。
// 创立字节输出流
FileInputStream fis = null;
try {
// 将 File 对象(即地址)给到 FileInputStream
fis = new FileInputStream(file);
// 创立字节数组
byte[] bytes = new byte[1024];
// 输入字节数组
int len = 0;
while ((len = fis.read(bytes)) != -1) {System.out.println(new String(bytes, 0, len));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
在上文,咱们曾经写入了一个 Hello Word
咱们当初这段代码,咱们将会输入文件中的内容。
len = fis.read(bytes)) != -1
我当初还是先解说一下这一段。
咱们的 len 是定义的一个数值。而 read()办法,是为了读取到整个文件外面内容的字节长度,就像数组的 lenth()一样。
而!= - 1 是因为,如果值为 - 1 那么,这个文件能够说是没有数据的,空的你也没必要输入。
而咱们字节流呢,个别是用于读取二进制文件,如音频、图片这些,大片的文字内容还是交给字符流吧。
字符流的应用
下面的字节流,它是一个个的输入的,而咱们当初的字符流,是大水管输入,一次能够运输一段。
个别能够用记事本关上的文件,咱们能够看到内容不乱码的。就是文本文件,能够应用字符流。而操作二进制文件(比方图片、音频、视频)必须应用字节流。
FileWriter(字符输入流)
老规矩哈,办法本人看看。
先写入一个 String 试试。
package IoDemo;
import java.io.*;
public class IoDemo {
public static void main(String[] args) {
String str = "嘿嘿!我是字符流·········";
// 创立 File 对象
File file = new File("D:\\test.txt");
try {
// 将 str 用 writer 写入文件
FileWriter fw = new FileWriter(file);
fw.write(str);
// 敞开流,字符流必须敞开流才能够输入
fw.close();} catch (FileNotFoundException e) {e.printStackTrace();
} catch (IOException e) {e.printStackTrace();
}
}
}
写入成果如下:
实际上,写入字符串就几个步骤。
//1. 将 str 用 writer 写入文件
FileWriter fw = new FileWriter(file);
//2. 应用 write()办法写入字符串
fw.write(str);
//3. 敞开流,字符流必须敞开流才能够输入
fw.close();
FileReader(字符输入流)
// 输入文件内容
try {
// 创立输出字符流
FileReader fr = new FileReader(file);
// 输入文件内容
int ch = 0;
while ((ch = fr.read()) != -1){System.out.print((char)ch);
}
// 敞开流
fr.close();} catch (FileNotFoundException e) {e.printStackTrace();
} catch (IOException e) {e.printStackTrace();
}
这里采纳 Char 挨个字符遍历数据。
包装流
缓冲流
为什么应用缓冲流呢?
简略地说就是,写入数据更快,能够减速写入。
缓冲流,也叫高效流。可能高效读写缓冲流,可能转换编码的转换流,可能长久化存储对象的序列化对象等等。它是四个根本 File 流的加强,所以也是 4 个流,依照数据类型分类。缓冲流的基本原理,是在创立流对象时,会创立一个内置的默认大小的缓冲区数组,通过缓冲区读写,缩小零碎 IO 读取次数,从而进步读写的效率。
package IoDemo;
import java.io.*;
public class IoDemo {
public static void main(String[] args) {
// 创立 File 对象
File file = new File("D:\\test.txt");
// 创立缓冲流
BufferedWriter bw = null;
try {
// 创立 FileWriter 对象
FileWriter fw = new FileWriter(file);
// 创立 BufferedWriter 对象
bw = new BufferedWriter(fw);
// 写入一首诗分四次写入
bw.write("窗前明月光,");
bw.write("疑是地上霜。");
bw.write("举头望明月,");
bw.write("抬头思故土。");
bw.flush();} catch (IOException e) {e.printStackTrace();
}
}
}
这个很简略,本人看就可以看懂。
转换流
InputStreamReader: 把字节输出流转换为字符输出流
OutputStreamWriter: 把字节输入流转换为字符输入流
我就不写示范了,网上找了一段。
// 转换流实现将 a.txt 文件 复制到 b.txt 中
//1、创立源和指标
File srcFile = new File("io"+File.separator+"a.txt");
File descFile = new File("io"+File.separator+"b.txt");
//2、创立字节输入输出流对象
InputStream in = new FileInputStream(srcFile);
OutputStream out = new FileOutputStream(descFile);
//3、创立转换输入输出对象
Reader rd = new InputStreamReader(in);
Writer wt = new OutputStreamWriter(out);
//3、读取和写入操作
char[] buffer = new char[10];// 创立一个容量为 10 的字符数组,存储曾经读取的数据
int len = -1;// 示意曾经读取了多少个字符,如果是 -1,示意曾经读取到文件的开端
while((len=rd.read(buffer))!=-1){wt.write(buffer, 0, len);
}
//4、敞开流资源
rd.close();
wt.close();
扩大
而后,找相干材料时,还涨了个常识。大家能够看看。
合并流
合并流:把多个输出流合并为一个流,也叫程序流,因为在读取的时候是先读第一个,读完了在读上面一个流。
SequenceInputStream seinput = new SequenceInputStream();
new FileInputStream("io/1.txt"), new FileInputStream("io/2.txt"));
byte[] buffer = new byte[10];
int len = -1;
while((len=seinput.read(buffer))!=-1){System.out.println(new String(buffer,0,len));
}
seinput.close();
这里先是创立了一个 SequenceInputStream 对象,而后 new 了两个 FileInputStream 对象,咱们应用合并流读取,先应用 seinput.read 办法 读取 1.txt 的内容,而后再对其 2.txt 的内容。