Java笔记-IO

Java笔记-IO流

IO?

InputStream:输入流

OutputStream:输出流

之前在学Java的时候,对IO总有点似懂非懂,什么时候用输入流/输出流有些迷糊。刚刚看了个视频,觉得解释的很好:是输入,还是输出是以【内存】为主体来讲的;例如:

从硬盘中读入文件、从网络流中读取消息、读取键盘输入等等,这些情况都是从其它地方获取数据到内存,使用的是输入流;

相反,写入文件、网络通信中发送消息、输出字符到屏幕(System.out.print)等,这些是从内容输出数据到其它的地方,这是用到了输出流;

创建文件

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
/*
1、三种方法创建File对象
File(String path);
File(File parFile,String fileName);
File(String parPath,String fileName);
2、再通过File对象的createNewFile()方法,这样就真正在磁盘上创建好了文件
*/

@Test
public void createFile1() throws IOException {
File file = new File("d:\\f1.txt");
file.createNewFile();
}

@Test
public void createFile2() throws IOException {
File parFile = new File("d:\\");
File file = new File(parFile, "f2.txt");
file.createNewFile();
}

@Test
public void createFile3() throws IOException {
String parPath = "d:\\";
File file = new File(parPath, "f3.txt");
file.createNewFile();
}

获取文件信息

查看类图,可以看到提供了很多的方法,来获取文件的各种信息。

image-20210514212305649

1
2
3
4
5
6
7
8
9
10
@Test
public void getFileInfo(){
File file = new File("d:\\f1.txt");
System.out.println(file.getName());
System.out.println(file.getAbsolutePath());
System.out.println("文件大小(字节)"+file.length());
System.out.println("是否存在"+file.exists());
System.out.println("是否是目录"+file.isDirectory());
System.out.println("是否是文件"+file.isFile());
}

image-20210514212544720

值得注意的是,Java中通过mkdir(),如果填写的参数是多级目录就用mkdirs()来创建目录;

1
2
3
4
5
6
7
8
9
10
11
public void newPath() throws IOException {
String path = "d:\\a\\b\\c";
File file = new File(path);
if(file.exists()){
System.out.println("目录已经存在");
}else{
file.mkdirs();
System.out.println("多级目录创建成功");
}

}

image-20210514214044134

流的分类

按操作的数据单位:

​ 字节流(InputStream\OutputStream)用于二进制文件、

​ 字符流(Reader\Writer)用于字符文件

Java中IO流有40多个,他们都是有上面这4个抽象类派生而来的。这些派生出来的子类名称都是以父类名作为后缀。

FileInputStream、FileOutputStream

读文件

1
2
3
4
5
6
7
8
9
public void read1() throws IOException {
FileInputStream fileInputStream = new FileInputStream("d:\\mytest.txt");
byte[] buf = new byte[8];
int len = 0;
while ((len = fileInputStream.read(buf)) != -1) {
System.out.print(new String(buf, 0, len));
}
fileInputStream.close();
}

复制文件

1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void read1() throws IOException {
FileInputStream fileInputStream = new FileInputStream("d:\\a.png");
FileOutputStream fileOutputStream = new FileOutputStream("d:\\a2.png");
byte[] buf = new byte[1024];
int len = 0;
while ((len = fileInputStream.read(buf)) != -1) {
fileOutputStream.write(buf);
}
fileOutputStream.close();
fileInputStream.close();
}

FileReader\FileWriter

FileWriter使用后,必须要关闭(close)或者刷新(flush),否则写入不到指定的文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Test
public void fileReader1() {
FileReader fileReader = null;
try {
fileReader = new FileReader("d:\\f1.txt");
char[] buff = new char[8];
int len = 0;
while ((len = fileReader.read(buff)) != -1) {
System.out.println(new String(buff, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}

}

节点流\处理流

节点流:可以从一个特定的数据源读写数据

处理流:(包装流),是“连接”在已存在的流(节点流/处理流)之上,提供更强大的读写功能,BufferedReader、BufferedWriter——修饰器模式

下面这段代码,就是使用BufferedReader这个包装类,通过注入FileReader,实现读取文件;其中BufferedReader还提供了readLine()这个方法,返回读取到的一行字符串,很方便。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Test
public void bufferedReader1() {
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader("d:\\f1.txt"));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

对象流

序列化:在保存数据时,保存数据的值和类型;ObjectOutputStream

反序列化:在恢复数据时,恢复数据的值和类型;ObjectInputStream

要让某个类是可序列化的,这个类必须实现Serializable接口或者是Externalizable接口;

其中前者是一个标记接口没有方法,后者有方法需要实现。

注意:

  1. 读写顺序要一致;
  2. 要进行序列化的对象,它的类需要实现Serializable/Externalizable接口;
  3. 序列化的类中建议添加SerialVersionUID属性(private static final long 序列版本号),以提高兼容性;
  4. 序列化时默认将这个类的所有属性都进行序列化,除了哪些被static,transient修饰的属性;所以要求里面的属性也要实现可序列化接口;
  5. 序列化具备可继承性;父类实现了序列化接口,子类也可以序列化;

标准输入输出流

标准输入:System.in 键盘

​ 编译类型-InputStream

​ 运行类型-BufferedInputStream

标准输出:System.out 显示器

​ 编译类型-运行类型-PrintStream

转换流

InputStreamReader 字节输入流-》字符输入流

OutputStreamWriter

打印流

只有输出流,没有输入

PrintStream

PrintWriter

Properties

专门用于读写配置文件的类;底层是HashMap;

格式:键=值

“=”连接,没有空格,值不需要用引号包起来,默认类型String

load()

list()

getProperties()

setProperties()

store(),其中如果有中文,会存储Unicode码


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!