1、IO流
1.流和流的分类
什么是IO流?
I:Input (输入)
O: Ouput(输出)
IO流的分类?
有多种分类方式:
- 一种方式是按照流的方向进行分类:
以内存作为参照物
往内存中去,叫做输入(Input)。或者叫做读(Read) .
从内存中出来,叫做输出(output)。或者叫做写(write) .
-
另一种方式是按照读取薮据方式不同进行分类:
- 有的流是按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制。
- 这种流是万能的,什么类型的文件都可以读取。包括:文本文件,图片,声音文件,视频……
- 有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取普通文本文件而存在的,这种流不能读取:图片、声音、视频等文件。只能读取纯文本文件,连word文件都无法读取
总结:流的分类
输入流、输出流、字节流、字符流
Java IO流的四大家族
java.io.InputStream | 字节输入流 |
---|---|
java.io.OutputStream | 字节输出流 |
java.io.Reader | 字符输入流 |
java.io.Writer | 字符输出流 |
注意:
- 四个都是抽象类。
-
所有流都是实现了java.io.Closeable接口,都是可关闭的
- 流是一个管道,是内存和硬盘之间的通道。用完后一定要关闭,不然会占用很多资源。
-
所有的输出流都实现了java.io.Flushable接口,都是可刷新的
- 最终输出后,一定要记得调用flush()方法。目的是将管道中剩余未输出的数据强行输出完(清空管道)
- 如果没有flash(),可能会导致丢失数据
- 在java中只要”类名”以strean结尾的都是字节流。以"Reader/writer"结尾的都是字符流
java.io包下需要掌握的流有16个:
文件专属:
java . io.FileInputstream
java.io.FileOutputstream
java.io.FileReader
java.io.Filewriter
转换流:(将字节流转换成字符流)
java . io . InputstreamReader
java . io. outputstreamWriter
缓冲流专属:
java. io. BufferedReader
java.io.BufferedWriter
java.io. BufferedInputstream
java . io.Bufferedoutputstrean
数据流专属:
java . io . DataInputstream
java .io. Dataoutputstrean
标准输出流:
java . io . Printwriter
java . io . Printstream
对象专属流:
java.io.ObjectInputstream
java.io.ObjectOutputstream
一下子看到这么多流。不用怕,只需要掌握一组的使用方法就可以了,使用其他的都是一样,一通百通。
下面以万能的字节流(FileInputStream、FileOutputStream)来举例说明。
2.如何使用流
1、输入流(读文件):FileInputStream
方法一
使用FileInputStream的read()
步骤:
1、 创建流对象
new FileInputStream(参数)
参数可以是一个File类、String字符串表示的文件路径
2、使用流的方法对文件进行读
输入流调用read()方法,每次从流中读取一个数据字节。返回值是读到的字节的ASCII值
读取一个后,他会指向下一个字符,如果到达末尾。返回-1,可以用while()来实现。
3、关闭流
调用close()方法
实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
package com.io.stream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class TestFileInputStream {
//定义一个流对象
private static FileInputStream fis;
public static void main(String[] args) {
try {
//1、 创建流对象.参数可以是一个File类、String字符串表示的文件路径
fis = new FileInputStream( "E:\\aaa.txt" ); //在e盘下有一个aaa.txt的文件夹,内容为(abcdefg)
//2、使用流的方法对文件进行读
while ( true ) {
int read = fis.read(); //注意这里返回的是int类型,代表是字符的ASCII值
if (read==- 1 ) { //读到最后会返回-1,退出条件
break ;
}
System.out.println(read);
}
} catch (FileNotFoundException e) { //异常细粒化,不同异常可以选择不同的处理方式
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//3、关闭流
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
|
/*输出
97
98
99
100
101
102
103
*/
int read()
该方法因为每次都是只读取一个字节,这样内存和硬盘交互太频繁 ,开销大且效率不高。一般不使用,但是要了解,这是基础。
方法二
一般使用这种方法
使用read(byte[] b)
一次读取最多 b.length 个字节,减少内存和硬盘交互,提高执行效率
该方法返回的是读到的字节的数量
使用步骤:和前面只有第二步有些差别
byte[] b= new byte[3];
int readNum = fis.read(b);
解析
- 新建一个byte[]数组b,代表我们一次需要读多少个字符。读完这么多字符后,下次一读是从当前读到的位置开始,和上面一样
- 将byte数组b传入read()方法中,返回一个我们byte数组的大小,此时readNum值为3
那么我们读出来的数据在哪里呢。自然是存放在byte数组里。我们打印b数组看,发现b数组里存放的读到的ascii值
细节:
因为数组的长度是我们设定的。如果文件读到最后,不一定刚好符合我们设定的长度,最后一组的长度只有小于或等于数组的长度。如果小于它会返回剩余的字符的数量,读不到返回-1,我们可以利用这个作为循环退出的条件。
另外一个,因为他的长度小于b数组,那么它的值也是无法填满b数组的,此时,它只更新b数组中前面的n个读到的值,b数组后面的是上一个读取时读取到的值。
实例:
仍然读取aaa.txt文件,内容为(abcdefg)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
public class TestFileInputStream2 {
private static FileInputStream fis;
public static void main(String[] args) {
try {
fis = new FileInputStream( "IO流\\aaa.txt" );
//准备一个byte数组
byte [] b= new byte [ 3 ];
int readNum = 0 ;
while ( true ) {
//先进行读操作。
readNum=fis.read(b);
//判断
if (readNum == - 1 ) {
break ;
}
//将字符数组转为String,后面两个参数为起始位置,和长度
String str = new String(b, 0 , readNum);
System.out.println(str);
}
/*输出
abc
def
g
*/
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//关闭流
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
|
其他常用的方法
int available()
返回流中还有多少个字符没有读。(相当于获得文件读到的位置到末尾字符的个数,如果没开始读,返回文件中总字符的数量)
使用这个可以对一些比较小的(字符长度)文件一次读完,如果不超过byte数组的范围的话
1
2
3
4
5
6
7
8
|
public class TestFileInputStream3 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream( "IO流\\aaa.txt" );
byte [] bytes = new byte [fis.available()]; //创建一个和文件字符数量一样大的byte数组,文件不能太大。
fis.read(bytes);
System.out.println( new String(bytes)); //b转为字符串,输出abcdefg
}
}
|
skip(long n)
顾名思义:从输入流中跳过并丢弃 n 个字节的数据。
2、输出流(写文件):FileOutputStream
和输入的流程差不多,过程也基本相同
write(byte[] b)
注意:
- byte的范围是-128~127,超过会报错
- 写完之后,一定要刷新
-
如果当前路径下文件已存在,会将原文件清空,再写入(慎用)。
- 如果它是一个目录,而不是一个常规文件,会报错。
- 或者该文件不存在,但无法创建它,会报错。
- 如果当前路径下文件不存在,会新建文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
package com.io.stream.output;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @Author cyh
* @Date 2021/8/7 17:21
*/
public class Test1 {
private static FileOutputStream fos;
public static void main(String[] args) {
try {
//新建一个输出流,参数是输出的路径,最后的为文件名。
fos = new FileOutputStream( "IO流\\bbb.txt" );
//新建一个byte数组,里面对应的是abcd的ascii值
byte [] bytes = { 97 , 98 , 99 , 100 , 101 , 127 }; //注意byte的范围是-128~127
//输出流调用write方法写入byte数组,以文件形式保存到上面的路径
fos.write(bytes);
//写完之后,一定要刷新
fos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
|
追加写文件
想要追加写文件,则需要在新建流的的时候,加一个参数true。
表示将字节写入文件末尾处,而不是写入文件开始处
1
2
|
//新建一个输出流,参数是输出的路径,最后的为文件名。增加true表示开启追加写
fos = new FileOutputStream( "IO流\\bbb.txt" , true );
|
注意:和上面一样,不一样的点只是追加写。
write(byte[] b, int off, int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流.
意思就是,写入的内容为off~len。如果off是0,len是数组长度,那就全部写入;如果off是数组长度-1,len是数组长度,那就只写入了一个字符
3.文件的拷贝
- 使用FileInputStream+FileOutputStream即可完成文件的拷贝
- 拷贝的过程应该是一边读、一边写
- 使用上面的字节流拷贝文件的时候,文件类型随意,是万能的。什么文件都可以拷贝
实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
package com.io.stream.copy;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @Author cyh
* @Date 2021/8/7 17:53
*/
public class TestCopy {
private static FileInputStream fis;
private static FileOutputStream fos;
public static void main(String[] args) {
try {
//创建一个输入流
fis = new FileInputStream( "D:\\edgeDownload\\VSCodeUserSetup-x64-1.55.0.exe" );
//创建一个输出流
fos = new FileOutputStream( "C:\\Users\\PC\\Desktop\\copy\\b\\VSCodeUserSetup-x64-1.55.0.exe" );
//核心,一边读、一边写
byte [] bytes = new byte [ 1024 * 1024 ]; //1MB,一次最多拷贝1MB
int readNum= 0 ;
while ((readNum=fis.read(bytes))!=- 1 ){
fos.write(bytes, 0 ,readNum); //将bytes全部写入
}
//刷新
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//资源要分开释放,不然一个出错会导致另一个无法释放
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
|
总结
本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注服务器之家的更多内容!
原文链接:https://blog.csdn.net/qq_44769557/article/details/119490606