一、存储数据的方案(内存中和磁盘中)
内存中:
磁盘中:
1.1 什么是File?
1.2 什么是IO流?有什么作用?
由于File只能对文件本身进行操作,不能读写文件里面存储的数据,为了解决这个缺陷,引入了IO流,IO流用于读写数据,可以读写文件以及网络中的数据
二 、File的创建,常用方法
import java.io.File;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
// 创建File对象
File file = new File("E:\\work\\2025后端工单\\2025-3-31关于优化黄金会员权益次包融合销售页面的工单\\2025.4.2黄金会员+权益产品html\\2025.4.2黄金会员+权益产品html\\images\\icon-1.png");
// 获取文件路径
System.out.println(file.getAbsolutePath());
// 获取文件大小
System.out.println(file.length());
// 获取文件名
System.out.println(file.getName());
// 创建文件对象,判断文件是否存在,不存在则创建
File file1 = new File("D:\\study\\text.txt");
System.out.println(file1.exists());
System.out.println(file1.createNewFile());
// 创建文件夹
File file2 = new File("D:\\study\\images");
System.out.println(file2.mkdir());
// 创建多级文件夹
File file3 = new File("D:\\study\\test\\img\\images");
System.out.println(file3.mkdirs());
// 删除文件,删除空文件夹
File file4 = new File("D:\\study\\text.txt");
System.out.println(file4.delete());
// 获取某个目录下的全部一级文件名称
File file5 = new File("D:\\study");
String[] list = file5.list();
for (String s : list) {
/**
* 打印结果:
* images
* studyJava
* test
* typescript
* **/
System.out.println(s);
}
// 获取某个目录下的全部一级文件对象绝对路径
File file6 = new File("D:\\study");
File[] files = file6.listFiles();
for (File f : files) {
/**
* 打印结果:
* D:\study\images
* D:\study\studyJava
* D:\study\test
* D:\study\typescript
* **/
System.out.println(f.getAbsoluteFile()); // 获取文件绝对路径
}
}
}
/**
* 当主调是文件,或者路径不存在的时候,返回null
* 当主调是空文件夹,返回长度为0的数组
* 当主调是一个有内容的文件夹,将里面所有一级文件和文件夹的路径放在File数组中返回
* 当主调是一个文件夹,且里面有隐藏文件时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
* 当主调是一个文件夹,但是没有权限访问该文件夹时,返回null
*
**/
// 当主调是文件,或者路径不存在的时候,返回null
File file7 = new File("D:\\study\\tx.txt");
System.out.println(file7.exists()); // false
File[] files1 = file7.listFiles();
System.out.println(files1); // null
//当主调是空文件夹,返回长度为0的数组
File file8 = new File("D:\\study\\images");
File[] files2 = file8.listFiles();
System.out.println(Arrays.toString(files2)); // []
// 当主调是一个有内容的文件夹,将里面所有一级文件和文件夹的路径放在File数组中返回
File file9 = new File("D:\\study");
File[] files3 = file9.listFiles();
// [D:\study\images, D:\study\studyJava, D:\study\test, D:\study\typescript]
System.out.println(Arrays.toString(files3));
三、递归
案例:递归求1-n的和
需求:计算1-n的和的结果,使用递归思想解决。
分析:我们先从数学思维上理解递归的流程和核心点
1)假如我们认为存在一个公式是f(n)=1+2+3+4+5+6+7+.(n-1)+ n;
那么公式等价形式就是:f(n)=f(n-1)+ n
2)递归的终结点:f(1)=1
3)递归方向:
f(5) = f(4)+5
f(4) = f(3)+4
f(3) = f(2)+3
f(2) = f(1)+2
f(1) = 1
public class Digui {
public static void main(String[] args) {
System.out.println(sum(5));
}
public static int sum(int n) {
// 递归结束条件
if (n == 1) {
return 1;
}
// 递归调用
// sum(n - 1) + n 数学公式
return sum(n - 1) + n;
}
}
案例
猴子第一天摘下若干桃子,当即吃了一半,觉得好不过瘾,于是又多吃了一个第二天又吃了前天剩余桃子数量的一半,觉得好不过瘾,于是又多吃了一个以后每天都是吃前天剩余桃子数量的一半,觉得好不过瘾,又多吃了一个等到第10天的时候发现桃子只有1个了。那么第一天总共摘了多少个桃子?
案例:文件搜索
public class Digui2 {
public static void main(String[] args) {
// 在D盘下搜索文件名为qq.exe的文件
// 创建文件
File file = new File("D:\\");
searchFile(file,"qq.exe");
}
/**
* @param dir 搜索的目录
* @param filename 要搜索的文件名
* **/
public static void searchFile(File dir,String filename)
{
// 1.极端情况判断
if (dir == null || !dir.exists()|| dir.isFile()) {
return; // 如果dir不存在或者dir是一个文件,直接返回
}
// 2.获取目录下所有一级文件或者一级文件夹对象
File[] files = dir.listFiles();
// 3.判断当前目录下是否存在一级文件对象,存在才可以遍历
if (files != null && files.length > 0) {
// 4.遍历一级文件对象
for (File file : files) {
// 5.判断当前一级文件对象是否是文件,是文件就进行判断
if (file.isFile()) {
// 6.判断文件名是否是目标文件名
if (file.getName().equals(filename)) {
System.out.println("找到文件:" + file.getAbsolutePath());
}
} else {
// 7.如果当前一级文件对象是文件夹,就递归调用searchFile方法
searchFile(file,filename);
}
}
}
}
}
四、常见字符集
由于每个国家都有一套自己的编码方案,不利于通用,美国人为了统一编码于是做了Unicode字符集
由于Unicode编码每一个字符要4个字节,太占空间,为了解决这个问题,UTF-8出现了
4.1 UTF-8字符集
4.2 使用程序对字符进行编码和解码操作
String(byte[] bytes, String charsetName) 是 Java 中 String 类的一个构造方法:
byte[] bytes:表示一个字节数组,其中存储了以某种字符编码方式编码的字节数据。
String charsetName:表示字符集名称(如 “UTF-8”、“ISO-8859-1”、“GBK” 等)。
byte[ ] getBytes( ): 是 Java 中 String 类的一个方法,用于将字符串按照平台的默认字符集编码为字节数组
五、IO流
5.1 io流分类
5.2 FileInputStream(文件字节输入流)
public class Test {
public static void main(String[] args) throws IOException {
// 创建文件字节输入流管道与源文件接通
InputStream is = new FileInputStream("03\\src\\tx.txt");
// 读取文件内容,每次读一个字节
int b = 0;
// while ((b = is.read()) != -1) {
// // System.out.println(b);
// System.out.println((char)b);
// }
// 读取文件内容,每次多个字节
// 1、定义一个字节数组,每次读3个字节
byte[] buffer = new byte[3];
// 定义一个变量len,用于记住每次读取了多少个字节
int len = 0;
while ((len = is.read(buffer)) != -1) {
// 0表示从第一个字节开始读取,len表示读取了多少个字节就输出多少个字节
String str = new String(buffer,0,len);
System.out.println(str);
}
}
}
5.2.1 FileInputStream缺陷
**缺陷展示:**假设tx.txt文件的内容为:abc6669我爱你g,每次读取3个字节,第一次读取abc,第二次读取666,第三次读取9我爱的时候就会出问题,原因是9是数字字符只需要1个字节,我爱是汉子,每个字符需要2个字节
InputStream is = new FileInputStream("03\\src\\tx.txt");
// 1、定义一个字节数组,每次读3个字节
byte[] buffer = new byte[3];
// 定义一个变量len,用于记住每次读取了多少个字节
int len = 0;
while ((len = is.read(buffer)) != -1) {
// 0表示从第一个字节开始读取,len表示读取了多少个字节就输出多少个字节
String str = new String(buffer,0,len);
System.out.println(str);
}
5.2.2 如何解决FileInputStream缺陷问题:一次读取完全部字节
public class Test2 {
public static void main(String[] args) throws FileNotFoundException {
// 创建文件流
InputStream is = new FileInputStream("03\\src\\tx2.txt");
// 读取文件
// readAllBytes() 方法必须jdk版本9以上
// byte[] bytes = is.readAllBytes();
// String rs = new String(bytes);
// System.out.println(rs);
}
}
5.2.3 FileOutputStream文件字节输出流
public class Test {
public static void main(String[] args) throws IOException {
// 1、创建文件字节输出流管道与目标文件接通
// OutputStream os = new FileOutputStream("03\\src\\txout.txt"); // 覆盖管道
OutputStream os = new FileOutputStream("03\\src\\txout.txt",true); //内容追加管道
// 2、写入数据
os.write(97);
os.write('b');
os.write("\r\n".getBytes()); // 换行
// 3、写一个字节数组的一部分出去
byte[] bytes = "我爱你中国666".getBytes();
// 全部写入
os.write(bytes);
os.write("\r\n".getBytes()); // 换行
// 4、写一个字节数组的一部分出去,写3个字节,即:写出了我
os.write(bytes, 0, 3);
os.write("\r\n".getBytes());// 换行
// 关闭流,用完流之后要关闭管道,释放占用的资源
os.close();
}
}
5.2.4 案例:文件复制,将D盘的一张图复制到C盘
public class Test {
public static void main(String[] args) throws IOException {
copyFile("E:\\btn-icon1.png", "D:\\btn-new.png");
}
// 复制文件copyFile
public static void copyFile(String srcPath,String destPath) throws IOException {
// 1、创建一个文件字节输入流管道与源文件接通
InputStream fis = new FileInputStream(srcPath);
OutputStream fos = new FileOutputStream(destPath);
// 2、读取一个字节数组,写入一个字节数组
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1){
// 写入fos中
fos.write(buffer,0,len); // 读取多少个字节就写入多少个字节
}
System.out.println("复制成功!");
}
}
总结:字节流非常适合做文件的复制操作:
任何文件的底层都是字节,字节流做复制,是一字不漏的转移完全部字节,只要复制后的文件格式一致就没问题!
5.2.5 资源释放方案
5.2.5.1 **方案一(try-catch-finally):**缺点:写法过于臃肿,基本已经被放弃这种写法
public class Test {
public static void main(String[] args) throws IOException {
copyFile("E:\\btn-icon1.png", "D:\\btn-new.png");
}
// 复制文件
public static void copyFile(String srcPath,String destPath) {
InputStream fis = null;
OutputStream fos = null;
try{
// 1、创建一个文件字节输入流管道与源文件接通
fis = new FileInputStream(srcPath);
fos = new FileOutputStream(destPath);
// 2、读取一个字节数组,写入一个字节数组
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1){
// 写入fos中
fos.write(buffer,0,len); // 读取多少个字节就写入多少个字节
}
System.out.println("复制成功!");
}catch (IOException e){
e.printStackTrace();
}finally {
// 关闭流,释放资源
try{
if(fos != null) fos.close();
}catch (Exception e){
e.printStackTrace();
}
try{
if(fis != null) fis.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
5.2.5.2 方案二(try-with-resource)
public class Test {
public static void main(String[] args) throws IOException {
copyFile("E:\\btn-icon1.png", "D:\\btn-new.png");
}
// 复制文件
public static void copyFile(String srcPath,String destPath) {
try(
// 1、创建一个文件字节输入流管道与源文件接通
InputStream fis = new FileInputStream(srcPath);
OutputStream fos = new FileOutputStream(destPath);
){
// 2、读取一个字节数组,写入一个字节数组
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1){
// 写入fos中
fos.write(buffer,0,len); // 读取多少个字节就写入多少个字节
}
System.out.println("复制成功!");
}catch (Exception e){
e.printStackTrace();
}
}
}
5.3 字符流
5.3.1 文件字符输入流
5.3.2 文件字符输出流
5.4 缓冲流
5.4.1 缓冲字节输入流BufferedInputStream
5.4.2 缓冲字符流
5.5 其他流
5.5.1 InputStreamReader字符输入转换流
作用:解决不同编码时,字符流读取文本内容乱码的问题
解决思路:先获取文件的原始字节流,再将其按真实的字符集编码转成字符输入流,这样字符输入流中的字符就不乱码了
5.5.2 PrintStream、PrintWriter打印流
作用 :打印流可以实现更方便、更高效的打印数据出去,能实现打印啥出去就是啥出去
5.5.3 DataInputStream、DataOutputStream(特殊数据流)
DataOutputStream数据输出流
DataInputStream输入流
5.6 IO框架