《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门,即可获取!
注:当编码方式和解码方式不一致时,就会出现乱码!
五、字符流
引入:3个字节相当于一个字符,当我们要读取汉字(字符)时,如果用字节流来读取的话,他是一个一个字节读取的,最终的结果是字节,而不是我们想要的字符了!
字符流的两个父类(抽象类):
Reader
:字符输入流
常用方法:
public int read() {}
public int read(char[] c) {}
public int read(char[] b, int off, int len) {}
Write
:字符输出流
常用方法:
public void write(int n) {}
public void write(String str) {}
public void write(char[] c) {}
文件字符流
FileReader
——文件字符输入流
阅读字符文件的便利课。 该类的构造函数假定默认字符编码和默认字节缓冲区大小是适当的。 要自己指定这些值,请在FileInputStream上构造一个InputStreamReader。
FileReader
是用于读取字符流。 要读取原始字节流,请考虑使用 FileInputStream
。
public class FileReader extends InputStreamReader
构造方法:
常用方法:继承父类!
public int read(char[] c);
从流中读取多个字符,讲读到内容存入c数组,返回实际读到的字符数;如果文件达到尾部,则返回-1.
【参考代码】
import java.io.FileReader;
public class FileReaderDemon {
public static void main(String[] args) throws Exception{
//1. 创建FileReader 文件字符输入流
FileReader fr = new FileReader(“d:\\hello.txt”);
//2. 读取
//2.1 单个读取
// int data = 0;
// while ((data = fr.read()) != -1){ // 读取一个字符!
// System.out.println((char)data);
// }
char[] buf = new char[1024];
int count = 0;
while((count = fr.read(buf)) != -1){
System.out.println(new String(buf, 0, count));
}
//3. 关闭
fr.close();
}
}
FileWriter
——文件字符输出流
public void write(String str);
一次写入多个字符,将b数组中所有字符,写入输出流;
【参考代码】
import java.io.FileWriter;
public class FileWriterDemon {
public static void main(String[] args) throws Exception{
//1. 创建FileWriter对象
FileWriter fw = new FileWriter(“d:\\write.txt”);
//2. 写入字符
String str = “防不胜防”;
for(int i = 0; i < str.length(); i ++){
fw.write(str);
fw.flush();
}
//3. 关闭
fw.close();
System.out.println(“执行完毕”);
}
}
案例:文件字符流实现文本文件复制
注: FileReader、FileWriter
只能复制文本文件,不能复制图片或者二进制文件!—— 文本文件有字符编码!
【参考代码】
import java.io.FileReader;
import java.io.FileWriter;
public class CopyDemon {
public static void main(String[] args) throws Exception{
//1. 创建FileReader FileWriter 对象
FileReader fr = new FileReader(“d:\\write.txt”);
FileWriter fw = new FileWriter(“d:\\write2.txt”);
//2. 读写
int data = 0;
while((data = fr.read()) != -1){
fw.write(data);
fw.flush();
}
//3. 关闭
fr.close();
fw.close();
System.out.println(“复制完毕!”);
}
}
字符缓冲流
字符缓冲流: BufferedReader/BufferedWriter
(1)高效读写
(2)支持输入换行
(3)可一次写一行,读一行。
BufferedReader
——字符缓冲输入流
从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取。
可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途。
通常,由读取器做出的每个读取请求将引起对底层字符或字节流的相应读取请求。 因此,建议将BufferedReader包装在其read()操 作可能昂贵的读取器上,例如FileReader
BufferedReader in = new BufferedReader(new FileReader(“foo.in”));
将缓冲指定文件的输入。 没有缓冲,每次调用read()或readLine()可能会导致从文件中读取字节,转换成字符,然后返回,这可能非常低效。
构造方法:
常用方法:
【参考代码】
``
import java.io.BufferedReader;
import java.io.FileReader;
/**
* 字符缓冲流读取文件
*/
public class BufferedReaderDemon {
public static void main(String[] args) throws Exception{
//1. 创建缓冲流
FileReader fr = new FileReader(“d:\\write.txt”);
BufferedReader br = new BufferedReader(fr);
//2. 读取
//2.1 第一种读取方式
// char[] buf = new char[1024];
// int count = 0;
// while ((count = br.read(buf)) != -1){
// System.out.println(new String(buf, 0, count));
// }
//2.2 第二种读取方式。 一行一行的读取
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
//3. 关闭
br.close();
}
}
BufferedWriter
——字符缓冲输出流(写入字符)
将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入。
可以指定缓冲区大小,或者可以接受默认大小。 默认值足够大,可用于大多数用途。
提供了一个newLine()方法,它使用平台自己的系统属性 line.separator
定义的行分隔符概念。 并非所有平台都使用换行符(‘\ n’)来终止行。 因此,调用此方法来终止每个输出行,因此优选直接写入换行符。
构造方法:
常用方法:
【参考代码】
import java.io.BufferedWriter;
import java.io.FileWriter;
public class BufferedWriterDemon {
public static void main(String[] args) throws Exception{
//1. 创建BufferedWriter对象
FileWriter fw = new FileWriter(“d:\\buffer.txt”);
BufferedWriter bw = new BufferedWriter(fw);
//2. 写入
for (int i = 0; i < 5; i ++){
bw.write(“好好学习吧!”);
bw.newLine();// 换行!
bw.flush();
}
//3. 关闭
bw.close();
}
}
打印流
PrintWriter
——打印流
将对象的格式表示打印到文本输出流。 这个类实现了全部在发现 print种
方法 PrintStream。 它不包含用于编写原始字节的方法,程序应使用未编码的字节流。
不像类,如果启用自动刷新,它只会在调用的 println,printf,
或 format
方法来完成,而不是当一个换行符恰好是输出。 这些方法使用平台自己的行分隔符而不是换行符。
转换流
转换流: InputStreamReader/OutputStreamWriter
(1)可以将字节流转为字符流
(2)可设置字符的编码方式
转换流的使用:
InputStreamReader读取文件
【参考代码】
import java.io.FileInputStream;
import java.io.InputStreamReader;
public class ZhuanHuanLiuTest {
public static void main(String[] args) throws Exception{
//1. 创建InputStreamReader对象
FileInputStream fis = new FileInputStream(“d:\\write.txt”);
InputStreamReader isr = new InputStreamReader(fis, “utf-8”); // 转换流设置编码方式
//2.读取文件
int data = 0;
while ((data = isr.read()) != -1){
System.out.println((char) data);
}
//3. 关闭
isr.close();
}
}
OutputStreamWriter——写入文件
【参考代码】
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
public class ZhuanHuanLiuTest {
public static void main(String[] args) throws Exception{
//1. 创建OutputStreamWriter对象
FileOutputStream fos = new FileOutputStream(“d:\\info.txt”);
OutputStreamWriter osw = new OutputStreamWriter(fos, “gbk”); // 转换流设置编码方式
//2. 写入
for(int i = 0; i < 5; i ++){
osw.write(“我爱学习\r\n”);
osw.flush();
}
//3. 关闭
osw.close();
}
}
六、对象流
对象流: ObjectInputStream/ObjectOutputStream
。
(1)增强了缓冲区功能
(2)增强了读取8种基本数据类型和字符串功能
(3)增强了读写对象的功能:
readObject() 从流中读取一个对象(反序列化)
writeObject(Object obj) 向流中写入一个对象(序列化)
使用流传输对象的过程称为序列化,和反序列化。
- 对象输出流:
ObjectOutputStream
——序列化(写入对象)
ObjectOutputStream将Java对象的原始数据类型和图形写入OutputStream。 可以使用ObjectInputStream读取(重构)对象。 可以 通过使用流的文件来实现对象的持久存储。 如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象。
构造方法:
常用方法:
【参考代码】
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class ObjectOutputStreamDemon {
/**
* 使用ObjectOutputStream实现对象的序列化————读入对象
* 要求:序列化类必须实现接口
*/
public static void main(String[] args) throws Exception{
//1. 创建对象流
FileOutputStream fos = new FileOutputStream(“d:\\stu.bin”);
ObjectOutputStream oos = new ObjectOutputStream(fos);
//2. 序列化(写入操作)
Student student = new Student(“张三”,19);
oos.writeObject(student);
//3. 关闭(自带flush()方法了)
oos.close();
System.out.println(“序列化完毕”);
}
}
class Student implements Serializable {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return “Student{” +
“name='” + name + ‘\’’ +
“, age=” + age +
‘}’;
}
}
使用ObjectOutputStream实现对象的序列化————写入对象
要求:序列化类必须实现接口
- 对象输入流:
ObjectInputStream
——反序列化(读取重构成对象)
ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象。
构造方法:
常用方法:
【参考代码】
import java.io.*;
public class ObjectInputStreamDemon {
public static void main(String[] args) throws Exception{
//1. 创建对象流
FileInputStream fis = new FileInputStream(“d:\\stu.bin”);
ObjectInputStream ois = new ObjectInputStream(fis);
//2. 读取文件(反序列化)
Student st = (Student) ois.readObject();
//3. 关闭
ois.close();
System.out.println(st.toString());// Student{name=‘张三’, age=19}
}
}
序列化和反序列化注意事项:
(1)序列化类必须实现 Serializable
接口
(2)序列化类中对象属性要求实现Serializable接口
(3)序列化版本号ID,保证序列化的类和反序列化的类是同一个类
(4)使用transient(瞬间的)修饰属性,这个属性不能序列化
(5)静态属性不能序列化
(6)序列化多个对象,可以借助集合
七、File类
概念:代表物理磁盘中的一个 文件 或者 文件夹(目录) 。
常用方法:
文件操作
(1)分隔符:
;
\
(2)文件操作:
- 创建文件
createNewFile()
boolean createNewFile()
当且仅当具有该名称的文件尚不存在时,原子地创建一个由该抽象路径名命名的新的空文件。
if(!file.exists()){ // 如果文件不存在则创建
boolean b = file.createNewFile();
System.out.println(“创建结果” + b);
}
- 删除文件
直接删除: delete()
boolean delete()
删除由此抽象路径名表示的文件或目录
JVM退出时删除:
file.deleteOnExit();
Thread.sleep(5000); // 休眠五秒
-
获取文件信息
-
getAbsolutePath()
:获取到文件的绝对路径 -
getPath()
:获取到文件的路径 -
getName()
:获取文件的名称 -
getParent()
:获取文件的父级目录 -
length()
:获取文件的长度 -
lastModified()
:获取文件的创建时间
System.out.println(“文件创建时间:” + new Date(file.lastModified()));
- 判断
canWrite()
isFile()
isHidden()
【参考代码】
import java.io.File;
import java.util.Date;
public class FileTest {
public static void main(String[] args) throws Exception{
fileOpe();
}
/**
* 文件操作
*/
public static void fileOpe() throws Exception{
//1. 创建文件
File file = new File(“d:\\file.txt”); // 只是创建了一个文件对象,此时在d盘下并没有该文件
if(!file.exists()){ // 如果文件不存在则创建
boolean b = file.createNewFile();
System.out.println(“创建结果” + b);
}
//2. 删除文件
//2.1 直接删除
// System.out.println(“删除结果” + file.delete());
// //2.2 JVM退出时删除
// file.deleteOnExit();
// Thread.sleep(5000); // 休眠五秒
//3. 获取文件信息
System.out.println(“获取文件绝对路径” + file.getAbsolutePath()); // 获取文件绝对路径d:\file.txt
System.out.println(“获取路径” + file.getPath());
System.out.println(“获取文件名称” + file.getName());
System.out.println(“获取文件父目录” + file.getParent());
System.out.println(“获取文件长度” + file.length());
System.out.println(“文件创建时间:” + new Date(file.lastModified()));
//4. 判断
System.out.println(“是否可写” + file.canWrite());
System.out.println(“是否是文件” + file.isFile());
System.out.println(“是否隐藏” + file.isHidden());
}
}
文件夹操作
- 创建文件夹
| boolean
| mkdir()
创建由此抽象路径名命名的目录。 |
| — | — |
| boolean
| mkdirs()
创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录。 |
File dir = new File(“d:\\aaa\\bbb\\ccc”);
if(! dir.exists()){
dir.mkdir();// 只能单级目录
System.out.println(“创建结果:” + dir.mkdirs()); //mkdirs();//可以创建多级目录
}
- 删除文件夹
直接删除: delete()
——只能删除空目录
JVM删除: file.deleteOnExit();Thread.sleep(5000);
// 休眠五秒
- 获取文件夹信息
getAbsolutePath()
getPath()
getName()
getParent()
lastModified()
- 判断
isDirectory()
isHidden()
- 遍历文件
(1) list()
//5. 遍历文件夹
File dir2 = new File(“e:\\picture”);
String[] files = dir2.list();
for(String str: files){
System.out.println(str);
}
(2) listFiles()
//5. 遍历文件夹
File dir2 = new File(“e:\\picture”);
File[] files = dir2.listFiles(); // 文件数组
for(File file: files){
System.out.println(file.getName());
}
FileFilter接口
当调用File类中的 listFiles()
方法时,支持传入 FileFilter
接口接口实现类,对获取文件进行过滤,只有满足条件的文件才可以出现在 listFiles()
方法的返回值中。
【参考代码】
File dir2 = new File(“e:\\picture”);
// 过滤:过滤出满足条件的文件
File[] file2 = dir2.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if(pathname.getName().endsWith(“.png”)){ // 只要.png结尾的图片
return true;
}
return false;
}
});
// 遍历输出
for(File file : file2){
System.out.println(file.getName());
}
递归遍历与删除
递归遍历文件夹:
遍历拿到 dir.listFiles()
路径的路径数组,数组不为空且有文件的情况下,如果是文件夹递归则进去,直到不是文件夹,然后输出文件,否则输出当前目录下的文件!
【参考代码】
import java.io.File;
public class ListDemon {
public static void main(String[] args) {
listDir(new File(“e:\\aaa”));
}
//递归遍历文件夹
public static void listDir(File dir){
File[] files = dir.listFiles();// 得到所有得子文件与子文件夹
System.out.println(“路径:”+ dir.getAbsolutePath());
if(files != null && files.length > 0){
for(File file : files){
if(file.isDirectory()){// 判断是否为文件夹
listDir(file); // 如果是文件夹递归进去,直到不是文件夹
}else{// 不是文件夹 则输出
System.out.println(file.getAbsolutePath());
}
}
}
}
}
我电脑E盘下的aaa文件如下图:
递归删除文件夹:
我们直到 delete()
方法只能删除空目录。如果目录里边有内容, delete()
方法是无法删除的,即我们想用 delete()
方法删除上述aaa文件是行不通的!
为此,我们得先将 aaa
文件中所有内容给删除之后,才能将 aaa
文件删除掉! aaa
里边有 bbb
文件夹,为此得先把它里边得内容先删掉, bbb
里边有 ccc
文件夹为此得先把它里边得内容先删掉…然后再逐步回退删除文件夹!
【参考代码】
import java.io.File;
public class ListDemon {
public static void main(String[] args) {
deleteDir(new File(“e:\\aaa”));
}
本次面试答案,以及收集到的大厂必问面试题分享:
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门,即可获取!
file2){
System.out.println(file.getName());
}
递归遍历与删除
递归遍历文件夹:
遍历拿到 dir.listFiles()
路径的路径数组,数组不为空且有文件的情况下,如果是文件夹递归则进去,直到不是文件夹,然后输出文件,否则输出当前目录下的文件!
【参考代码】
import java.io.File;
public class ListDemon {
public static void main(String[] args) {
listDir(new File(“e:\\aaa”));
}
//递归遍历文件夹
public static void listDir(File dir){
File[] files = dir.listFiles();// 得到所有得子文件与子文件夹
System.out.println(“路径:”+ dir.getAbsolutePath());
if(files != null && files.length > 0){
for(File file : files){
if(file.isDirectory()){// 判断是否为文件夹
listDir(file); // 如果是文件夹递归进去,直到不是文件夹
}else{// 不是文件夹 则输出
System.out.println(file.getAbsolutePath());
}
}
}
}
}
我电脑E盘下的aaa文件如下图:
递归删除文件夹:
我们直到 delete()
方法只能删除空目录。如果目录里边有内容, delete()
方法是无法删除的,即我们想用 delete()
方法删除上述aaa文件是行不通的!
为此,我们得先将 aaa
文件中所有内容给删除之后,才能将 aaa
文件删除掉! aaa
里边有 bbb
文件夹,为此得先把它里边得内容先删掉, bbb
里边有 ccc
文件夹为此得先把它里边得内容先删掉…然后再逐步回退删除文件夹!
【参考代码】
import java.io.File;
public class ListDemon {
public static void main(String[] args) {
deleteDir(new File(“e:\\aaa”));
}
本次面试答案,以及收集到的大厂必问面试题分享:
[外链图片转存中…(img-Mkv3S31h-1714690514803)]
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门,即可获取!