Java从入门到实战总结-3.3、Java的IO处理


文章目录


IO表示In和out,表示对计算机资源的读入和写出,包括文件、网络等内容的读取和写入。

为了避免对流的流向的理解混乱,记住一点:对于流的入和出都是针对内存的,即input是到内存,output是出内存;读和写则是针对外部介质的,read是从外部介质读取,write是写入外部介质;打印就好理解了,打印到屏幕上或者打印到其它介质中,都是对内存内容的output。

1、java.io.File

java.io.File类是文件和目录路径名的抽象表示。以下是有关文件的要点:

  • 实例可以或可以不表示实际的文件系统对象,如文件或目录。如果是这样表示这样一个对象,然后该对象位于一个分区。分区是存储为文件系统的操作系统的特定部分。
  • 文件系统可以实现限制某些操作的实际文件系统对象,如读,写,和执行上。这些限制统称为访问权限。
  • File类的实例是不可变的;也就是说,一旦创建,由一个File对象表示的抽象路径名是不会改变的。

(1)、类的声明

以下是声明java.io.File类:

public class File extends Object implements Serializable , Comparable < File >

(2)、字段

  • static String pathSeparator – 这是系统相关的路径分隔符,表示为一个字符串以方便使用。
  • static char pathSeparatorChar – 这是依赖于系统的路径分隔符。
  • static String separator – 这是与系统有关的默认名称分隔符,表示为一个字符串以方便使用。
  • static char separatorChar – 这是与系统有关的默认名称分隔符。

(3)、类的构造函数

SN

构造函数& 描述

1

File(File parent, String child) 此方法创建从父抽象路径名和child路径名字符串的新File实例。

2

File(String pathname) 该方法通过将给定路径名字符串转换为抽象路径名来创建一个新File实例。

3

File(String parent, String child) 此方法创建从父路径名字符串和child路径名字符串的新File实例。

4

File(URI uri) URI转换成抽象路径名:此方法通过给定的文件将创建一个新的File实例。

(4)、类方法

SN

方法& 描述

1

​boolean canExecute() ​​ 此方法测试应用程序是否可以执行表示此抽象路径名的文件。

2

​boolean canRead() ​​ 这种方法测试应用程序是否可以读取表示此抽象路径名的文件。

3

​boolean canWrite() ​​ 此方法测试应用程序是否可以修改表示此抽象路径名的文件。

4

​int compareTo(File pathname) ​​ 这种方法比较两个抽象路径名的字典顺序。

5

​boolean createNewFile() ​​ 此方法自动创建此抽象路径名命名的,当且仅当具有此名称的文件尚不存在一个新的空文件。

6

​static File createTempFile(String prefix, String suffix) ​​ 此方法创建的默认临时文件目录的空文件,使用给定前缀和后缀生成其名称。

7

​static File createTempFile(String prefix, String suffix, File directory) ​​ 此方法会在指定的目录中一个新的空文件,使用给定前缀和后缀字符串生成其名称。

8

​boolean delete() ​​ 此方法删除表示此抽象路径名的文件或目录。

9

​void deleteOnExit() ​​ 此方法要求将表示此抽象路径名的文件或目录在虚拟机终止时被删除。

10

​boolean equals(Object obj) ​​ 此方法测试此抽象路径名与给定对象是否相等。

11

​boolean exists() ​​ 此方法测试表示此抽象路径名的文件或目录是否存在。

12

​File getAbsoluteFile() ​​ 此方法返回此抽象路径名的绝对形式。

13

​String getAbsolutePath() ​​ 此方法返回此抽象路径名的绝对路径名字符串。

14

​File getCanonicalFile() ​​ 此方法返回此抽象路径名的规范形式。

15

​String getCanonicalPath() ​​ 此方法返回此抽象路径名的规范路径名字符串。

16

​long getFreeSpace() ​​ 此方法返回此抽象路径名的分区中的未分配的字节数。

17

​String getName() ​​ 此方法返回表示此抽象路径名的文件或目录的名称。

18

​String getParent() ​​ 此方法返回此抽象路径名的父路径名的字符串,或者null,如果此路径名冇有指定父目录。

19

​File getParentFile() ​​ 此方法返回此抽象路径名的父抽象路径名,或null,如果此路径名冇有指定父目录。

20

​String getPath() ​​ 此方法此抽象路径名转换为一个路径名字符串。

21

​long getTotalSpace() ​​ 此方法返回此抽象路径名的分区的大小。

22

​long getUsableSpace() ​​ 此方法返回可用字节数这个虚拟机上命名此抽象路径名的分区。

23

​int hashCode() ​​ 此方法用于计算此抽象路径名的哈希码。

24

​boolean isAbsolute() ​​ 此方法测试此抽象路径名是否是绝对的。

25

​boolean isDirectory() ​​ 此方法测试表示此抽象路径名的文件是否是一个目录。

26

​boolean isFile() ​​ 此方法测试表示此抽象路径名的文件是否是一个正常的文件。

27

​boolean isHidden() ​​ 此方法测试此抽象路径名的文件是否是一个隐藏文件。

28

​long lastModified() ​​ 此方法返回的时候,表示此抽象路径名的文件的最后修改

29

​long length() ​​ 此方法返回表示此抽象路径名的文件的长度。

30

​String[] list() ​​ 此方法返回的字符串命名表示此抽象路径名的目录中的文件和目录的数组。

31

​String[] list(FilenameFilter filter) ​​ 此方法返回的字符串命名的目录表示此抽象路径名满足指定过滤器的文件和目录的数组。

32

​File[] listFiles() ​​ 此方法返回抽象路径名表示在表示此抽象路径名的目录中的文件的数组。

33

​File[] listFiles(FileFilter filter) ​​ 此方法返回抽象路径名表示的目录表示此抽象路径名满足指定过滤器的文件和目录的数组。

34

​File[] listFiles(FilenameFilter filter) ​​ 此方法返回抽象路径名表示的目录表示此抽象路径名满足指定过滤器的文件和目录的数组。

35

​static File[] listRoots() ​​ 此方法列出可用的文件系统的根。

36

​boolean mkdir() ​​ 此方法创建此抽象路径名的目录。

37

​boolean mkdirs() ​​ 此方法创建此抽象路径名的目录,包括任何必需但不存在的父目录

38

​boolean renameTo(File dest) ​​ 这种方法将重命名表示此抽象路径名的文件。

39

​boolean setExecutable(boolean executable) ​​ 这是一个方便的方法来设置所有者对于此抽象路径名执行权限。

40

​boolean setExecutable(boolean executable, boolean ownerOnly) ​​ 此方法设置所有者或每个人的执行权限,此抽象路径名。

41

​boolean setLastModified(long time) ​​ 此方法设置此抽象路径名的文件或目录的最后修改时间。

42

​boolean setReadable(boolean readable) ​​ 这是一个方便的方法来设置此抽象路径名的所有者的读取权限。

43

​boolean setReadable(boolean readable, boolean ownerOnly) ​​ 此方法设置所有者或在此抽象路径名大家的读取权限。

44

​boolean setReadOnly() ​​ 此方法标志着此抽象路径名命名的,这样只允许读操作的文件或目录。

45

​boolean setWritable(boolean writable) ​​ 这是一个方便的方法来设置此抽象路径名的所有者的写权限。

46

​boolean setWritable(boolean writable, boolean ownerOnly) ​​ 此方法设置此抽象路径名的所有者或每个人的写权限。

47

​String toString() ​​ 此方法返回此抽象路径名的路径名字符串。

48

​URI toURI() ​​ 这种方法构造一个文件:URI表示此抽象路径名。

(5)、示例

package com.xiaoyaoyou.day10;

import java.io.File;
import java.io.IOException;

public class FileTest {
public static void main(String[] args) throws IOException {
System.out.println(File.pathSeparator);
System.out.println(File.pathSeparatorChar);
System.out.println(File.separator);
System.out.println(File.separatorChar);

File f = new File("1.txt");
System.out.println("文件是否存在:"+f.createNewFile());
System.out.println("文件名称:"+f.getName());
System.out.println("文件路径:"+f.getPath());
System.out.println("文件绝对路径:"+f.getAbsoluteFile());
System.out.println("文件是否存在:"+f.exists());
File f1 = new File("./1.txt");
f1.createNewFile();
System.out.println("文件是否存在:"+f1.exists());
System.out.println("文件长度:"+f.length());
System.out.println("文件绝对路径:"+f1.getAbsoluteFile());
f1.delete();
System.out.println("文件是否存在:"+f1.exists());
}
}

结果:

:
:
/
/
文件是否存在:true
文件名称:1.txt
文件路径:1.txt
文件绝对路径:/Users/yz/work/java/JavaStudy/src/1.txt
文件是否存在:true
文件是否存在:true
文件长度:0
文件绝对路径:/Users/yz/work/java/JavaStudy/src/./1.txt
文件是否存在:false

2、文件遍历

对某个文件夹进行遍历,打印出文件名字,找到某个后缀的文件进行统计:

package com.xiaoyaoyou.day10;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class FilesListTest {
public static void main(String[] args) {
File f = new File("/Users/yz/work/java/JavaStudy/src");
File[] files = f.listFiles();
Map<String, List> res = new HashMap<>();
listFiles(files, res);
System.out.println(res);
}

static List<String> img = new ArrayList<>();
static List<String> zip = new ArrayList<>();
public static void listFiles(File[] files, Map<String, List> res) {
if (files != null && files.length > 0) {
for (File file : files) {
if (file.isFile()) {
System.out.println(file.getName());
if (file.getName().endsWith(".png")) {
img.add(file.getAbsolutePath());
res.put("图片", img);
} else if (file.getName().endsWith(".zip")) {
zip.add(file.getAbsolutePath());
res.put("压缩包", zip);
}
} else {
File[] files2 = file.listFiles();
listFiles(files2, res);
}
}
}
}
}

结果:

Demo1.java
Demo2.java
Homework10101007.java
Demo3.java
Homework10101006.java
Demo4.java
Demo5.java
Demo6.java
Homework10101003.java
Demo10.java
Demo11.java
Demo7.java
Homework10101005.java
Homework10101004.java
Demo1.java
Demo2.java
Demo3.java
Demo4.java
Demo8.java
Demo9.java
Demo5.java
.DS_Store
homework2.java
homework3.java
Homework4.java
homework1.java
HomeWork10201001.java
Demo1.java
Demo2.java
Demo3.java
Demo4.java
Demo5.java
Express.class
ExpressDao.class
快乐E栈项目集合数据结构.zip
StudentCourse.class
BinaryTree$Node.class
CollectionsTest.class
TreeSetTest.class
HashMapTest.class
MyLinked$Node.class
Person.class
IteratorTest.class
MyBinaryTree.class
MyLinked.class
Course.class
TreeSetSortTest.class
自定义单链表和二叉树作业.zip
HashSetTest.class
LinkedIteratorTest.class
TestArrayList.class
BinaryTree.class
VectorTest.class
LinkedListTest.class
Student.class
ForeachTest.class
Views.class
Homework1.class
Homework3.class
Homework4.class
Homework2.class
Student.class
UserClient.class
CourierClient.class
Main.class
FileTest.class
FilesListTest.class
image-20210329011124135.png
demo1.iml
happyEStack.java
Test.java
Demo2.java
Demo3.java
demo.java
Demo5.java
Demo1.java
Demo1.java
Demo2.java
Demo3.java
main.java
Demo4.java
main.class
.DS_Store
.DS_Store
Homework10201002.java
Demo1.java
Test.java
Person.java
Student.java
.DS_Store
MyListTest.java
MyList.java
Demo.java
Outer.java
PlayGame.java
Computer.java
Game.java
UserService.java
UserServiceTest.java
Person.java
Demo.java
Test.java
Person.java
Student.java
Nurse.java
uiDesigner.xml
.gitignore
workspace.xml
modules.xml
.name
misc.xml
.DS_Store
.DS_Store
.DS_Store
Express.java
ExpressDao.java
快乐E栈项目集合数据结构.zip
MyLinked.java
LinkedListTest.java
.DS_Store
HashMapTest.java
MyBinaryTree.java
StudentCourse.java
LinkedIteratorTest.java
TestArrayList.java
TreeSetTest.java
HashSetTest.java
CollectionsTest.java
TreeSetSortTest.java
自定义单链表和二叉树作业.zip
ForeachTest.java
IteratorTest.java
VectorTest.java
Views.java
Homework2.java
Homework3.java
Homework4.java
Homework1.java
UserClient.java
Main.java
CourierClient.java
FilesListTest.java
FileTest.java
image-20210329011124135.png
{图片=[/Users/yz/work/java/JavaStudy/src/out/production/demo1/com/xiaoyaoyou/image-20210329011124135.png, /Users/yz/work/java/JavaStudy/src/src/com/xiaoyaoyou/image-20210329011124135.png], 压缩包=[/Users/yz/work/java/JavaStudy/src/out/production/demo1/com/xiaoyaoyou/快乐E栈项目集合数据结构.zip, /Users/yz/work/java/JavaStudy/src/out/production/demo1/com/xiaoyaoyou/day9/自定义单链表和二叉树作业.zip, /Users/yz/work/java/JavaStudy/src/src/com/xiaoyaoyou/快乐E栈项目集合数据结构.zip, /Users/yz/work/java/JavaStudy/src/src/com/xiaoyaoyou/day9/自定义单链表和二叉树作业.zip]}

进程已结束,退出代码为 0

3、文件过滤器

使用文件过滤器接口对文件进行过滤,不用再对文件名进行判断:

package com.xiaoyaoyou.day10;

import java.io.File;
import java.io.FileFilter;

public class FileFilterTest {
public static void main(String[] args) {
File f = new File("/Users/yz/work/java/JavaStudy/src");
listFiles(f);
}

public static void listFiles(File file) {
FileFilter filter = new ZIPFileFilter();
File[] files = file.listFiles(filter);
if (files != null && files.length > 0) {
for (File f : files) {
if (f.isFile()) {
System.out.println(f.getAbsolutePath());
} else {
listFiles(f);
}
}
}
}

static class ZIPFileFilter implements FileFilter{
@Override
public boolean accept(File pathname) {
if(pathname.getName().endsWith(".zip") || pathname.isDirectory()) {
return true;
}
return false;
}
}
}

结果:

/Users/yz/work/java/JavaStudy/src/out/production/demo1/com/xiaoyaoyou/快乐E栈项目集合数据结构.zip
/Users/yz/work/java/JavaStudy/src/out/production/demo1/com/xiaoyaoyou/day9/自定义单链表和二叉树作业.zip
/Users/yz/work/java/JavaStudy/src/src/com/xiaoyaoyou/快乐E栈项目集合数据结构.zip
/Users/yz/work/java/JavaStudy/src/src/com/xiaoyaoyou/day9/自定义单链表和二叉树作业.zip

4、相对路径和绝对路径

绝对路径:从盘符开始,是一个完整的路径,例如:c://a.txt

相对路径:在Java代码中是相对于项目目录路径,这是一个不完整的便捷路径,在Java开发中很常用

package com.xiaoyaoyou.day10;

import java.io.File;

public class PathTest {
public static void main(String[] args) {
File f = new File("1.txt");
File f2 = new File("/Users/yz/work/1.txt");
System.out.println(f.getAbsolutePath());
System.out.println(f2.getAbsolutePath());
}
}

结果:

/Users/yz/work/java/JavaStudy/src/1.txt
/Users/yz/work/1.txt

5、IO流

(1)、概述

可以将这种数据传输操作,看做一种数据的流动,按照流动的方向分为输入Input和输出Output。

Java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。

Java.io 包中的流支持很多种格式,比如:基本类型、对象、本地化字符集等等。

一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。

Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。

Java从入门到实战总结-3.3、Java的IO处理_字符串

(2)、分类

按照流的方向分为:输入流和输出流

按照流动的数据类型分为:字节流和字符流

字节流:输入流的父类InputStream,输出流父类OutputStream

字符流:输入流父类Reader,输出流Writer

6、字节流

这输入字节流的顶级父类,先来了解一切皆字节的描述:计算机中的任何数据(文本、图片、视频、音乐等)都是以二进制形式存储的。在数据传输时也都是以二进制的形式存储的。后续的学习的任何流,在传输时底层都是二进制。

(1)、InputStream 和 OutputStream

Java.io.InputStream 类是表示字节输入流的所有类的超类。这需要定义InputStream的子类的应用程序必须始终提供返回输入的下一个字节的方法。OutputStream类似。

(2)、FileInputStream 和 FileOutputStream

A、java.io.FileInputStream
public class FileInputStream extends InputStream

构造方法:

SN

构造函数& 描述

1

FileInputStream(File file) 这通过打开一个到实际文件,命名在文件系统中的File对象文件的文件的连接创建一个FileInputStream。

2

FileInputStream(FileDescriptor fdObj) 这通过使用文件描述符fdObj,它代表在文件系统中某个实际文件的现有连接创建一个FileInputStream。

3

FileInputStream(String name) 这将创建一个FileInputStream通过打开一个到实际文件的连接,通过路径名名在文件系统命名的文件。

类方法:

SN

方法& 描述

1

​int available() ​​ 此方法从输入流中通过一个方法的下一次调用阻塞该输入流返回可以读取(或跳过)的剩余字节数的估计值。

2

​void close() ​​ 此方法关闭此文件输入流并释放与该流关联的所有系统资源。

3

​protected void finalize() ​​ 此方法可确保此文件输入流的close方法被调用当它冇有更多的参考引用。

4

​FileChannel getChannel() ​​ 此方法返回与此文件输入流关联的唯一文件通道对象。

5

​FileDescriptor getFD() ​​ 此方法返回FileDescriptor对象,表示连接到正在使用此文件输入流文件系统的实际文件。

6

​int read() ​​ 此方法读取当前输入流中一个字节的数据。

7

​int read(byte[] b) ​​ 此方法从这个输入流中数据读取可达b.length个字节到字节数组。

8

​int read(byte[] b, int off, int len) ​​ 此方法读取最多len个从这个输入流中数据的字节到字节数组。

9

​long skip(long n) ​​ 此方法跳过并丢弃n个字节从输入流中的数据。

B、java.io.FileOutputStream

Java.io.FileOutputStream 类是用于将数据写入一个文件或FileDescriptor的输出流。以下是关于文件输出流的要点:

  • 这个类是指用于记录的原始字节,例如图像数据流。
  • 写字符流,可以使用文件字符 FileWriter

类构造函数:

SN

构造函数& 描述

1

FileOutputStream(File file) 这将创建一个文件输出流写入到由指定的File对象表示文件。

2

FileOutputStream(File file, boolean append) 这将创建一个文件输出流写入到由指定的File对象表示的文件。

3

FileOutputStream(FileDescriptor fdObj) 这将创建一个输出文件流写入到指定的文件描述符,它代表了文件系统中的某个实际文件的现有连接。

4

FileOutputStream(String name) 这将创建一个输出文件流写入到具有指定名称的文件。

5

FileOutputStream(String name, boolean append) 这将创建一个输出文件流写入到具有指定名称的文件。

类方法:

SN

方法& 描述

1

​void close() ​​ 此方法关闭此文件输出流并释放与此流有关的所有系统资源。

2

​protected void finalize() ​​ 这种方法清除连接到文件,并确保此文件输出流的close方法被调用时,此流不再有引用。

3

​FileChannel getChannel() ​​ 此方法返回与此文件输出流关联的唯一文件通道对象。

4

​FileDescriptor getFD() ​​ 此方法返回与此流有关的文件描述符。

5

[void write(byte​​] b) ​​ 此方法写入b.length个字节从指定的字节数组到该文件输出流。

6

[void write(byte​​] b, int off, int len) ​​ 此方法从指定的字节数组开始到该文件输出流关闭写入len字节。

7

​void write(int b) ​​ 此方法写入指定的字节写入此文件输出流。

示例
package com.xiaoyaoyou.day10;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileInputOutputStreamTest {
public static void main(String[] args) throws IOException {
//将流数据输出到文件中
FileOutputStream fileOutputStream = new FileOutputStream("/Users/yz/work/1.txt");
byte[] bytes = {65, 66, 67};
fileOutputStream.write(bytes);
fileOutputStream.close();
//从文件中读入数据流到内存
FileInputStream fileInputStream = new FileInputStream("/Users/yz/work/1.txt");
byte[] bytes2 = new byte[5];
fileInputStream.read(bytes2);
for (byte b: bytes2) {
System.out.println(b);
}
fileInputStream.close();
}
}

结果:

65
66
67
0
0

7、字符编码

计算机中储存的信息都是用二进制数表示的;而我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果。通俗的说,按照何种规则将字符存储在计算机中,如’a’用什么表示,称为"编码";反之,将存储在计算机中的二进制数解析显示出来,称为"解码",如同密码学中的加密和解密。在解码过程中,如果使用了错误的解码规则,则导致’a’解析成’b’或者乱码。

字符集(Charset):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。

字符编码(Character Encoding):是一套法则,使用该法则能够对自然语言的字符的一个集合(如字母表或音节表),与其他东西的一个集合(如号码或电脉冲)进行配对。即在符号集合与数字系统之间建立对应关系,它是信息处理的一项基本技术。通常人们用符号集合(一般情况下就是文字)来表达信息。而以计算机为基础的信息处理系统则是利用元件(硬件)不同状态的组合来存储和处理信息的。元件不同状态的组合能代表数字系统的数字,因此字符编码就是将符号转换为计算机可以接受的数字系统的数,称为数字代码。

常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等。计算机要准确的处理各种字符集文字,需要进行字符编码,以便计算机能够识别和存储各种文字。

Java从入门到实战总结-3.3、Java的IO处理_java_02

这个是漫画介绍,更生动一些:https://mp.weixin.qq.com/s/CSsN5rd-a6yPEI7hzLMtFw

8、字符流

字节流处理文字一般会遇到乱码,读取文字一半等问题,所以需要更改为字符流处理。

(1)、Reader和Writer

Java.io.Reader 类是一个抽象类,用于读取字符流。Java.io.Writer 类是一个抽象类,用于写入字符流。

(2)、FileWriter和FileReader

Java.io.FileReader 类是一个方便的类用于读取字符文件。以下是有关的FileReader要点:

  • 这个类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。
  • FileReader是为字符读取流。对于原始字节流读取,使用文件输入流-FileInputStream。

序号

构造函数& 描述

1

FileReader(File file) 创建一个新的FileReader,从给定的文件读取。

2

FileReader(FileDescriptor file) 创建一个新的FileReader,从给出的FileDescriptor读取。

3

FileReader(String fileName) 创建一个新的FileReader,因为要读取的文件的名称。

Java.io.FileWriter 类是一个方便的类写入字符文件。以下是关于FileWriter中重要的几点:

  • 这个类的构造方法假定默认字符编码和默认字节缓冲区大小都是可以接受的。
  • 文件字符写的意思是写入字符流。对于原始字节写入流,使用文件输出流。

以下是Java.io.FileWriter类的声明:

public class FileWriter extends OutputStreamReader

以下是Java.io.FileWriter类中的字段:

SN

构造函数& 描述

1

FileWriter(File file) 此构造一个文件字符写对象给出一个File对象。

2

FileWriter(File file, boolean append) 此构造一个文件字符写对象给出一个File对象。

3

FileWriter(FileDescriptor fd) 此构造与文件描述符相关联的文件字符写的对象。

4

FileWriter(String fileName) 此构造一个文件字符写对象给出文件名。

5

FileWriter(String fileName, boolean append) 此构造函数一个文件字符写对象给出一个布尔值,指示是否附加写入数据的文件名。

(3)、示例

代码如下,如果加了append为true则后续追加的内容会添加到文件中,否则会创建新的文件:

package com.xiaoyaoyou.day10;

import java.io.FileWriter;
import java.io.IOException;

public class FileWriterReaderTest {
public static void main(String[] args) throws IOException {
FileWriter fileWriter = new FileWriter("/Users/yz/work/1.txt", true);
fileWriter.append("你好吗?").append("我很好。").append("谢谢");
fileWriter.close();
}
}

append为true的结果:

Java从入门到实战总结-3.3、Java的IO处理_路径名_03

没有append的结果:

Java从入门到实战总结-3.3、Java的IO处理_java_04

package com.xiaoyaoyou.day10;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class FileWriterReaderTest {
public static void main(String[] args) throws IOException {
FileWriter fileWriter = new FileWriter("/Users/yz/work/1.txt");
fileWriter.append("你好吗?").append("我很好。").append("谢谢");
fileWriter.close();
FileReader fileReader = new FileReader("/Users/yz/work/1.txt");
char[] chars = new char[100];
int len = fileReader.read(chars);
String text = new String(chars);
System.out.println(text);
System.out.println(text.length());
String res = new String(chars, 0, len);
System.out.println(text);
System.out.println(res.length());
fileReader.close();
}
}

结果(不设置长度的话会有很多空字符):

你好吗?我很好。谢谢
100
你好吗?我很好。谢谢
10

9、flush刷新管道

默认关闭文件时会执行一次刷新。当不关闭时写入则需要调用flush()进行写入,再比如循环写入时记得及时刷新,否则可能导致未及时写入。

10、字节装饰为字符流InputStreamReader和OutputStreamWriter

使用了装饰者设计模式,把字节流装饰为字符流。

Java.io.InputStreamReader 类是一座桥从字节流与字符流。它读取字节并将其解码为使用指定的字符集的字符。

类构造函数:

序号

构造函数& 描述

1

InputStreamReader(InputStream in) 这将创建一个使用默认字符集的输入流。

2

InputStreamReader(InputStream in, Charset cs) 这将创建一个使用给定字符集的输入流。

3

InputStreamReader(InputStream in, CharsetDecoder dec) 这将创建一个使用给定的charset解码器的输入流。

4

InputStreamReader(InputStream in, String charsetName) 这将创建一个使用指定的字符集的输入流。

类方法:

序号

方法 & 描述

1

​void close() ​​ 此方法关闭该流并释放与之关联的所有系统资源。

2

​String getEncoding() ​​ 此方法返回正在使用此流的字符编码的名称。

3

​int read() ​​ 此方法读取单个字符。

4

[int read(char​​] cbuf, int offset, int length) ​​ 此方法读取字符到一个数组中的一部分。

5

​boolean ready() ​​ 此方法通知此流是否已准备好被读取。

Java.io.OutputStreamWriter 类是从字符流桥接字节流。写入字符编码成使用指定的字符集的字节。

类构造函数:

序号

构造函数& 描述

1

OutputStreamWriter(OutputStream out) 这将创建一个使用默认的字符编码的OutputStreamWriter。

2

OutputStreamWriter(OutputStream out, Charset cs) 这将创建一个使用给定字符集的OutputStreamWriter。

3

OutputStreamWriter(OutputStream out, CharsetEncoder enc) 这将创建一个使用给定的charset编码器的OutputStreamWriter。

4

OutputStreamWriter(OutputStream out, String charsetName) 这将创建一个使用指定的字符集的OutputStreamWriter。

类方法:

序号

方法 & 描述

1

​void close() ​​ 此方法关闭该流,但要先刷新它。

2

​void flush() ​​ 此方法刷新流。

3

​String getEncoding() ​​ 此方法返回正在使用此流的字符编码的名称。

4

[void write(char​​] cbuf, int off, int len) ​​ 此方法写入字符数组的一部分。

5

​void write(int c)​​ 此方法写入的单个字符。

6

​void write(String str, int off, int len) ​​ 此方法将写入一个字符串的一部分。

package com.xiaoyaoyou.day10;

import java.io.*;

public class ByteCharExchangeTest {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("/Users/yz/work/1.txt");
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "utf8");
while (true) {
int c = inputStreamReader.read();
if (c == -1) {
break;
}
System.out.println((char)c);
}

FileOutputStream fileOutputStream = new FileOutputStream("/Users/yz/work/1.txt");
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
outputStreamWriter.write("哈哈哈");
outputStreamWriter.flush();
outputStreamWriter.close();
}
}

结果:










Java从入门到实战总结-3.3、Java的IO处理_字符串_05

11、打印流和缓存流Print和Buffered

这里主要是格式化字节流,便于将字节流输出或输入为字符流,相对于刚才的文件流装饰,还可以用于其它位置读取或者写入的字节流进行格式化。

(1)、PrintStream和PrintWriter

A、PrintStream

Java.io.PrintStream类添加功能到另一个输出流,打印各种数据值表示形式方便的能力。

类构造函数:

序号

构造函数& 描述

1

PrintStream(File file) 这将创建一个新的打印流,与指定的文件无自动行刷新。

2

PrintStream(File file, String csn) 这将创建一个新的打印流,无自动行刷新,指定文件和字符集。

3

PrintStream(OutputStream out) 这将创建一个新的打印流。

4

PrintStream(OutputStream out, boolean autoFlush) 这将创建一个新的打印流。

5

PrintStream(OutputStream out, boolean autoFlush, String encoding) 这将创建一个新的打印流。

6

PrintStream(String fileName) 这将创建一个新的打印流,无自动行刷新的,与指定的文件名。

7

PrintStream(String fileName, String csn) 这将创建一个新的打印流,无自动行刷新,用指定的文件名和字符集。

类方法:

序号

方法 & 描述

1

​PrintStream append(char c) ​​ 此方法将指定字符追加到当前输出流。

2

​PrintStream append(CharSequence csq) ​​ 此方法将指定的字符序列此输出流。

3

​PrintStream append(CharSequence csq, int start, int end) ​​ 此方法将指定的字符序列的子序列来此输出流。

4

​boolean checkError() ​​ 此方法刷新流并检查其错误状态。

5

​protected void clearError() ​​ 此方法清除该流的内部错误状态。

6

​void close() ​​ 此方法关闭该流。

7

​void flush() ​​ 此方法刷新流。

8

​PrintStream format(Locale l, String format, Object… args) ​​ 此方法写入一个格式化字符串使用指定格式字符串和参数此输出流。

9

​PrintStream format(String format, Object… args) ​​ 此方法写入一个格式化字符串使用指定格式字符串和参数此输出流。

10

​void print(boolean b) ​​ 此方法打印一个布尔值。

11

​void print(char c) ​​ 这种方法打印的字符。

12

​void print(char[] s) ​​ 这种方法打印一个字符数组。

13

​void print(double d) ​​ 此方法打印一个双精度浮点数。

14

​void print(float f) ​​ 此方法打印一个浮点数。

15

​void print(int i) ​​ 此方法打印一个整数-int。

16

​void print(long l) ​​ 此方法打印一个长整数-long。

17

​void print(Object obj) ​​ 此方法打印一个对象。

18

​void print(String s) ​​ 此方法打印一个字符串。

19

​PrintStream printf(Locale l, String format, Object… args) ​​ 这是一个方便的方法使用指定格式字符串和参数将格式化字符串写入此输出流。

20

​PrintStream printf(String format, Object… args) ​​ 这是一个方便的方法使用指定格式字符串和参数将格式化字符串写入此输出流。

21

​void println() ​​ 此方法通过写入行分隔符字符串终止当前行。

22

​void println(boolean x) ​​ 此方法打印一个布尔值,然后终止该行。

23

​void println(char x) ​​ 此方法打印一个字符,然后终止该行。

24

​void println(char[] x) ​​ 此方法打印字符数组,然后终止该行。

25

​void println(double x) ​​ 此方法打印double,然后终止该行。

26

​void println(float x) ​​ 此方法打印一个float,然后终止该行。

27

​void println(int x) ​​ 此方法打印一个整数int,然后终止该行。

28

​void println(long x) ​​ 此方法打印一个long,然后终止该行。

29

​void println(Object x) ​​ 此方法打印一个对象,然后终止该行。

30

​void println(String x) ​​ 此方法打印一个String,然后终止该行。

31

​protected void setError() ​​ 此方法设置流的错误状态为true。

32

​void write(byte[] buf, int off, int len) ​​ 此方法从指定的字节数组开始,在这个流offset偏移写入len字节。

33

​void write(int b) ​​ 此方法将指定字节写入此流。

B、PrintWriter

Java.io.PrintWriter 类打印格式化对象的表示到文本输出流。

类构造函数:

序号

构造函数& 描述

1

PrintWriter(File file) 这将创建一个新的PrintWriter,不带自动行刷新指定文件。

2

PrintWriter(File file, String csn) 这将创建一个新的PrintWriter,不带自动行刷新的指定文件和字符集。

3

PrintWriter(OutputStream out) 这将创建一个新的PrintWriter,无自动行刷新,从现有的OutputStream。

4

PrintWriter(OutputStream out, boolean autoFlush) 这将创建从现有的OutputStream一个新的PrintWriter。

5

PrintWriter(String fileName) 这将创建一个新的PrintWriter,无自动行刷新,用指定的文件名。

6

PrintWriter(String fileName, String csn) 这将创建一个新的PrintWriter,无自动行刷新,用指定的文件名和字符集。

7

PrintWriter(Writer out) 这将创建一个新的PrintWriter,无自动行刷新。

8

PrintWriter(Writer out, boolean autoFlush) 这将创建一个新的PrintWriter。

类方法:

序号

方法 & 描述

1

​PrintWriter append(char c) ​​ 此方法将指定字符追加到这个writer。

2

​PrintWriter append(CharSequence csq) ​​ 此方法将指定的字符序列到此writer。

3

​PrintWriter append(CharSequence csq, int start, int end) ​​ 此方法将指定的字符序列的子序列写入此writer。

4

​boolean checkError() ​​ 这个方法刷新流,如果它冇有关闭,并检查其错误状态。

5

​protected void clearError() ​​ 这种方法清除该流的错误状态…

6

​void close() ​​ 此方法关闭该流并释放与之关联的所有系统资源。

7

​void flush() ​​ 此方法刷新该流…

8

​PrintWriter format(Locale l, String format, Object… args) ​​ 使用指定的格式字符串和参数此方法写入一个格式化的字符串写入此writer…

9

​PrintWriter format(String format, Object… args) ​​ 使用指定的格式字符串和参数此方法写入一个格式化的字符串写入此writer…

10

​void print(boolean b) ​​ 此方法打印一个布尔值。

11

​void print(char c) ​​ 此方法打印的字符。

12

​void print(char[] s) ​​ 此方法打印一个字符数组…

13

​void print(double d) ​​ 此方法打印一个双精度浮点数。

14

​void print(float f) ​​ 此方法打印一个浮点数。

15

​void print(int i) ​​ 此方法打印一个整数。

16

​void print(long l) ​​ 此方法打印一个长整数。

17

​void print(Object obj) ​​ 此方法打印对象。

18

​void print(String s) ​​ 此方法打印一个字符串。

19

​PrintWriter printf(Locale l, String format, Object… args) ​​ 这是一个方便的方法使用指定格式字符串和参数将格式化字符串写入此writer中。

20

​PrintWriter printf(String format, Object… args) ​​ 这是一个方便的方法使用指定格式字符串和参数将格式化字符串写入此writer中。

21

​void println() ​​ 此方法通过写入行分隔符字符串终止当前行。

22

​void println(boolean x) ​​ 此方法打印一个布尔值,然后终止该行。

23

​void println(char x) ​​ 此方法打印一个字符,然后终止该行。

24

​void println(char[] x) ​​ 此方法将打印的字符数组,然后终止该行。

25

​void println(double x) ​​ 此方法打印一个双精度浮点数,然后终止该行。

26

​void println(float x) ​​ 此方法打印一个浮点数,然后终止该行。

27

​void println(int x) ​​ 此方法将打印的整数,然后终止该行。

28

​void println(long x) ​​ 此方法打印一个长整数,然后终止该行。

29

​void println(Object x) ​​ 此方法打印一个对象,然后终止该行。

30

​void println(String x) ​​ 此方法打印一个String,然后终止该行

31

​protected void setError() ​​ 此方法表明发生了错误。

32

​void write(char[] buf) ​​ 此方法写入字符数组。

33

​void write(char[] buf, int off, int len) ​​ 此方法写入字符数组的一部分。

34

​void write(int c) ​​ 此方法写入的单个字符。

35

​void write(String s) ​​ 此方法写入一个字符串。

36

​void write(String s, int off, int len) ​​ 此方法将一个字符串的一部分写入。

(2)、Buffered

A、BufferedReader

Java.io.BufferedReader 类从字符输入流中读取文本,缓冲各个字符,从而提供字符,数组和行的高效读取。以下是有关的BufferedReader要点:

  • 缓冲区的大小可以被指定或默认的大小也可使用。
  • Reader的每一个读取请求会导致相应的读取请求底层字符或字节流。

类构造方法:

序号

构造函数& 描述

1

BufferedReader(Reader in) 这将创建一个使用默认大小输入缓冲区的缓冲字符输入流。

2

BufferedReader(Reader in, int sz) 这将创建一个使用指定大小输入缓冲区的缓冲字符输入流。

类方法:

序号

方法与说明

1

​void close() ​​ 此方法关闭该流并释放与之关联的所有系统资源。

2

​void mark(int readAheadLimit) ​​ 此方法标记流中的当前位置。

3

​boolean markSupported() ​​ 这个方法告诉此流是否支持mark()操作,这确实如此。

4

​int read() ​​ 此方法读取单个字符。

5

​int read(char[] cbuf, int off, int len)​​ 此方法读取字符到一个数组中的一部分。

6

​String readLine() ​​ 此方法读取一行文本。

7

​boolean ready() ​​ 这个方法告诉此流是否已准备好被读取。

8

​void reset() ​​ 这个方法重置流。

9

​long skip(long n) ​​ 此方法跳过n个字符。

B、BufferedWriter

Java.io.BufferedWriter 类将文本写入字符输出流,缓冲各个字符,从而提供单个字符,数组和字符串的高效写入。以下是有关的BufferedWriter要点:

  • 缓冲区的大小可以被指定或默认的大小也可使用。
  • Writer 发送其输出到底层字符或字节流。

构造函数:

序号

构造函数与说明

1

BufferedWriter(Writer out) 这将创建一个使用默认大小输出缓冲区的缓冲字符输出流。

2

BufferedWriter(Writer out, int sz) 这将创建一个使用给定大小的输出缓冲区的新缓冲字符输出流。

类方法:

序号

方法与说明

1

​void close() ​​ 此方法关闭该流,但要先刷新它。

2

​void flush() ​​ 这个方法刷新流。

3

​void newLine() ​​ 此方法写入一个行分隔符。

4

[void write(char​​] cbuf, int off, int len) ​​ 此方法写入字符数组的一部分。

5

​void write(int c) ​​ 此方法写入的单个字符。

6

​void write(String s, int off, int len) ​​ 此方法写入一个字符串的一部分。

(3)、示例

package com.xiaoyaoyou.day10;

import java.io.*;

public class PrintAndBufferedTest {
public static void main(String[] args) throws IOException {
PrintStream printStream = new PrintStream("/Users/yz/work/1.txt");
printStream.println("哈哈哈啊哈哈哈");
printStream.println("哈哈哈啊哈哈哈");
printStream.flush();

FileReader fileReader = new FileReader("/Users/yz/work/1.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
System.out.println(fileReader.read());
System.out.println(bufferedReader.read());
System.out.println(bufferedReader.readLine());

FileWriter fileWriter = new FileWriter("/Users/yz/work/1.txt", true);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.write("测试一下");
bufferedWriter.close();
}
}

结果:

21704
21704
哈啊哈哈哈

print字符格式化打印到文件中:

Java从入门到实战总结-3.3、Java的IO处理_java_06

Buffered缓存后写入:

Java从入门到实战总结-3.3、Java的IO处理_字符串_07

12、收集异常日志

将printStackTrace的异常日志通过printWriter写入到文件中,用来收集异常日志到文件中。

package com.xiaoyaoyou.day10;

import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.SimpleTimeZone;

public class PrintStackTraceWriterTest {
public static void main(String[] args) throws FileNotFoundException {
try {
String s = null;
s.toString();
}catch (Exception e) {
PrintWriter printWriter = new PrintWriter("/Users/yz/work/bug.txt");
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
printWriter.println(simpleDateFormat.format(new Date()));
e.printStackTrace(printWriter);
printWriter.close();
}
}
}

结果:

Java从入门到实战总结-3.3、Java的IO处理_路径名_08

13、java.util.Properties

可以以map形式存储到文件中。

java.util.Properties类是代表一个持久的一套详细属性,属性可以被保存到一个流或从流中加载的类。以下是关于属性的要点:

  • 属性列表中每个键及其对应值是一个字符串。
  • 一个属性列表可包含另一个属性列表作为它的“默认”,第二个属性可在列表中搜索,如果冇有在原有的属性列表中找到的属性键。
  • 这个类是线程安全的;多个线程可以共享一个Properties对象,而不需要外部同步。

构造函数:

SN

构造函数& 描述

1

Properties() 这种构造创建一个空的属性列表,冇有默认值。

2

Properties(Properties defaults) 这种构造创建一个空的属性列表中具有指定默认值。

类方法:

SN

方法& 描述

1

​String getProperty(String key)​​ 该方法将搜索具有此属性列表中指定键的属性。

2

​String getProperty(String key, String defaultValue) ​​ 该方法将搜索具有此属性列表中指定键的属性。

3

​void list(PrintStream out) ​​ 这种方法打印属性列表输出到指定的输出流。

4

​void list(PrintWriter out) ​​ 这种方法打印属性列表输出到指定的输出流。

5

​void load(InputStream inStream) ​​ 此方法读取属性列表(键和元素对)从输入字节流。

6

​void load(Reader reader) ​​ 这个方法从一个简单的面向行的格式输入字符流中读取属性列表(键和元素对)。

7

​void loadFromXML(InputStream in) ​​ 此方法加载所有指定的输入流中到此属性表中的XML文档所表示的所有属性。

8

​Enumeration propertyNames() ​​ 此方法返回属性列表中所有键,包括默认属性列表中不同的键的枚举,如果尚未发现从主属性列表中名称相同的键。

9

​void save(OutputStream out, String comments)​​ 此方法读取a

10

​Object setProperty(String key, String value) ​​ 此方法调用Hashtable的put()方法。

11

​void store(OutputStream out, String comments)​​ 该方法写入此属性列表(键和元素对)在此属性表中适于装成一个属性表中使用load(InputStream)方法的格式输出流。

10

​void store(Writer writer, String comments) ​​ 该方法写入此属性列表(键和元素对)在此属性表中适合使用load(Reader)方法的格式输出字符流。

11

​void storeToXML(OutputStream os, String comment) ​​ 这个方法会发出代表所有包含在此表中的属性的XML文档。

12

​void storeToXML(OutputStream os, String comment, String encoding) ​​ 这个方法会发出代表所有包含在此表中的属性的XML文档,使用指定的编码。

13

​Set stringPropertyNames() ​​ 此方法返回一组键在此属性列表,其中的键及其对应值是字符串,包括默认属性列表中不同的键,如果尚未发现从主属性列表中同名的键。

示例:

package com.xiaoyaoyou.day10;

import java.io.*;
import java.util.Properties;

public class PropertiesTest {
public static void main(String[] args) throws IOException {
Properties properties = new Properties();
properties.put("company", "顺丰");
properties.put("code", "123456");
properties.put("num", "123");
FileOutputStream fileOutputStream = new FileOutputStream("/Users/yz/work/express.txt");
properties.storeToXML(fileOutputStream, "存储的快递", "UTF-8");
fileOutputStream.close();

Reader reader = new FileReader("/Users/yz/work/express.txt");
properties.load(reader);
System.out.println(properties.getProperty("company"));
System.out.println(properties.getProperty("code"));
System.out.println(properties.getProperty("num"));
}
}

结果:

顺丰
123456
123

Java从入门到实战总结-3.3、Java的IO处理_字符串_09

14、序列化和反序列化

序列化和反序列化用的非常多,分布式技术以及大多框架都在使用,但是Java官方发现其会产生大量的bug,因此宣布将在后续逐渐在JDK中取消序列化和反序列化相关内容。

我们把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。

序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。

反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化。

package com.xiaoyaoyou.day10;

import java.io.*;

public class ObjectStreamTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Book b = new Book("金苹果", "讲述了果农种植苹果发家致富的过程");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("/Users/yz/work/book.txt"));
objectOutputStream.writeObject(b);
objectOutputStream.close();

ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("/Users/yz/work/book.txt"));
Book book = (Book) objectInputStream.readObject();
System.out.println(book.getInfo());
}

static class Book implements Serializable {
private String name;
private String info;

public Book() {
}

public Book(String name, String info) {
this.name = name;
this.info = info;
}

@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", info='" + info + '\'' +
'}';
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getInfo() {
return info;
}

public void setInfo(String info) {
this.info = info;
}
}
}

结果:

讲述了果农种植苹果发家致富的过程

该文件在mac上预览如下,实际上打开应该是一堆乱码:

Java从入门到实战总结-3.3、Java的IO处理_路径名_10

15、try-with-resources

在try()中进行new的对象存在close时在调用结束后会自动调用close方法。

package com.xiaoyaoyou.day10;

import com.xiaoyaoyou.bean.Express;

import java.io.*;

public class TryCatchTest {
public static void main(String[] args) throws FileNotFoundException {
//1.7之前
/*FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream("/Users/yz/work/1.txt");
int c = fileInputStream.read();
System.out.println((char)c);
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}*/

//1.7时,finally会自动调用关闭
/*try(FileInputStream fileInputStream = new FileInputStream("/Users/yz/work/1.txt")) {
int c = fileInputStream.read();
System.out.println((char)c);
} catch (IOException e) {
e.printStackTrace();
}*/

//JDK9进行优化
FileInputStream fileInputStream = new FileInputStream("/Users/yz/work/1.txt");
PrintWriter printWriter = new PrintWriter("/Users/yz/work/1.txt");
try(fileInputStream;printWriter) {
int c = fileInputStream.read();
System.out.println((char)c);
} catch(Exception e) {
e.printStackTrace();
}

CloseDemo closeDemo = new CloseDemo();
try(closeDemo) {

} catch (Exception e) {

}
}

static class CloseDemo implements Closeable {

@Override
public void close() throws IOException {
System.out.println("调用了close方法");
}
}
}