IO流详解之字符流与File类
IO流
1.字符流简介
- 字符流核心组成
- 核心组成:Reader--> 字符输入流、Writer--> 字符输出流、BufferedReader-->字符缓冲流读取文件、BufferedWriterr-->字符缓冲流文写入件
-
字符流
- 字节流能操作所有文件,而字符流操作文本文件比较方便
- 解决了乱码问题
-
字节流与字符流的区别:
-
在所有的流操作里。字节永远是最基础的。任何基于字节的操作都是正确的
-
无论你是文本文件还是二进制的文件。如果确认流里面只有可打印的字符,包括英文的和各种国家的文字,也包括中文,那么可以考虑用字符流。由于编码不同,多字节的字符可能占用多个字节。比如GBK的汉字就占用2个字节,而UTF-8的汉字就占用3个字节。所以,字符流是根据指定的编码,将1个或多个字节转化为java里面的unicode的字符,然后进行操作
-
字符操作一般使用Writer,Reader等
-
字节操作一般都是InputStream,OutputStream以及各种包装类,比如BufferedlnputStream和BufferedOutputStream等。
-
如果你确认你要处理的流是可打印的字符,那么使用字符流会看上去简单一点。如果不确认,那么用字节流总是不会错的。
-
一般操作非文本文件时,使用字节流;操作文本文件时,建议使用字符流。
-
2.字符流抽象类常见方法
2.1字符流抽象类
-
reader:字符输入流
public int read(){}
public int read(char[] c){}
public int read(char[] b, int off, int len){}
-
Writer: 字符输出流
public void write(int n){}
public void write(String str){}
public void write(char[] c){}
2.2文件字符流
-
FileReader:
- public int read(char[] c) // 从流中读取多个字符,将读到的内容存入 c 数组,返回实际读到的字符数;如果达到文件的尾部,则返回 -1
-
FileWriter:
- public void write(String str) // 一次写多个字符,将所有字符写入输出流
2.21 使用字节流读取文本文件代码演示
package stream.demo02;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
// 传统字节流读取txt中文文本
/*
使用传统字节流读中文文本,会出现乱码问题。因为字节流读入文件内容时是按照一个字节一个字节来读。
而hello.txt 采用UTF-8 编码格式,一个汉字占三字节,一节流的读入方式将一个汉字拆分为三字字节,所以读入内容出现了乱码
*/
public class Demo01 {
public static void main(String[] args) throws IOException {
// 1. 创建FileInputStream对象
FileInputStream fis = new FileInputStream("D:\\hello.txt");
// 2. 读取
int count=0;
while ((count=fis.read())!=-1){
System.out.print((char)count);
}//好好å¦ä¹ ï¼å¤©å¤©åä¸ 乱码
// 3. 关闭
fis.close();
}
}
运行结果
好好å¦ä¹ ï¼å¤©å¤©åä¸
2.22 使用文件字符流读取文件代码演示
package stream.demo02;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
//使用filereader读取文件
public class FileReaderTest {
public static void main(String[] args) throws IOException {
// 1. 创建FileReader 文件字符输入流
FileReader frd = new FileReader("D:\\hello.txt");
/*
// 2. 读取
// 2.1 单个字符读取
int date=0;
while ((date=frd.read())!=-1){//读取一个字符
System.out.print((char)date);
}
*/
//读取多个字符
char[] bytes = new char[5];// 字符缓冲区读取
int count=0;
while ((count=frd.read(bytes))!=-1){
System.out.println(new String(bytes,0,count));
}
// 3. 关闭
frd.close();
}
}
运行结果
好好学习,
天天向上
2.23 使用文件字符流写入文件代码演示
package stream.demo02;
import java.io.FileWriter;
import java.io.IOException;
//使用filewriter 写入文件
public class FileWriteTest {
public static void main(String[] args) throws IOException {
// 1. 创建FileWriter对象
FileWriter fileWriter = new FileWriter("D:\\write.txt");
// 2. 写入
for (int i = 0; i < 10; i++) {
fileWriter.write("要精通java\r\n");
fileWriter.flush();
}
System.out.println("执行完毕");
// 3. 关闭
fileWriter.close();
}
}
运行结果
执行完毕
2.24 利用字符流复制文件代码演示
package stream.demo02;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/*
使用字节流可以复制任意文件
使用FileReader和FileWriter复制文本文件,不能复制图片或二进制文件
一切类型文件都是以二进制010101的形式存储在硬盘上,字符流读取文件时是按照编码格式例如UTF-8 读取,而图片音频等文件没有编码格式,因此字符流读入乱码
*/
public class FileCopyTest {
public static void main(String[] args) throws IOException {
// 1. 创建 FileReader FileWriter
FileReader frd = new FileReader("D:\\write.txt");
FileWriter fwt = new FileWriter("D:\\write2.txt");
// 2. 读写
int count=0;
while ((count=frd.read())!=-1){
fwt.write(count);
fwt.flush();
}
frd.close();
fwt.close();
System.out.println("执行完毕");
}
}
运行结果
执行完毕
2.3 字符缓冲流
- 缓冲流:BufferedReader / BufferedWriter
- 高效读写
- 支持输入换行符
- 可一次写一行读一行
2.31 字符缓冲输入流代码演示:
package stream.demo02;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
//使用字符缓冲流读取文件
public class BufferReaderTest {
public static void main(String[] args) throws IOException {
// 创建缓冲流
FileReader flr = new FileReader("D:\\write.txt");
BufferedReader bufferedReader = new BufferedReader(flr);
/*
// 读取
// 1. 第一种方式
char[] chars=new char[1024];
int count=0;
while ((count=bufferedReader.read(chars))!=-1){
System.out.println(new String(chars,0,count));
}
*/
// 2. 第二种方式 一行一行读取
String st=null;
while ((st=bufferedReader.readLine())!=null){//readLine():一行一行读取文件,返回值为String类型当没有下一行时返回null
System.out.println(st);
}
// 关闭
bufferedReader.close();
System.out.println("执行完毕");
}
}
运行结果
要精通java
要精通java
要精通java
要精通java
要精通java
要精通java
要精通java
要精通java
要精通java
要精通java
执行完毕
2.32 字符缓冲输出流代码演示:
package stream.demo02;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
//使用字符缓冲流写入文件
public class BufferWriterTest {
public static void main(String[] args) throws IOException {
// 1. 创建BufferedWriter对象
FileWriter fileWriter = new FileWriter("D:\\buffer.txt");
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
// 2. 写入
for (int i = 0; i < 10; i++) {
bufferedWriter.write("我爱学习,学习爱我");
bufferedWriter.newLine(); // 写入一个换行符 相当于windows \r\n linux \n
bufferedWriter.flush();
}
// 3. 关闭
bufferedWriter.close();// 此时会自动关闭fw
System.out.println("执行完毕");
}
}
运行结果
执行完毕
2.4 打印流
-
PrintWriter
- 封装了 print() / println()方法,支持写入后换行
- 支持数据原样打印
2.41 打印流代码演示:
package stream.demo02;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
//功能:将数据打印到文件里 数据在代码里什么样子,打印出来就是什么样子
public class PrintWriterTest {
public static void main(String[] args) throws FileNotFoundException {
// 1 创建打印流
PrintWriter printWriter = new PrintWriter("D:\\print.txt");
// 2 打印
printWriter.println(65);
printWriter.println(true);
printWriter.println(3.1415);
printWriter.print("A");
// 3 关闭
printWriter.close();
System.out.println("打印完毕");
}
}
运行结果
打印完毕
2.5 转换流
-
桥转换流:InputStreamReader / OutputStreamWriter
- 可将字节流转换为字符流
- 可设置字符的编码方式
2.51 转换流读文件代码演示:
package stream.demo03;
import java.io.*;
//使用inputStreamReader 读取文件,指定使用的编码 (和FileinputStream 最大区别就是可以指定编码)
public class InputStreamReaderTest {
public static void main(String[] args) throws IOException {
// 1 创建InputStreamReader对象
FileInputStream fis = new FileInputStream("D:\\write.txt");
InputStreamReader inputStreamReader = new InputStreamReader(fis,"utf-8");
// 2 读取文件
int count=0;
while ((count=inputStreamReader.read())!=-1){
System.out.print((char)count);
}
// 3 关闭
inputStreamReader.close();
System.out.println("执行完毕");
}
}
运行结果
要精通java
要精通java
要精通java
要精通java
要精通java
要精通java
要精通java
要精通java
要精通java
要精通java
执行完毕
2.52 转换流写文件代码演示:
package stream.demo03;
import java.io.*;
//转换流 使用OutputStreamWriter 写文件 使用指定的编码
public class OutputStreamWriterTest {
public static void main(String[] args) throws IOException {
// 1 创建OutputStreamReader对象
FileOutputStream fos = new FileOutputStream("D:\\utf.txt");
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fos,"utf-8");
// 2 写入
for (int i = 0; i < 10; i++) {
outputStreamWriter.write("我爱中国,热爱祖国\n\r");// **\r:**回车,移动到当前行行首;
//**\n:**换行,换到当前位置的下一行,但是不会回到行首;
//**\r\n:**回车+换行,移动到下一行的行首
outputStreamWriter.flush();
}
// 3 关闭
outputStreamWriter.close();
System.out.println("执行完毕");
}
}
运行结果
执行完毕
3.File 类
- 概念:代表物理盘符中的一个文件或者文件夹
-
IO 流: 对文件的内容操作.
-
File 类: 对文件自身进行操作,eg:删除文件,文件重新命名等.
-
3.1 常用方法
- 目前常见的方法有:
createNewFile()
// 创建一个新文件mkdir()
//创建文件夹delete()
// 删除文件或空文件夹exists()
// 判断 File 对象所代表的对象是否存在getAbsolutePath()
// 获取文件的绝对路径getName()
// 获取名字getParent()
// 获取 文件/目录 所在的目录isDirectory()
// 是否是目录,而不是文件isFile()
是否为文件,而不是目录length()
// 获取文件的长度listFiles()
// 列出目录中所有内容renameTo()
// 更改文件的名字
3.1 文件操作代码演示:
package stream.demo04;
import java.io.File;
import java.io.IOException;
import java.util.Date;
/*
File类的使用
1. 分隔符
2. 文件操作
3. 文件夹操作
*/
//对文件进行操作
public class FileTest {
public static void main(String[] args) throws Exception {
sepearatorTest();
fileOpTest();
}
// 1. 分隔符
public static void sepearatorTest(){
System.out.println("打印路径分割符:"+File.pathSeparator);
System.out.println("名称分割符:"+File.separator);
}
// 2. 文件操作
public static void fileOpTest() throws IOException, InterruptedException {
// 1. 创建文件
File file = new File("D:\\file.txt");
if(!file.exists()){// 是否存在
boolean newFile = file.createNewFile();
System.out.println("创建结果:"+newFile);
}
// 2. 删除文件两个删除方法
// 2.1 直接删除
//System.out.println("删除结果:"+file.delete());
// 2.2 使用jvm退出时删除
// file.deleteOnExit();
// Thread.sleep(5000);
// 3. 获取文件信息
System.out.println("获取文件绝对路径"+file.getAbsolutePath());
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()).toLocaleString());
// 4. 判断
System.out.println("是否是文件:"+file.isFile());
System.out.println("是否可写:"+file.canWrite());
System.out.println("是否隐藏:"+file.isHidden());
}
}
运行结果
打印路径分割符:;
名称分割符:\
获取文件绝对路径D:\file.txt
获取文件相对路径D:\file.txt
获取文件名称file.txt
获取文件父目录D:\
获取文件的长度27
获取文件的创建时间2022-7-7 16:31:48
是否是文件:true
是否可写:true
是否隐藏:false
3.2 文件夹操作代码演示:
package stream.demo04;
import java.io.File;
import java.io.FileFilter;
import java.util.Date;
//文件夹操作
public class DirOpeTest {
public static void main(String[] args) throws InterruptedException {
dirTest();
}
public static void dirTest() throws InterruptedException {
// 1. 创建文件夹
File dir = new File("D:\\aa\\bb\\cc");
if(!dir.exists()){
//dir.mkdir(); // 只能创建单级目录
System.out.println("创建文件夹结果"+dir.mkdirs());// 创建多级目录
}
// 2. 删除文件夹
// 2.1 直接删除
//dir.delete();// 只能删除最底层空目录
// 2.2 使用jvm删除
// dir.deleteOnExit();
//Thread.sleep(5000);
// 3. 获取文件夹信息
System.out.println("获取文件夹绝对路径:"+dir.getAbsolutePath());
System.out.println("获取文件夹路径:"+dir.getPath());
System.out.println("获取父目录:"+dir.getParent());
System.out.println("获取最后一次调整时间:"+new Date(dir.lastModified()).toLocaleString());
System.out.println("获取文件夹名称:"+dir.getName());
// 4. 判断
System.out.println("判断文件夹是否存在:"+dir.exists());
System.out.println("是否隐藏:"+dir.isHidden());
// 5. 遍历文件夹 使用list()
File dir2 = new File("D:\\aa");
String[] list = dir2.list();
System.out.println("=======================");
for (String s : list) {
System.out.println(s);
}
System.out.println("------------FileFilter的使用-------------------");
//使用listFiles() 遍历文件夹
File[] files = dir2.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if(pathname.getName().endsWith("jpg")){
return true;
}
return false;
}
});
for (File file : files) {
System.out.println(file.getName());
}
}
}
运行结果
获取文件夹绝对路径:D:\aa\bb\cc
获取文件夹路径:D:\aa\bb\cc
获取父目录:D:\aa\bb
获取最后一次调整时间:2022-7-12 20:39:30
获取文件夹名称:cc
判断文件夹是否存在:true
是否隐藏:false
=======================
13-1F113092322-50.jpg
13-1F1130Z915.jpg
bb
------------FileFilter的使用-------------------
13-1F113092322-50.jpg
13-1F1130Z915.jpg
3.3 文件夹遍历操作代码演示:
package stream.demo04;
import java.io.File;
//文件夹遍历操作
public class ListdirDemo {
public static void main(String[] args) {
listDir(new File("D:\\aa"));
deleteDir(new File("D:\\aa"));
}
//递归遍历文件夹所有文件
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) {//遍历files 文件夹中所有内容
if (file.isDirectory()){//若该内容是一个文件夹,则递归调用listDIr()方法,进入该文件夹然后重复判断文件夹是否还有文件夹
listDir(file);
}else {
System.out.println(file.getAbsolutePath()//直到递归内容不是文件夹为止,打印当前文件内容的绝对路径
);
}
}
}
}
//递归 删除文件夹及所有文件
public static void deleteDir(File dir){
File[] files = dir.listFiles();
if(files!=null&&files.length>0){
for (File file : files) {
if (file.isDirectory()){//files中有子文件夹和文件,判断当前内容是否是文件,是文件递归调用方法,进入子文件夹
deleteDir(file);//递归
}else {
//删除文件
System.out.println(file.getAbsolutePath()+"删除文件:"+file.delete());
}
}
}
System.out.println(dir.getAbsolutePath()+"删除:"+dir.delete());//当该文件夹中内容删除完毕时,删除文件夹
}
}
运行结果
D:\aa
D:\aa\13-1F113092322-50.jpg
D:\aa\13-1F1130Z915.jpg
D:\aa\bb
D:\aa\bb\cc
D:\aa\bb\fjogan.jfif
D:\aa\bb\girl_cloth1.jpg
D:\aa\bb\girl_cloth2.jpg
D:\aa\bb\i1636011671_2947_0.jpg
D:\aa\bb\idCard1.png
D:\aa\bb\increment.meta
D:\aa\13-1F113092322-50.jpg删除文件:true
D:\aa\13-1F1130Z915.jpg删除文件:true
D:\aa\bb\cc删除:true
D:\aa\bb\fjogan.jfif删除文件:true
D:\aa\bb\girl_cloth1.jpg删除文件:true
D:\aa\bb\girl_cloth2.jpg删除文件:true
D:\aa\bb\i1636011671_2947_0.jpg删除文件:true
D:\aa\bb\idCard1.png删除文件:true
D:\aa\bb\increment.meta删除文件:true
D:\aa\bb删除:true
D:\aa删除:true
————————————————————————————————————————————————————————————————————————————