1 文件
1.1 文件流的相关概念
流:数据在数据源(文件)和程序(内存)之间经历的路径
输入流:数据从数据源(文件)到程序(内存)的路径
输出流:数据从程序(内存)到数据源(文件)的路径
1.2 常用的文件操作
1.2.1 创建文件对象
public class File_ {
public static void main(String[] args) throws IOException {
//1.根据路径构建一个File对象
String pathname = "d:/fileTest1.txt";
File file1 = new File(pathname);
file1.createNewFile();
//2.根据父目录文件和子路径构建
File parent = new File("d:/");
File file2 = new File(parent, "fileTest2.txt");
file2.createNewFile();
//3.根据父目录和子路径构建
File file3 = new File("d:/", "fileTest3.txt");
file3.createNewFile();
}
}
1.2.2 获取文件的相关信息
public class File_ {
public static void main(String[] args) throws IOException {
String pathname = "d:/fileTest1.txt";
File file = new File(pathname);
//1.getName 获取文件名
System.out.println(file.getName());
//2.getAbsolutePath 获取文件绝对路径
System.out.println(file.getAbsolutePath());
//3.getParent 获取文件父级目录
System.out.println(file.getParent());
//4.length 文件大小(字节)
System.out.println(file.length());
//5.exists 文件是否存在
System.out.println(file.exists());
//6.isFile 判断是不是一个文件
System.out.println(file.isFile());
//7.isDirectory 判断是不是一个目录
System.out.println(file.isDirectory());
}
}
- result
fileTest1.txt
d:\fileTest1.txt
d:\
0
true
true
false
2 IO 流原理及流的分类
2.1 IO 流的分类
- 按操作数据单位不同分为:字节流(8 bit)二进制文件,字符流(按字符)文本文件
- 按数据流的流向不同分为:输入流,输出流
- 按流的角色的不同分为:节点流,处理流(包装流)
2.2 IO 流的体系图
image-20210518150008681.png3 FileInputStream和FileOutputStream
说明:使用这两个类可以实现对二进制文件的读入和写出,节点流
//使用FileInputStream 和 FileOutputStream 实现对照片的拷贝
public class FileCopy {
public static void main(String[] args) {
String srcPathName = "d:/testPicture.png";
String destPathName = "d:/testPicture_new.png";
FileInputStream fis = null;
FileOutputStream fos = null;
int readLen = 0;
byte[] buf = new byte[1024];
try {
fis = new FileInputStream(srcPathName);
fos = new FileOutputStream(destPathName);
//每次读入1024字节内容至缓冲区,返回实际存储至缓冲区的字节数
while ((readLen = fis.read(buf)) != -1) {
fos.write(buf, 0, readLen);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4 FileReader 和 FileWriter
说明:使用这两个类可以实现对字符的输入输出,FileWriter使用后,必须关闭或刷新,否则写入不到指定的文件
public class FileReaderWriter {
public static void main(String[] args) {
String srcFilePath = "d:/testFile.txt";
String destFilePath = "d:/testFile_new.txt";
FileReader fr = null;
FileWriter fw = null;
int readLen = 0;
char[] buf = new char[8];
try {
fr = new FileReader(srcFilePath);
fw = new FileWriter(destFilePath);
//每次读入8字符内容至缓冲区,返回实际存储至缓冲区的字符数
while ((readLen = fr.read(buf)) != -1) {
fw.write(buf, 0, readLen);
//打印字符到屏幕
System.out.println(new String(buf,0,readLen));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fr != null) {
fr.close();
}
if (fw != null) {
fw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5 节点流和处理流
5.1 基本说明
- 节点流:可以从一个特定的数据源读写数据,如 FileReader,FileWriter
- 处理流/包装流:连接在已存在的流之上,为程序提供更强大的读写功能,更灵活,如 BufferedReader,BufferedWriter
5.2 节点流和处理流的区别
- 节点流是底层流/低级流,直接跟数据源相接
- 处理流包装节点流,既可以消除不同节点流的实现差异,也可以提供方便的方法实现输入输出。
- 处理流采用修饰器模式,不会直接于数据源连接
6 BufferedReader 和 BufferedWriter
6.1 基本说明
- Buffer额度Reader 和 BufferedWriter 属于字符流,是按照字符来读取数据的
- 关闭时只需要关闭最外层流即可
- 不能操作二进制文件,由于其是以字符的形式流动,故会造成二进制文件的损坏
6.2 示例
说明:使用这两个类可以实现对文本文件的读入和写出,包装流
public class BufferedReaderWriter {
public static void main(String[] args) {
//获取resources目录下的文件方法(target目录下)
String srcFilePath = Thread.currentThread().getContextClassLoader().getResource("testFile.txt").getPath();
String destFilePath = Thread.currentThread().getContextClassLoader().getResource("testFile_new.txt").getPath();
BufferedReader br = null;
BufferedWriter bw = null;
String line;
try {
br = new BufferedReader(new FileReader(srcFilePath));
bw = new BufferedWriter(new FileWriter(destFilePath));
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close();
}
if (bw != null) {
bw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
7 BufferedInputStream 和 BufferedOutputStream
说明:使用这两个类可以实现对二进制文件的读入和写出,包装流
public class BufferedInputStreamOutputStream {
public static void main(String[] args) {
String srcFilePath = Thread.currentThread().getContextClassLoader().getResource("testFile.txt").getPath();
String destFilePath = Thread.currentThread().getContextClassLoader().getResource("testFile_new.txt").getPath();
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
byte[] buf = new byte[64];
int len = 0;
try {
bis = new BufferedInputStream(new FileInputStream(srcFilePath));
//true 表示追加
bos = new BufferedOutputStream(new FileOutputStream(destFilePath,true));
while ((len = bis.read(buf)) != -1) {
bos.write(buf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bis != null) {
bis.close();
}
if (bos != null) {
bos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
8 对象流 ObjectInputStream 和 ObjectOutputStream
8.1 对象流说明
-
将Java对象保存至文件中称为序列化,将文件中的数据(值和类型)恢复为Java对象称为反序列化
-
序列化和普通的保存不同之处在于,普通的保存只存储值,而序列化会保存值和数据类型
-
对象流提供了对基本类型和对象类型的序列化和反序列化
8.2 序列化说明
- 读写顺序要相同,按什么顺序序列化就需要按什么顺序反序列化
- 要求序列化或反序列化对象,实现Serializable接口
- 序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性
- 序列化对象时,默认将所有属性序列化,除了static和transient修饰的成员
- 序列化对象时,要求属性的类型需要实现序列化接口
- 序列化具备可继承性,如果某个类已经实现序列化,则它的所有子类也默认实现序列化
8.3 示例
- 序列化
说明:使用 ObjectOutputStream 序列化基本数据类型和自定义对象,包装流
- 反序列化
说明:使用 ObjectInputStream 反序列化上述内容,包装流
public class ObjectInputStreamOutputStream {
public static void main(String[] args) {
serialFunc();
deserialFunc();
}
//反序列化
public static void deserialFunc(){
String objectPath = Thread.currentThread().getContextClassLoader().getResource("objectFile.txt").getPath();
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(objectPath));
//反序列化基本类型
System.out.println(ois.readInt());
System.out.println(ois.readBoolean());
System.out.println(ois.readUTF());
//反序列化自定义对象
System.out.println(ois.readObject());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (ois !=null){
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//序列化
public static void serialFunc(){
String objectPath = Thread.currentThread().getContextClassLoader().getResource("objectFile.txt").getPath();
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream(objectPath));
//序列化基本类型
oos.writeInt(233);
oos.writeBoolean(false);
oos.writeUTF("hello world");
//序列化自定义对象
oos.writeObject(new Person("yorick",24));
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (oos !=null){
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
9 标准输入输出流
9.1 基本说明
- System.in 标准输入,类型是InputStream(BufferedInputStream),默认设备为键盘
- System.out 标准输出,类型是PrintStream,默认设备为显示器
10 转换流 InputStreamReader 和 OutputStreamWriter
10.1 基本说明
- 若本地文件采用gbk编码,则使用字符输入流读入默认采用的为utf-8编码,会导致出现乱码。可以借助 字节输入流转换编码,再使用字符输入流读入,故需要借助转换流转换
- InputStreamReader 是 Reader 的子类,可以将 InputStream 包装为 Reader
- OutputStreamWriter 是 Writer 的子类,可以将 OutputStream 包装为 Writer
10.2 示例
说明:将gbk编码的文件,读入不产生乱码
public class InputStreamReaderOutputStreamWriter {
public static void main(String[] args) {
String srcFilePath = Thread.currentThread().getContextClassLoader().getResource("testFile.txt").getPath();
BufferedReader br = null;
String line;
try {
//将其进行层层包装
br = new BufferedReader(new InputStreamReader(new FileInputStream(srcFilePath),"gbk"));
while ((line = br.readLine())!=null){
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br !=null){
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
11 打印流 PrintStream 和 PrintWriter
11.1 基本说明
-
打印流只有输出流,没有输入流
-
PrintStream 间接继承 OutputStream,PrintWriter 继承 Writer
网友评论