File
- 定位文件
- File类可以定位文件:进行删除、获取文本本身信 息等操作
- 但是不能读写文件内容
- 读写文件数据
- IO流技术可以对硬盘中的文件进行读写
- 总体学习思路
- 先学会使用File类定义文件以及操作文件本身
- 然后学习IO流读写文件数据
File类概述
- File类在包java.io.Flile下、代表操作系统的文件对象(文件、文件夹)
- File类提供了诸如:定位文件,获取文件本身的信息、删除文件、创建文件(文件夹)等功 能。
File类创建对象
- File对象可以定位文件和文件夹
- File封装的对象仅仅是一个路径名,这个路径可以是存在的,也可以是不存在的
绝对路径和相对路径
- 绝对路径:从盘符开始
- 相对路径:不带盘符,默认直接到当前工程下的目录寻找文件
/**
目标:学会创建File对象,定位操作系统的文件对象(文件 文件夹)
*/
public class FileDemo {
public static void main(String[] args) {
// 1.创建File对象(指定了文件的路径)
// 路径写法: C:\Users\zhaozhixuan\Desktop\picture\3.jpeg
// C:/Users/zhaozhixuan/Desktop/picture/3.jpeg
// File.separator
// File f = new File("C:\\Users\\zhaozhixuan\\Desktop\\picture\\3.jpeg");
// File f = new File("C:/Users/zhaozhixuan/Desktop/picture/3.jpeg");
File f = new File("C:"+File.separator+"Users"+File.separator+"zhaozhixuan"+File.separator+"Desktop"+File.separator+"picture"+File.separator+"3.jpeg");
long size = f.length();//是文件的字节大小
System.out.println(size);
// 2.File创建对象,支持绝对路径,支持相对路径(重点)
File f1 = new File("C:/Users/zhaozhixuan/Desktop/picture/3.jpeg"); //绝对路径
System.out.println(f1.length());
// 相对路径:一般定位模块中的文件的. 相对到工程下
File f2 = new File("day09-file-io/src/data.txt");
System.out.println(f2.length());
File f3 = new File("C:\\Users\\zhaozhixuan\\Desktop\\picture");
System.out.println(f3.exists());
File f4 = new File("C:\\Users\\zhaozhixuan\\Desktop\\picture1");
System.out.println(f4.exists());
}
}
File类的常用API
判断文件类型、获取文件信息功能
/**
目标:File类的获取功能的API
- public String getAbsolutePath() 返回此File的绝对路径名字符串
- public String getPath() 获取创建文件对象的时候用的路径
- public String getName() 返回由此File表示的文件或目录的名称
- public long length() 返回由此File表示的文件的长度
*/
public class FileDemo2 {
public static void main(String[] args) {
// 1.绝对路径创建一个文件对象
File f1 = new File("C:\\Users\\zhaozhixuan\\Desktop\\picture\\1.jpeg");
// a.获取它的绝对路径
System.out.println(f1.getAbsolutePath());
// b.获取创建文件对象的时候用的路径
System.out.println(f1.getPath());
// c.获取文件的名称:带后缀
System.out.println(f1.getName());
// d.获取文件的大小:字节个数
System.out.println(f1.length());
// e.获取文件的最后修改时间
long time = f1.lastModified();
System.out.println("最后修改时间:"+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(time));
// f.半段文件是文件还是文件夹
System.out.println(f1.isFile()); //true
System.out.println(f1.isDirectory()); //false
System.out.println("=============================");
// 2.创建一个相对路径文件对象
File f2 = new File("day09-file-io/src/data.txt");
// a.获取它的绝对路径
System.out.println(f2.getAbsolutePath());
// b.获取创建文件对象的时候用的路径
System.out.println(f2.getPath());
// c.获取文件的名称:带后缀
System.out.println(f2.getName());
// d.获取文件的大小:字节个数
System.out.println(f2.length());
// e.获取文件的最后修改时间
long time2 = f2.lastModified();
System.out.println("最后修改时间:"+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(time2));
// f.判断文件是文件还是文件夹
System.out.println(f2.isFile()); //true
System.out.println(f2.isDirectory()); //false
System.out.println("==============================");
File file = new File("D:/");
System.out.println(file.isFile()); //false
System.out.println(file.isDirectory()); //true
}
}
创建文件、删除文件功能
/**
目标:File类的创建和删除的方法
- public boolean createNewFile() 当且仅当具有该名称的文件尚不存在时,
创建一个新的空文件夹。(几乎不用的,因为以后文件都是自动创建的!)
- public boolean delete() 删除由此File表示的文件或者目录(只能删除空目录)
- public boolean mkdir() 创建由此File表示的目录(只能创建一级目录)
- public boolean mkdirs() 可以篡改就多级目录(建议使用的)
*/
public class FileDemo3 {
public static void main(String[] args) throws IOException {
File f = new File("day09-file-io\\src\\data.txt");
// a.创建新文件,创建成功返回true,反之false,不需要这个,以后文件写出去的时候都会自动创建
System.out.println(f.createNewFile());
File f1 = new File("day09-file-io\\src\\data1.txt");
System.out.println(f1.createNewFile());
// b.mkdir创建一级目录
File f2 = new File("day09-file-io\\src\\aaa");
System.out.println(f2.mkdir());
// c.mkdirs创建多级目录(重点)
File f3 = new File("day09-file-io\\src\\bbb\\ccc");
System.out.println(f3.mkdirs());
// d.删除文件或者空文件夹
System.out.println(f1.delete());
File f4 = new File("C:\\Users\\zhaozhixuan\\Desktop\\picture\\3.jpeg");
System.out.println(f4.delete()); //占用一样可以删除
// 只能删除空文件夹,不能删除非空文件夹
System.out.println(f2.delete());
File f5 = new File("day09-file-io\\src\\bbb");
System.out.println(f5.delete());
}
}
遍历文件夹
listFiles方法注意事项:
- 当调用者不存在时,返回null
- 当调用者是一个文件时,返回null
- 当调用者是一个空文件夹时,返回一个长度为0的数组
- 当调用者是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回
- 当调用者时一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包括隐藏文件
/**
目标:File针对目录的遍历
- public String[] list()
获取当前目录下所有的"一级文件名称"到一个字符串数组中去返回
- public File[] listFiles()(常用)
获取当前目录下所有的"一级文件对象"到一个数组对象中去返回(重点)
*/
public class FileDemo4 {
public static void main(String[] args) {
// 1.定位一个目录
File f1 = new File("C:\\Users\\zhaozhixuan\\Desktop\\picture");
String[] names = f1.list();
for (String name : names) {
System.out.println(name);
}
// 2.以及文件对象
// 获取当前目录下所有的"一级文件对象"到一个数组对象中去返回(重点)
File[] files = f1.listFiles();
for (File file : files) {
System.out.println(file.getAbsolutePath());
}
// 注意事项
File dir = new File("D:/aaaaaaaaaaa");
File[] files1 = dir.listFiles();
System.out.println(files1);
File file = new File("C:\\Users\\zhaozhixuan\\Desktop\\picture\\1.jpeg");
File[] files2 = file.listFiles();
System.out.println(files2);
File div2 = new File("C:\\Users\\zhaozhixuan\\Desktop\\picture\\aaa");
File[] files3 = div2.listFiles();
System.out.println(files3);
System.out.println(files3.length);
System.out.println(Arrays.toString(files3));
}
}
方法递归
递归的形式和特点
什么是方法递归
- 方法直接调用自己或者间接调用自己的形式成为方法递归
- 递归做为一种算法在程序设计语言中广泛应用。
递归的形式
- 直接递归:方法自己调用自己
- 间接递归:方法调用其他方法,其他方法有回调方法自己
方法递归存在的问题
- 递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出现象
递归的算法流程、核心要素
public static int f(int n){
if (n==0) return 1;
if (n==1) {
return 1;
}else {
return f(n-1)*n;
}
}
递归解决问题的思路:
- 把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解
递归算法三要素大体可以总结为:
- 递归的公式:f(n) = f(n-1) *n
- 递归的终结点: f(1)
- 递归的方式必须走向终结点
递归常见案例
public static int sum(int n ){
if (n==0) return 0;
if (n==1) {return 1;}
else {
return sum(n-1)+n;
}
}
递归的经典问题
public class RecursionDemo3 {
public static void main(String[] args) {
for (int i = 1; i <11 ; i++) {
System.out.println(f(i));
}
}
/*
f(1) = ? 需要求:第一天有多少桃子
已知 f(10) = 1 第10天剩余1个桃子
第x天吃了一半桃子,然后又吃了一个 ,剩余的桃子在第x+1天
f(x) - f(x)/2 -1 = f(x+1)
变形 f(x) = 2 * f(x+1) + 2
*/
public static int f(int n){
if (n==10){
return 1;
}else {
return 2*f(n+1) +2;
}
}
}
非规律化递归案例 - 文件搜索
/**
目标:去D盘搜索logback.xml文件
*/
public class RecursionDemo5 {
public static void main(String[] args) {
// 2.传入目录 和文件名称
searchFile(new File("D:/"),"logback.xml");
//searchFile(new File("D:/"),"WeChat.exe");
}
/**
* 1.搜索某个目录下的全部文件,找到我们想要的文件
* @param dir 被搜索的源目录
* @param fileName 被搜索的文件名称
*/
public static void searchFile(File dir,String fileName){
// 3.判断dir是否是目录
if (dir != null && dir.isDirectory()){
// 可以找了
// 4.提前当前目录下的一级文件对象
File[] files = dir.listFiles();
// 5.判断是否存在一级文件对象
if (files != null && files.length>0){
for (File file : files) {
// 6.判断当前遍历的以及文件对象 是文件 还是文件夹
if (file.isFile()){
// 7.是文件,判断是不是唯美要找的文件,是的话输出绝对路径
if (file.getName().contains(fileName)){
System.out.println("找到了:"+file.getAbsolutePath());
// 启动它,只能启动 .exe 文件
// Runtime r = Runtime.getRuntime();
// try {
// r.exec(file.getAbsolutePath());
// } catch (IOException e) {
// e.printStackTrace();
// }
}
}else {
// 8.是文件夹,继续递归查找
searchFile(file,fileName);
}
}
}
}else {
System.out.println("对不起,当前搜索的位置不是文件夹");
}
}
}
非规律化递归案例 - 啤酒问题
/**
目标:啤酒2元1瓶,4个盖子可以换1瓶,2个空瓶可以换1瓶
问:10元钱可以喝多少啤酒,剩余多少空瓶子喝盖子。
答案:15瓶 3盖子 1瓶子
*/
public class RecursionDemo6 {
// 定义一个静态的成员变量用于存储可以买的酒的数量
public static int totalNumber;//总数量
public static int lastBottleNumber; //记录每次剩余的瓶子个数
public static int lastCoverNumber; //记录每次剩余的盖子个数
public static void main(String[] args) {
// 1.拿钱买酒
buy(11);
}
public static void buy(int money){
// 2.看看可以卖多少瓶
int buyNumber = money/2 ; //5
totalNumber += buyNumber;
// 3.八盖子喝瓶子换算成钱
// 统计本轮总的盖子数喝瓶子数
int coverNumber = lastCoverNumber + buyNumber;
int bottleNumber = lastBottleNumber + buyNumber;
// 统计可以换算的钱
int allMoney = 0;
allMoney += (coverNumber / 4) *2;
lastCoverNumber = coverNumber % 4;
allMoney += (bottleNumber / 2) *2;
lastBottleNumber = bottleNumber % 2;
if (allMoney>=2){
buy(allMoney);
}else {
System.out.println("喝啤酒总数::"+totalNumber);
System.out.println("剩余盖子数:"+lastCoverNumber);
System.out.println("剩余瓶子数:"+lastBottleNumber);
}
}
}
字符集
字符集基础知识
-
计算机底层不可以直接存储字符。计算机中底层只能存储二进制(0、1)
-
er禁止是可以转换成十进制的
- 结论:计算机底层可以表示十进制编号。计算机可以给人类字符进行编号存储,这套编号规则就是字符集
常见字符集介绍
ASCII字符集:
- ASCII(American Standard Code for Information Interchange,美国信息交换标准代码):包括了数字、英文、符号
- ASCII 使用1个字节存储一个字符,一个字节是8位,总共可以表示128个字符信息,对于英文、数字来说是够用的
GBK
- window系统默认的码表。兼容ASCII码表,也包含了几万个汉字,并支持繁体汉字以及部分日韩文字
- 注意:GBK是中国的码表,一个中文以两个字节的形式存储。但不包含世界上所有国家的文字。
Unicode
- unicode(又称统一码、万国码、单一码)是计算机科学领域里的一项业界字符编码标准
- 容纳世界上大多数国家的所有常见文字和符号
- 由于Unicode会先通过UTF-8, UTF-6, 以及UTF-32 的编码成二进制后在存储到计算机,其中最为常见的是UTF-8
注意
- Unicode是万国码,以UTF-8编码后一个中文一般以三个字节的形式存储
- UTF-8 也要兼容ASCII编码表
- 技术人员都应该使用UTF-8的字符集编码
- 编码前和编码后的字符集需要一致,否则会出现中文乱码
字符集的编码和解码操作
/**
目标:学会自己进行文字的编码和解码,为以后可能用到的场景做准备。
*/
public class Test {
public static void main(String[] args) throws Exception {
// 1.编码:把文字转换成字节(使用指定的编码)
String name = "abc我爱你中国";
//byte[] bytes = name.getBytes();//以当前代码默认字符集进行编码(UTF-8)
byte[] bytes = name.getBytes("GBK");//以GBK字符集编码
System.out.println(bytes.length);
System.out.println(Arrays.toString(bytes));
// 2.解码:把字节转化成对应的中文形式(编码前和编码后的字符集必须一致,否则乱码)
//String rs = new String(bytes);//默认的UTF-8
String rs = new String(bytes,"GBK"); //指定GBK解码
System.out.println(rs);
}
}
IO流
IO流概述
IO流也成为输入、输出流,就是用来读写数据的
- I表示input,是数据从硬盘文件读入到内存的过程,称之输入,负责读。
- O表示output,是内存程度的数据从内存到写出到硬盘文件的过程,称之输出,负责写。
IO流的分类
四大类:
- 字节输入流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流成为字节输入流
- 字节输出流:以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中去的流成为字节输出流
- 字符输入流:以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入到内存中去的流成为字符输入流
- 字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中去的流成为字符输出流
字节输入流
文件字节输入流:FileInputStream
- 作用:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去
每次读取一个字节
public class FileInputStreamDemo1 {
public static void main(String[] args) throws Exception {
// 1.创建一个文件字节输入流 管道 与源文件接通
//InputStream is = new FileInputStream(new File("day09-file-io/src/data.txt"));
// 简化写法
InputStream is = new FileInputStream("day09-file-io/src/data.txt");
// 2.读取一个字节返回(每次读取一滴水)
// int b1 = is.read();
// System.out.println((char) b1);
//
// int b2 = is.read();
// System.out.println((char) b2);
//
// int b3 = is.read();
// System.out.println((char) b3);
//
// int b4 = is.read(); //读取完毕返回-1
// System.out.println(b4);
// 3.使用循环改进
// 定义一个遍历记录每次读取的字节 a b 3 爱
// o o o [ooo]
int b;
while ((b=is.read())!=-1){
System.out.print((char) b);
}
}
}
每次读取一个字节数组
/**
目标:使用文件字节输入流每次读取一个字节数组的数据
*/
public class FileInputStreamDemo2 {
public static void main(String[] args) throws Exception {
// 1.创建一个文件字节输入流 管道 与源文件接通
InputStream is = new FileInputStream("day09-file-io/src/data02.txt");
// 2.定义一个字节数字,用于读取字节数组
// byte[] buffer = new byte[3]; //1kb = 1024 3B
// int len = is.read(buffer);
// System.out.println("读取了几个字节:"+len);
// String rs = new String(buffer);
// System.out.println(rs);
//
// int len1 = is.read(buffer);
// System.out.println("读取了几个字节:"+len1);
// String rs1 = new String(buffer);
// System.out.println(rs1);
//
// int len2 = is.read(buffer);
// System.out.println("读取了几个字节:"+len2);
// // 读取多少道出多少
// String rs2 = new String(buffer,0,len2);
// System.out.println(rs2);
//
// int len3 = is.read(buffer);
// System.out.println("读取了几个字节:"+len3);
// String rs3 = new String(buffer);
// System.out.println(len3);
// 3.改进使用循环,每次读取一个字节数组
byte[] buffer = new byte[3];
int len; //记录每次读取的字节数
while ((len = is.read(buffer))!=-1){
// 读取多少倒出多少
System.out.print(new String(buffer,0,len));
}
}
}
一次读完全部字节
方法一:
- 字节定义一个字节数组与文件的大小一样大,然后使用读取字节数组的方法,一次性读取完成
方法二(JDK 9 之后才有):
- 官方为字节输入流InputStream提供了如下API可以直接把文件的全部数据读取到一个字节数组中
/**
目标:使用文件字节输入流一次读完文件的全部字节。可以解决乱码问题
*/
public class FileInputStreamDemo3 {
public static void main(String[] args) throws Exception {
// 1.创建一个文件字节输入流 管道 与源文件接通
File f = new File("day09-file-io/src/data03.txt");
InputStream is = new FileInputStream(f);
// 2.定义一个字节数组与文件的大小刚刚一样大,用于读取字节数组
byte[] buffer = new byte[(int)f.length()];
int len = is.read(buffer);
System.out.println("读取了多少个字节:"+len);
System.out.println("文件大小:"+f.length());
System.out.println(new String(buffer));
}
}
字节输出流
文件字节输出流:FileOutPutStream
作用:以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中去
文件字节输出流写数据出去的API
流的关闭与刷新
public class OutputStreamDemo4 {
public static void main(String[] args) throws Exception {
// 1.创建一个文件字符输出流管道与目标文件接通
OutputStream os = new FileOutputStream("day09-file-io/src/out04.txt",true);//追加数据管道
//OutputStream os = new FileOutputStream("day09-file-io/src/out04.txt");//先清空之前的数据,在写新数据进去
// 2.写数据出去
// a.public void write(int a):写一个字节出去
os.write('a');
os.write(98);
//os.write('徐');//[ooo]
os.write("\r\n".getBytes());//换行
// 刷新数据,可以继续使用流
os.flush();
// 关闭流,释放资源,包含了刷新的!关闭后流不能在使用
//os.close();
// b.public void write(byte[] buffer):写一个字节数组出去
byte[] buffer = {'a',97,98,99};
os.write(buffer);
os.write("\r\n".getBytes());//换行
byte[] buffer2 = "我是中国人".getBytes();
// byte[] buffer2 = "我是中国人".getBytes("GBK"); //会乱码
os.write(buffer2);
os.write("\r\n".getBytes());//换行
// c。public void write(byte[] buffer, int pos , int len):写一个字节数组的一部分出去
byte[] buffer3 = {'a',97,98,99};
os.write(buffer3,0,3);
os.write("\r\n".getBytes());//换行
os.close();
}
}
文件拷贝
- 任何文件的底层都是字节,拷贝是一字不漏的转移字节,只要前后文件格式、编码一致没有任何问题
/**
目标:学会使用字节流完成文件拷贝(支持一切文件类型的复制)
*/
public class CopyDemo5 {
public static void main(String[] args) {
try {
// 1.定义一个字节输入流管道与原视频接通
InputStream is = new FileInputStream("E:\\2022-5-31\\手机备份\\Camera\\Video\\VID_20190611_214908.mp4");
// 2.创建一个字节输出流管道与目标文件接通
OutputStream os = new FileOutputStream("C:\\Users\\zhaozhixuan\\Desktop\\picture\\new.mp4");
// 3.定义一个字节数组用来转移数据
byte[] buffer = new byte[1024];
int len; //记录每次读取的字节数
while ((len=is.read(buffer))!=-1){
os.write(buffer,0,len);
}
System.out.println("复制完成了");
// 关闭流
os.close();
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
资源释放的方式
try-catch-finally
- finally:在异常处理时提供finally块来执行所有清除操作,比如说IO流中的释放资源
- 特点:被finally控制的语句最终一定会执行,除非JVM退出
- 异常处理标准格式:try...catch...finally
/**
目标:学会使用finally释放资源
*/
public class TryCatchFinallyDemo1 {
public static void main(String[] args) {
InputStream is = null;
OutputStream os = null;
try {
//System.out.println(10/0); //在流还没开始前出现异常
// 1.定义一个字节输入流管道与原视频接通
is = new FileInputStream("E:\\2022-5-31\\手机备份\\Camera\\Video\\VID_20190611_214908.mp4");
// 2.创建一个字节输出流管道与目标文件接通
os = new FileOutputStream("C:\\Users\\zhaozhixuan\\Desktop\\picture\\new.mp4");
// 3.定义一个字节数组用来转移数据
byte[] buffer = new byte[1024];
int len; //记录每次读取的字节数
while ((len=is.read(buffer))!=-1){
os.write(buffer,0,len);
}
System.out.println("复制完成了");
} catch (Exception e) {
e.printStackTrace();
} finally {
// 无论代码是正常结束,还是出现异常最后都要执行这里
System.out.println("======finally======");
// 关闭流
try {
if (os!=null) os.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (is!=null) is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(test(10,0));
}
public static int test(int a,int b ){
try {
int c = a/b;
return c;
}catch (Exception e){
e.printStackTrace();
return -1; //计算出现bug
}finally {
// 哪怕上面有return语句执行,也必须先执行完这里才可以
// 开发中不建议在这里加return,如果加了,返回的永远是这里的数据了
return 100;
}
}
}
try-catch-resource
- 自动释放资源,代码简洁
/**
目标: JDK7改进方式,自动释放资源,代码简洁
*/
public class TryCatchResourceDemo2 {
public static void main(String[] args) {
try (
// 这里面只能放置资源对象,用完会自动关闭,自动调用资源对象的close方法关闭资源(即使出现异常也会做关闭操作)
// 1.定义一个字节输入流管道与原视频接通
InputStream is = new FileInputStream("E:\\2022-5-31\\手机备份\\Camera\\Video\\VID_20190611_214908.mp4");
// 2.创建一个字节输出流管道与目标文件接通
OutputStream os = new FileOutputStream("C:\\Users\\zhaozhixuan\\Desktop\\picture\\new.mp4");
MyConnection connection = new MyConnection();//最终会自动调用资源的close方法
){
// 3.定义一个字节数组用来转移数据
byte[] buffer = new byte[1024];
int len; //记录每次读取的字节数
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
System.out.println("复制完成了");
} catch (Exception e) {
e.printStackTrace();
}
}
}
class MyConnection implements AutoCloseable{
@Override
public void close() throws IOException {
System.out.println("连接资源被成功释放");
}
}
字符输入流
字节流读取中文输出可能会出现乱码、内存溢出的问题
读取中文输出,字符流更合适,最小单位时按照单个字符读取的
文件字符输入流-FileReader
- 作用:以内存为基准,把磁盘文件的中数据以字符的形式读取到内存中去
一次读取一个字符
/**
目标:每次读取一个字符
*/
public class FileReaderDemo1 {
public static void main(String[] args) throws Exception {
// 1.创建一个字符输入流管道与源文件接通
Reader fr = new FileReader("day09-file-io\\src\\data06.txt");
// 2.读取一个字符
int code;
while((code=fr.read())!=-1){
System.out.print((char) code);
}
}
}
一次读取一个字符数组
/**
一次读取一个字符数组的数据
*/
public class FileReaderDemo2 {
public static void main(String[] args) throws Exception {
// 1.创建一个字符输入流管道与源文件接通
Reader fr = new FileReader("day09-file-io\\src\\data06.txt");
// 2.用循环,每次读取一个字符数组的数据
char[] buffer = new char[1024]; //1k字符
int len; //记录每次读取的字符数量
while((len = fr.read(buffer))!=-1){
String rs = new String(buffer,0,len);
System.out.print(rs);
}
}
}
字符输出流
文件字符输出流-FileWriter
- 作用:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中去
public class FileWriterDemo3{
public static void main(String[] args) throws Exception {
// 1.创建一个字符输入流管道与目标文件接通
//Writer fw = new FileWriter("day09-file-io\\src\\data07.txt"); //覆盖管道,每次启动都会清空文件之前的数据
Writer fw = new FileWriter("day09-file-io\\src\\data07.txt",true); //追加管道
// a.public void write(int c): 写一个字符出去
fw.write(97);
fw.write('a');
fw.write('徐'); //不会出问题
fw.write("\r\n"); //换行
// b.public void write(String c): 写一个字符串出去
fw.write("abc我时中国人");
fw.write("\r\n"); //换行
// c.public void write(char[] buffer): 写一个字符数组出去
char[] chars = "abc我是中国人".toCharArray();
fw.write(chars);
fw.write("\r\n"); //换行
// d.public void write(String c,int pos,int len): 写字符串的一部分出去
fw.write("abc我是中国人",0,5);
fw.write("\r\n"); //换行
// e.public void write(char[] buffer,int pos,int len): 写字符数组的一部分出去
fw.write(chars,3,5);
fw.write("\r\n"); //换行
//fw.flush(); //刷新
fw.close();
}
}
字符流、字节流使用选择
- 字节流适合做一切文件数据的拷贝(音视频,文本)
- 字节流不适合读取中文内容输出
- 字符流适合做文本文件的操作(读、写)
缓冲流
缓冲流概述
- 缓冲流也成为高效流或者高级流。之前学习的字节流可以成为原始流
- 作用:缓冲流自带缓冲区,可以提高原始字节流、字符流读写数据的性能
字节缓冲流
字节缓冲流性能优化原理:
- 字节缓冲输入流自带了8kb缓冲池,以后我们直接从缓冲池读取数据,所以性能较好
- 字节换成输出流自带了8kb缓冲池,数据就直接写入到缓冲池中去,写数据性能提高
- 字节缓冲输入流-BufferedInputStream,提高了字节输入流读取数据的性能,读写功能上并无变化
- 字节缓冲输出流-BufferedOutputStream,提高了字节输出流读取数据的性能,读写功能上并无变化
public class ByteBufferDemo {
public static void main(String[] args) {
try (
// 这里面只能放置资源对象,用完会自动关闭,自动调用资源对象的close方法关闭资源(即使出现异常也会做关闭操作)
// 1.定义一个字节输入流管道与原视频接通
InputStream is = new FileInputStream("E:\\Java project\\javasepromax\\day09-file-io\\src\\out04.txt");
// a.把原始的字节输入流包装成高级的缓冲字节输入流
InputStream bis =new BufferedInputStream(is);
// 2.创建一个字节输出流管道与目标文件接通
OutputStream os = new FileOutputStream("E:\\Java project\\javasepromax\\day09-file-io\\src\\out05.txt");
// b.把原始的字节输出流包装成高级的缓冲字节输出流
OutputStream bos =new BufferedOutputStream(os);
) {
// 3.定义一个字节数组用来转移数据
byte[] buffer = new byte[1024];
int len; //记录每次读取的字节数
while ((len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
System.out.println("复制完成了");
} catch (Exception e) {
e.printStackTrace();
}
}
}
字节缓冲流的性能分析
public class ByteBufferTimeDemo {
private static final String SRC_FILE = "E:\\2022-5-31\\手机备份\\Camera\\VID_20201106_131442.mp4";
private static final String DEST_FILE = "C:\\Users\\zhaozhixuan\\Desktop\\picture\\";
public static void main(String[] args) {
//使用低级的字节流按照一个一个字节的形式复制 :慢的让人无法忍受,直接被淘汰
//copy1(); //太慢了,等了二十分钟没出来
//使用低级的字节流按照一个一个字节数字的形式复制 :比较慢,但是还是可以忍受的
copy2(); //5.399s
//使用高级的缓冲字节流按照一个一个字节的形式复制 :很慢,不建议使用
copy3(); //7.546s
//使用高级的缓冲字节流按照一个一个字节数组的形式复制 :飞快,简直太完美了
copy4(); //0.955s
}
private static void copy1() {
long startTime = System.currentTimeMillis();
try (
// 1.创建低级的字节输入流与目标文件接通
InputStream is = new FileInputStream(SRC_FILE);
// 2.创建低级的字节输出流与目标玩家接通
OutputStream os = new FileOutputStream(DEST_FILE+"new1.mp4");
){
// 3.定义一个变量记录每次读取的字节
int b;
while((b = is.read())!=-1){
os.write(b);
}
}catch (Exception e){
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("使用低级的字节流按照一个一个字节的形式复制耗时:"+ (endTime-startTime)/1000.0 +"s");
}
private static void copy2() {
long startTime = System.currentTimeMillis();
try (
// 1.创建低级的字节输入流与目标文件接通
InputStream is = new FileInputStream(SRC_FILE);
// 2.创建低级的字节输出流与目标玩家接通
OutputStream os = new FileOutputStream(DEST_FILE+"new2.mp4");
){
// 3.定义一个变量记录每次读取的字节
byte[] buffer = new byte[1024];
int len;
while((len = is.read(buffer))!=-1){
os.write(buffer,0,len);
}
}catch (Exception e){
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("使用低级的字节流按照一个一个字节数组的形式复制耗时:"+ (endTime-startTime)/1000.0 +"s");
}
private static void copy3() {
long startTime = System.currentTimeMillis();
try (
// 1.创建高级的的缓冲字节输入流与目标文件接通
InputStream is = new FileInputStream(SRC_FILE);
InputStream bis =new BufferedInputStream(is);
// 2.创建高级的的缓冲字节输出流与目标玩家接通
OutputStream os = new FileOutputStream(DEST_FILE+"new3.mp4");
OutputStream bos = new BufferedOutputStream(os);
){
// 3.定义一个变量记录每次读取的字节
int b;
while((b = bis.read())!=-1){
bos.write(b);
}
}catch (Exception e){
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("使用高级的缓冲字节流按照一个一个字节的形式复制耗时:"+ (endTime-startTime)/1000.0 +"s");
}
private static void copy4() {
long startTime = System.currentTimeMillis();
try (
// 1.创建高级的的缓冲字节输入流与目标文件接通
InputStream is = new FileInputStream(SRC_FILE);
InputStream bis =new BufferedInputStream(is);
// 2.创建高级的的缓冲字节输出流与目标玩家接通
OutputStream os = new FileOutputStream(DEST_FILE+"new4.mp4");
OutputStream bos = new BufferedOutputStream(os);
){
// 3.定义一个变量记录每次读取的字节
byte[] buffer = new byte[1024];
int len;
while((len = bis.read(buffer))!=-1){
bos.write(buffer,0,len);
}
}catch (Exception e){
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("使用低级的字节流按照一个一个字节数组的形式复制耗时:"+ (endTime-startTime)/1000.0 +"s");
}
}
字符缓冲流
字符缓冲输入流
- 字符缓冲输入流:BufferedReader
- 作用:提高字符输入流读取数据的性能,除此之外多了按照行读取的功能
/**
目标:学会使用缓冲字符输入流提高字符输入流的性能,新增了按照行读取的方法
*/
public class BufferedReaderDemo1 {
public static void main(String[] args) throws Exception {
try (
// 1.创建一个字符输入流管道与源文件接通
Reader fr = new FileReader("day09-file-io\\src\\data06.txt");
BufferedReader br = new BufferedReader(fr);
){
// 2.用循环,每次读取一个字符数组的数据
// char[] buffer = new char[1024]; //1k字符
// int len; //记录每次读取的字符数量
// while((len = fr.read(buffer))!=-1){
// String rs = new String(buffer,0,len);
// System.out.print(rs);
// }
//按行读取数据
String line;
while((line = br.readLine())!=null){
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
字符缓冲输出流
- 字符缓冲输出流:BufferedWriter
- 作用:提高字符输出流写取数据的性能,除此之外多了换行功能
/**
目标:缓冲字符输出流的使用,学会它多出来的一个功能:换行 newLine();
*/
public class BufferedWriterDemo2 {
public static void main(String[] args) throws Exception {
// 1.创建一个字符输入流管道与目标文件接通
//Writer fw = new FileWriter("day09-file-io\\src\\data07.txt"); //覆盖管道,每次启动都会清空文件之前的数据
Writer fw = new FileWriter("day09-file-io\\src\\data07.txt",true); //追加管道
BufferedWriter bw = new BufferedWriter(fw);
// a.public void write(int c): 写一个字符出去
bw.write(97);
bw.write('a');
bw.write('徐'); //不会出问题
bw.newLine(); //换行
// b.public void write(String c): 写一个字符串出去
bw.write("abc我时中国人");
bw.newLine(); //换行
// c.public void write(char[] buffer): 写一个字符数组出去
char[] chars = "abc我是中国人".toCharArray();
bw.write(chars);
bw.newLine(); //换行
// d.public void write(String c,int pos,int len): 写字符串的一部分出去
bw.write("abc我是中国人",0,5);
bw.newLine(); //换行
// e.public void write(char[] buffer,int pos,int len): 写字符数组的一部分出去
bw.write(chars,3,5);
bw.newLine(); //换行
//fw.flush(); //刷新
bw.close();
}
}
案例
/**
目标:完成出师表顺序的恢复,并存入到另一个新文件中去
*/
public class BufferedCharTest3 {
public static void main(String[] args){
try (
// 1.创建缓冲字符输入流管道与源文件接通
BufferedReader br = new BufferedReader(new FileReader("day09-file-io\\src\\csb.txt"));
// 5.定义缓冲字符输出管道与目标文件接通
BufferedWriter bw = new BufferedWriter(new FileWriter("day09-file-io\\src\\new-csb.txt"));
){
// 2.定义一个List集合存储每行内容
List<String> lines = new ArrayList<>();
// 3.定义循环,按照行读取文章
String line;
while ((line= br.readLine())!=null){
lines.add(line);
}
// 4.排序
//自定义排序规则
List<String> sizes = new ArrayList<>();
Collections.addAll(sizes,"一","壹","二","贰","三","叁","四","肆","五","伍","六","陆","七","柒","八","捌","九","玖","十","拾","十一");
Collections.sort(lines, new Comparator<String>() { //lambda表达式,可简化
@Override
public int compare(String o1, String o2) {
return sizes.indexOf(o1.substring(0,o1.indexOf("."))) // substring(开始位置,结束位置) 截取字符串
- sizes.indexOf(o2.substring(0,o2.indexOf("."))); // indexOf("字符") 找出第一个"字符"的下标
}
});
System.out.println(lines); //打印集合看一下
// 6.遍历集合中的每行文章写出去,并换行
for (String s : lines) {
bw.write(s);
bw.newLine();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
出师表 csb.txt
十一.出师未捷身先死,长使英雄泪满襟。
三.侍中、侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。愚以为宫中之事,事无大小,悉以咨之,然后施行,必得裨补阙漏,有所广益。
八.愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎;陛下亦宜自谋,以咨诹善道,察纳雅言,深追先帝遗诏,臣不胜受恩感激。
四.将军向宠,性行淑均,晓畅军事,试用之于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。
二.宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。
一.先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。
九.今当远离,临表涕零,不知所言。
十.今当远离,临表涕零,不知所言。
陆.臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
柒.先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐付托不效,以伤先帝之明,故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。
五.亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。
转换流
字符转换输入流
- 字符转换输入流:InputStreamReader ,可以把原始的字节流按照指定编码转换成字符输入流
- 作用:可以解决字符流读取不同编码乱码的问题
public class InputStreamReaderDemo1 {
public static void main(String[] args){
try (
// 1.提取GBK文件的原始字节流
InputStream is = new FileInputStream("C:\\Users\\zhaozhixuan\\Desktop\\data.txt");
// 2. 八原始字节流转化成字符输入流
Reader isr = new InputStreamReader(is ,"GBK"); //以指定的GBK编码转换成字符输入流
// 3.
BufferedReader br = new BufferedReader(isr);
){
String line;
while((line = br.readLine())!=null){
System.out.println(line);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
字符转换输出流
- 字符输出转换流:OutputStreamWriter , 可以把字节输出流按照指定编码转换成字符输出流
- 作用:可以指定编码把字节输出流转换成字符输出流,从而可以指定写出去的字符编码
public class OutputStreamWriterDemo2 {
public static void main(String[] args) {
try (
// 1.定义一个字节输出流
OutputStream os = new FileOutputStream("day09-file-io/src/out08.txt");
// 2.把原始的字节输出流转换成字符输出流
Writer osw = new OutputStreamWriter(os,"GBK");
// 3.把低级的字符输出流包装成高级的缓冲字符输出流
BufferedWriter bw = new BufferedWriter(osw);
){
bw.write("我爱中国1~~");
bw.newLine();
bw.write("我爱中国2~~");
bw.newLine();
bw.write("我爱中国3~~");
bw.newLine();
}catch (Exception e){
e.printStackTrace();
}
}
}
序列化对象
对象序列化
- 作用:以内存为基准,把内存中的对象存储到磁盘文件中去,称为对象序列化。
- 使用到的流是对象字节输出流:ObjectOutStream
- 注意:对象必须实现序列化接口:Serializable
/**
目标:学会对象序列化,使用ObjectOutputStream 把内存中的对象存到磁盘文件中
*/
public class ObjectOutputStreamDemo1 {
public static void main(String[] args) throws Exception {
// 1.创建学生对象
Student s = new Student("陈磊", "chenlei", "1314520", 21);
// 2.对象序列化,对象字节输出流包装字节输出流管道
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day09-file-io/src/obj.txt"));
// 3.直接调用序列化方法
oos.writeObject(s);
// 4.释放资源
oos.close();
System.out.println("序列化就完成了");
}
}
/**
对象如果要实例化,必须实现Serializable序列化接口。
*/
public class Student implements Serializable {\
内容;
}
对象反序列化
- 作用:以内存为基准,把存储到磁盘文件中的对象数据恢复成内存中的对象,称为对象反序列化。
- 使用到的流是对象字节输入流:ObjectInputStream
/**
目标:学会对象反序列化,使用ObjectInputStream 把存储到磁盘文件的对象数据恢复到内存的对象中
对象如果要实例化,必须实现Serializable序列化接口。
transient修饰的成员变量不参与序列化了
序列化的版本号与反序列化的版本号必须一致才不会出错
*/
public class ObjectInputputStreamDemo2 {
public static void main(String[] args) throws Exception {
// 1.对象反序列化,对象字节输入流包装字节输出流管道
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day09-file-io/src/obj.txt"));
// 2.直接调用反序列化方法
Student s = (Student) ois.readObject();
System.out.println(s);
// 3.释放资源
ois.close();
System.out.println("反序列化就完成了");
}
}
打印流
- 作用:打印流可以实现方便、高效的打印数据到文件中去。
- 打印流一般是指:PrintStream , PrintWriter 两个类
- 可以实现打印什么数据就是什么数据,例如打印整数97写出去就是97,打印boolean的true,写出去就是true
PrintStream
PrintWriter
/**
目标:学会使用打印流 高效 方便写数据到文件
*/
public class PrintDemo1 {
public static void main(String[] args) throws Exception {
// 1.创建一个打印流对象
// PrintStream ps = new PrintStream(new FileOutputStream("day09-file-io/src/ps.txt"));
PrintStream ps = new PrintStream("day09-file-io/src/ps.txt");
// PrintWriter pw = new PrintWriter("day09-file-io/src/ps.txt");
//追加数据,在低级管道后面加true
PrintWriter pw = new PrintWriter(new FileOutputStream("day09-file-io/src/ps.txt",true));
ps.println(97);
ps.println('a');
ps.println(23.3);
ps.println(true);
ps.println("我是打印流输出的,我是啥就打印啥");
pw.println(96);
pw.println('a');
pw.println(23.3);
pw.println(true);
pw.println("我是打印流输出的,我是啥就打印啥");
ps.close();
pw.close();
}
}
PrintStream 和 PrintWriter 的区别
- 打印数据功能上是一模一样的,都是使用方便,性能高效(核心优势)
- PrintStream 继承自字节输出流 OutputStream,支持写字节数据的方法。
- PrintWriter 继承自字符输出流 Writer,支持写字符数据出去
输出语句重定向
- 属于打印流的一种应用,可以把输出语句的打印位置给到文件。
/**
目标:了解改变输出语句的位置到文件
*/
public class PrintDemo2 {
public static void main(String[] args) throws Exception {
System.out.println("锦瑟无端五十弦");
System.out.println("一弦一柱思华年");
// 改变输出语句的位置(重定向)
PrintStream ps = new PrintStream("day09-file-io/src/log.txt");
System.setOut(ps); //把系统打印流改成我们自己的打印流
System.out.println("庄生晓梦迷蝴蝶");
System.out.println("望帝春心托杜鹃");
}
}
Properties
Properties属性集对象
- 其实就是一个Map集合,但是我们一般不会当集合使用,因为HashMap更好用
Properties核心作用
- Properties代表的是一个属性文件,可以把自己对象中的键值对对信息存入到一个属性文件中去
- 属性文件:后缀是 .properties 结尾的文件,里面的内容都是 key=value , 后续做系统配置信息的。
Properties的API
public class PropertiesDemo1 {
public static void main(String[] args) throws Exception {
// 需求:使用Properties把键值对信息存入到属性文件中去
Properties properties = new Properties();
properties.setProperty("admin","123456");
properties.setProperty("dlei","123456");
properties.setProperty("zzx","1234567");
System.out.println(properties);
/**
参数一:保存管道,字符输出流管道
参数二:保存心得
*/
properties.store(new FileWriter("day09-file-io/src/users.properties")
,"this is Users!!I am very happy!!");
}
}
public class PropertiesDemo2 {
public static void main(String[] args) throws Exception {
// 需求:Properties读取属性文件中的键值对信息(读取)
Properties properties = new Properties();
System.out.println(properties);
// 读取属性文件的键值对数据到我们的属性集对象properties中去
properties.load(new FileReader("day09-file-io/src/users.properties"));
System.out.println(properties);
String rs = properties.getProperty("dlei");
System.out.println(rs);
String rs1 = properties.getProperty("zzx");
System.out.println(rs1);
}
}
IO框架
commons-io 概述
- commons-io 是apache开源基金组织提供的一组有IO操作的类库,可以提高IO功能开发的效率
- commons-io 工具包提供了很多有关io操作的类。由两个主要的类 FileUtils ,IOUtils
- commons-io工具包下载地址
public class CommonsIoDemo1 {
public static void main(String[] args) throws Exception{
// 1.完成文件复制
// IOUtils.copy(new FileInputStream("day09-file-io\\src\\data07.txt"),
// new FileOutputStream("day09-file-io\\src\\new-data07.txt"));
// 2.完成文件复制到某个文件夹下
// FileUtils.copyFileToDirectory(new File("day09-file-io\\src\\data07.txt"),
// new File("day09-file-io\\src\\txt\\"));
// 3.完成文件夹复制到某个文件夹下!
// FileUtils.copyDirectoryToDirectory(new File("day09-file-io\\\\src\\\\txt")
// ,new File("day09-file-io\\src\\txt1\\txt2"));
// FileUtils.deleteDirectory(new File("day09-file-io\\src\\txt1\\txt2"));
// JDK1.7 自己也做了一些一行代码完成复制的操作 NIO
Files.copy(Paths.get("day09-file-io\\src\\txt\\data07.txt"),Paths.get("day09-file-io\\src\\txt\\data08.txt"));
}
}
标签:IO,字符集,System,File,println,new,out,public,字节
From: https://www.cnblogs.com/zzx944964684/p/17007737.html