📃个人主页:个人主页
🔥系列专栏:JAVASE基础
前言:
目前的编程中,数据存储方式有很多种,包括但不限于:
-
文件存储:将数据以文件的形式存储在磁盘上,可以使用文件读写操作进行数据的存取。
-
数据库存储:将数据以表格的形式存储在数据库中,可以使用SQL语句进行数据的管理。
-
缓存存储:将数据存储在缓存中,可以快速地读写数据,提高程序的效率。
-
内存存储:将数据存储在程序的内存中,可以快速地读写数据,但是程序结束后数据就会丢失。
以上存储方式都有各自的优缺点。文件存储的优点是简单易懂,缺点是读写速度相对较慢;数据库存储的优点是可以进行高级的数据管理,缺点是需要较高的技术水平;缓存存储的优点是读写速度快,缺点是需要占用较多的内存资源;内存存储的优点是读写速度最快,缺点是数据易丢失。
目录
前言:
一、File类
1.创建File对象
2.常用方法
3.File类的遍历功能
4.案例:检查谁没交作业
二、IO流
1.字节流
1.文件字节输入流:FileInputStream
2.文件字节输出流:FileOutputStream
3.文件拷贝
2.资源释放的方式
1.try-catch-finally
2.try-with-resource
一、File类
Java中的File类表示文件或目录的路径名。它可以用于创建、删除、重命名、复制文件或目录。File类中的一些常见的方法包括:
- exists():判断文件或目录是否存在。
- mkdir() / mkdirs():创建一个文件夹,mkdir() 创建单级目录,mkdirs() 创建多级目录。
- delete():删除文件或目录。
- renameTo():重命名文件或目录。
- isFile() / isDirectory():判断是否是文件或目录。
- canRead() / canWrite() / canExecute():判断文件或目录是否可读、可写、可执行。
另外,File类还可以用于获取文件或目录的属性信息,例如文件修改时间、文件大小等等。在Java中,File类被广泛地应用于文件操作和文件路径处理。
1.创建File对象
方法名称 | 说明 |
public File(String pathname) | 根据文件路径创建文件对象 |
public File(String parent, String child) | 根据父路径名字符串和子路径名字符串创建文件对象 |
public File(File parent, String child) | 根据父路径对应文件对象和子路径名字符串创建文件对象 |
在Java中,可以使用File类来创建文件或目录的对象。
要创建一个File对象,你可以使用File类的构造函数,并向它传递文件或目录的路径作为参数。例如,如果要创建一个名为“myfile.txt”的文件对象,可以这样写:
File file = new File("myfile.txt");
如果你想在指定位置创建一个新的文件夹,可以使用相同的构造函数,并将目录路径作为参数:
File dir = new File("D:\\myFolder");
请注意,在使用File类创建对象时,它只是表示路径,而不涉及任何实际的文件或目录。因此,如果要使用这些文件或目录,你需要使用其他类和方法来读取、写入或操作它们。
绝对路径和相对路径
绝对路径和相对路径都是用来定位文件或目录的路径信息。
绝对路径是从根目录开始的完整路径,可以唯一地确定一个文件或目录的位置,如:C:\Users\Administrator\Desktop\test.txt。
相对路径是相对于当前目录的路径,可以通过与当前目录的相对位置来确定文件或目录的位置,如:..\Documents\test.txt,其中“..”表示当前目录的上级目录。
在使用路径时,需要根据需要选择使用绝对路径或相对路径,通常情况下,使用相对路径可以减少路径的长度,使路径更加简洁明了,但是如果需要确保路径的唯一性,则需要使用绝对路径。
2.常用方法
常用方法:判断文件类型、获取文件信息
- getPath():返回文件路径的字符串表示。
- getName():返回文件名。
- isDirectory():判断文件是否是目录。
- isFile():判断文件是否是普通文件。
- exists():判断文件是否存在。
- canRead():判断是否可读取文件。
- canWrite():判断是否可写入文件。
- length():返回文件的大小,以字节为单位。
- listFiles():返回此目录中包含的文件和目录的文件数组。
import java.io.File;
public class FileDemo {
public static void main(String[] args) {
// 实例化一个文件对象
File file = new File("D:/test.txt");
// 调用getPath()方法获取文件路径
String path = file.getPath();
System.out.println("文件的路径为:" + path);
// 调用getName()方法获取文件名
String name = file.getName();
System.out.println("文件名为:" + name);
// 调用isDirectory()方法判断是否是目录
boolean isDir = file.isDirectory();
System.out.println("是否是目录:" + isDir);
// 调用exists()方法判断文件是否存在
boolean isExist = file.exists();
System.out.println("文件是否存在:" + isExist);
// 调用length()方法获取文件大小
long size = file.length();
System.out.println("文件大小为:" + size + "字节");
}
}
常用方法:创建文件、删除文件功能
- createNewFile():创建一个新的空的文件
- mkdir():只能创建一级文件夹
- mkdirs():可以创建多级文件夹
- delete():删除由此抽象路径名表示的文件或空文件夹
创建文件:
File file = new File("example.txt");
try {
if (file.createNewFile()) {
System.out.println("文件创建成功!");
} else {
System.out.println("文件已存在!");
}
} catch (IOException e) {
e.printStackTrace();
}
在上述代码中,我们首先创建一个File
对象,指定了新文件的路径。然后,我们使用createNewFile()
方法创建该文件。如果文件创建成功,该方法返回 true;否则返回 false。如果文件已经存在,我们不会创建新文件,并提示用户文件已存在。
删除文件:
File file = new File("example.txt");
if (file.delete()) {
System.out.println("文件已删除!");
} else {
System.out.println("文件删除失败!");
}
在上述代码中,我们首先创建一个File
对象,指定待删除的文件路径。然后,我们使用delete()
方法删除该文件。如果文件删除成功,该方法返回 true;否则返回 false。如果文件不存在,该方法也会返回 false。
注意 delete方法默认只能删除文件和空文件夹,delete方法直接删除不走回收站
3.File类的遍历功能
Java中的File类提供了多种方法来遍历文件和目录。以下是一些常见的方法:
1.list()方法:返回指定目录下的所有文件和目录的名称数组。
File file = new File("/path/to/directory");
String[] files = file.list();
for (String fileName : files) {
System.out.println(fileName);
}
2.listFiles()方法:返回指定目录下的所有文件和目录的File对象数组。
File file = new File("/path/to/directory");
File[] files = file.listFiles();
for (File f : files) {
System.out.println(f.getName());
}
listFiles方法注意事项:
- 当文件不存在时或者代表文件时,返回null
- 当文件对象代表一个空文件夹时,返回一个长度为0的数组
- 当文件对象是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回
- 当文件对象是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
- 当没有权限访问该文件夹时,返回null
4.案例:检查谁没交作业
MySQL+Java实现
例如:同学们按:学号.txt 这样的格式交作业,利用 File类+MySQL 来 查询谁没交作业。
(实际中 可能大家按 学号-姓名-班级 这样的格式收作业,到时候只需变更部分Java代码即可 )
1. 把班级信息导入数据库中:
表结构:
模拟数据:
INSERT INTO Student (id,name) VALUES ('00001','农修平');
INSERT INTO Student (id,name) VALUES ('00002','贲新觉');
INSERT INTO Student (id,name) VALUES ('00003','容文滨');
INSERT INTO Student (id,name) VALUES ('00004','范姜雨文');
INSERT INTO Student (id,name) VALUES ('00005','商自怡');
INSERT INTO Student (id,name) VALUES ('00006','单幻枫');
INSERT INTO Student (id,name) VALUES ('00007','黄靖巧');
INSERT INTO Student (id,name) VALUES ('00008','寸开济');
INSERT INTO Student (id,name) VALUES ('00009','谯文山');
INSERT INTO Student (id,name) VALUES ('00010','之依柔');
INSERT INTO Student (id,name) VALUES ('00011','殴德本');
INSERT INTO Student (id,name) VALUES ('00012','纪晓槐');
INSERT INTO Student (id,name) VALUES ('00013','农从南');
INSERT INTO Student (id,name) VALUES ('00014','沃新竹');
INSERT INTO Student (id,name) VALUES ('00015','米文彦');
INSERT INTO Student (id,name) VALUES ('00016','应元彤');
INSERT INTO Student (id,name) VALUES ('00017','田笑旋');
INSERT INTO Student (id,name) VALUES ('00018','红华藏');
INSERT INTO Student (id,name) VALUES ('00019','宇文晓槐');
INSERT INTO Student (id,name) VALUES ('00020','广书芹');
INSERT INTO Student (id,name) VALUES ('00021','羊浩宕');
INSERT INTO Student (id,name) VALUES ('00022','喻晗');
INSERT INTO Student (id,name) VALUES ('00023','南宫雨雪');
INSERT INTO Student (id,name) VALUES ('00024','皮千山');
INSERT INTO Student (id,name) VALUES ('00025','逯映之');
INSERT INTO Student (id,name) VALUES ('00026','江天材');
INSERT INTO Student (id,name) VALUES ('00027','荆浩气');
INSERT INTO Student (id,name) VALUES ('00028','呼延芸');
INSERT INTO Student (id,name) VALUES ('00029','乜修齐');
INSERT INTO Student (id,name) VALUES ('00030','司徒德明');
INSERT INTO Student (id,name) VALUES ('00031','班听枫');
INSERT INTO Student (id,name) VALUES ('00032','公叔安波');
INSERT INTO Student (id,name) VALUES ('00033','京馡');
INSERT INTO Student (id,name) VALUES ('00034','万俟荭');
INSERT INTO Student (id,name) VALUES ('00035','尚兴昌');
INSERT INTO Student (id,name) VALUES ('00036','暨冷亦');
INSERT INTO Student (id,name) VALUES ('00037','别良平');
INSERT INTO Student (id,name) VALUES ('00038','居水 竹');
INSERT INTO Student (id,name) VALUES ('00039','郭怜梦');
INSERT INTO Student (id,name) VALUES ('00040','年映秋');
INSERT INTO Student (id,name) VALUES ('00041','毋阳辉');
INSERT INTO Student (id,name) VALUES ('00042','吕旭');
INSERT INTO Student (id,name) VALUES ('00043','国伟彦');
INSERT INTO Student (id,name) VALUES ('00044','安锐进');
INSERT INTO Student (id,name) VALUES ('00045','杨凝雁');
INSERT INTO Student (id,name) VALUES ('00046','南宫亨');
INSERT INTO Student (id,name) VALUES ('00047','却雅阳');
INSERT INTO Student (id,name) VALUES ('00048','富小霜');
INSERT INTO Student (id,name) VALUES ('00049','汲力学');
INSERT INTO Student (id,name) VALUES ('00050','慎姲');
2.Java 获取交作业同学的 学号
模拟数据:创建 50 个 5 位数字的 txt 文件
public class Main {
public static void main(String[] args) {
// 创建名为 "example" 的文件夹
File folder = new File("example");
if (!folder.exists()) {
folder.mkdir();
}
// 创建 50 个 5 位数字的 txt 文件
for (int i = 1; i < 51; i++) {
String fileName = String.format("%05d.txt", i);
File file = new File(folder, fileName);
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
获取学号:
因为格式是 学号.txt 格式,所以 把.txt切割掉 就能获得学号:
String[] list = folder.list();
for (String s : list) {
int i = s.indexOf(".");
System.out.print("'"+s.substring(0,i)+"',");
}
把文件中的 00004 00033 00021 00041 删除【假设这4人没交作业】
然后再次运行Java程序:
'00001','00002','00003','00005','00006','00007','00008','00009','00010','00011','00012','00013','00014','00015','00016','00017','00018','00019','00020','00022','00023','00024','00025','00026','00027','00028','00029','00030','00031','00032','00034','00035','00036','00037','00038','00039','00040','00042','00043','00044','00045','00046','00047','00048','00049','00050',
3.查询结果
编写SQL:
SELECT * FROM student WHERE id NOT IN()
括号里面放Java控制台上的数据
SELECT * FROM student WHERE id NOT IN('00001','00002','00003','00005','00006','00007','00008','00009','00010','00011','00012','00013','00014','00015','00016','00017','00018','00019','00020','00022','00023','00024','00025','00026','00027','00028','00029','00030','00031','00032','00034','00035','00036','00037','00038','00039','00040','00042','00043','00044','00045','00046','00047','00048','00049','00050')
此时就能查询到有那些同学没有交作业:
二、IO流
IO流概述
- I表示intput,把硬盘文件中的数据读入到内存的过程,称之输入,负责读。
- O表示output,把内存中的数据写出到硬盘文件的过程,称之输出,负责写。
IO流的分类
总结流的四大类:
- 字节输入流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流称为字节输入流。
- 字节输出流:以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中去的流称为字节输出流。
- 字符输入流:以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入到内存中去的流称为字符输入流。
- 字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中去的流称为字符输出流。
1.字节流
Java字节流是Java IO中处理二进制数据的基本方式。字节流指的是以字节为单位读写数据的流,而字符流则是以字符为单位读写数据的流。字节流可以处理任何类型的数据,包括文本、图像、音频和视频等。Java字节流主要分为输入字节流和输出字节流两种,其中,输入字节流用于从文件或其他数据源读取数据,而输出字节流用于将数据写入文件或其他数据目标。
Java字节流的操作对象通常是InputStream和OutputStream类及其子类。InputStream和OutputStream是两个抽象基类,分别表示字节输入流和输出流的基本操作。Java中常用的输入字节流有FileInputStream、ByteArrayInputStream等,常用的输出字节流有FileOutputStream、ByteArrayOutputStream等。
1.文件字节输入流:FileInputStream
作用:以内存为基准,把磁盘文件中的数据以字节的形式读取到内存中去。
构造器 | 说明 |
public FileInputStream(File file) | 创建字节输入流管道与源文件对象接通 |
public FileInputStream(String pathname) | 创建字节输入流管道与源文件路径接通 |
方法名称 | 说明 |
public int read() | 每次读取一个字节返回,如果字节已经没有可读的返回-1 |
public int read(byte[] buffer) | 每次读取一个字节数组返回,如果字节已经没有可读的返回-1 |
在D盘创建一个名为:test.txt的文档 ,然后里面随便输入一些英文:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamExample {
public static void main(String[] args) {
File file = new File("D:/test.txt");
try (FileInputStream fis = new FileInputStream(file)) {
int data;
while ((data = fis.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在上面的示例代码中,我们创建了一个FileInputStream
对象来读取指定文件中的字节流。然后,我们使用read()
方法逐字节读取文件内容,并将其转换为字符类型并打印出来。
如果在内容里面写入中文:
直接乱码了:
分析原因:
UTF-8编码 一个中文一般以三个字节的形式存储。
所以,对于中文 需要每次3个字节地读取。
解决方案:
创建一个长度为3的字节数组,每次读取 该字节数组。
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamExample {
public static void main(String[] args) {
File file = new File("D:/test.txt");
try (FileInputStream fis = new FileInputStream(file)) {
byte[] bytes = new byte[3];
while ((fis.read(bytes)) != -1) {
System.out.print(new String(bytes));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
上面例子中,中文符号前面刚好是有6个英文符号,咋们是3个字节地去读,如果把5个英文符号变成5个,又会发生什么呢?
又出现了乱码:
分析原因:
我们是3个字节地去读,到 N-热 这里, “N- ” 已经站2个字节,而 “热” 占3个字节 不能读完,故此乱码。
解决方案:
方式一
自己定义一个字节数组与文件的大小一样大,然后使用读取字节数组的方法,一次性读取完成。
方法名称 | 说明 |
public int read(byte[] buffer) | 每次读取一个字节数组返回,如果字节已经没有可读的返回-1 |
方式二
官方为字节输入流InputStream提供了如下API可以直接把文件的全部数据读取到一个字节数组中
方法名称 | 说明 |
public byte[] readAllBytes() throws IOException | 直接将当前字节输入流对应的文件对象的字节数据 装到一个字节数组返回 |
思考:
1、使用字节流读取中文输出乱码,如何使用字节输入流读取中文输出不乱码呢?
定义一个与文件一样大的字节数组,一次性读取完文件的全部字节。
2、直接把文件数据全部读取到一个字节数组可以避免乱码,是否存在问题?
如果文件过大,字节数组可能引起内存溢出。
2.文件字节输出流:FileOutputStream
作用:以内存为基准,把内存中的数据以字节的形式写出到磁盘文件中去的流。
构造器 | 说明 |
public FileOutputStream(File file) | 创建字节输出流管道与源文件对象接通 |
public FileOutputStream(File file,boolean append) | 创建字节输出流管道与源文件对象接通,可追加数据 |
public FileOutputStream(String filepath) | 创建字节输出流管道与源文件路径接通 |
public FileOutputStream(String filepath,boolean append) | 创建字节输出流管道与源文件路径接通,可追加数据 |
文件字节输出流(FileOutputStream)写数据出去的API
方法名称 | 说明 |
public void write(int a) | 写一个字节出去 |
public void write(byte[] buffer) | 写一个字节数组出去 |
public void write(byte[] buffer , int pos , int len) | 写一个字节数组的一部分出去。 |
流的关闭与刷新
方法 | 说明 |
flush() | 刷新流,还可以继续写数据 |
close() | 关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据 |
Java中的文件字节输出流用于向文件中写入数据。它可以将字节数组、字符串、单个字节以及任何实现了WritableByteChannel接口的对象写入文件。FileOutputStream是Java IO库中的一个类,用于创建一个输出流对象,可以将数据写入一个文件中。
以下是一个示例:
import java.io.*;
public class FileOutputStreamExample {
public static void main(String[] args) {
try {
// 创建一个文件输出流对象
FileOutputStream fileOutput = new FileOutputStream("output.txt");
// 写入一个字符串到文件中
String str = "Hello World!";
fileOutput.write(str.getBytes());
// 关闭输出流
fileOutput.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
在上面的示例代码中,我们首先创建了一个FileOutputStream对象,指定了输出文件的路径和名称。然后,我们使用write()方法将一个字符串写入到文件中。最后,我们关闭了输出流。
注意:在使用文件输出流时,如果指定的路径中不存在该文件,则会自动创建该文件;如果文件已经存在,则该文件的内容将被覆盖。
字节输出流如何实现数据追加?
public FileOutputStream(String filepath,boolean append)
创建字节输出流管道与源文件路径接通,可追加数据
import java.io.*;
public class FileOutputStreamExample {
public static void main(String[] args) {
try {
// 创建一个文件输出流对象
FileOutputStream fileOutput = new FileOutputStream("output.txt",true);
// 写入一个字符串到文件中
String str = "热爱编程的小白白";
fileOutput.write(str.getBytes());
// 关闭输出流
fileOutput.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
再次运行:
字节输出流如何实现写出去的数据能换行?
fileOutput.write(“\r\n”.getBytes())
3.文件拷贝
你可以使用Java中的IO流来实现文件拷贝。以下是一个基本的文件拷贝示例:
import java.io.*;
public class FileCopy {
public static void main(String[] args) {
String sourceFile = "path/to/source/file"; // 源文件路径
String destFile = "path/to/destination/file"; // 目标文件路径
try (InputStream in = new FileInputStream(new File(sourceFile));
OutputStream out = new FileOutputStream(new File(destFile))) {
byte[] buffer = new byte[1024]; // 缓冲区大小,可以自己调整
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在这个示例中,我们使用了InputStream和OutputStream来从源文件读取和写入到目标文件。我们还使用了缓冲区来存储读取的数据。最后,在try块的末尾关闭了输入和输出流。
注意,这只是一个基本的示例,还有很多方法可以优化和改进代码。
字节流适合做一切文件数据的拷贝吗?
任何文件的底层都是字节,拷贝是一字不漏的转移字节,只要前后文件格式、编码一致没有任何问题。
2.资源释放的方式
1.try-catch-finally
- finally:放在try-catch后面的,无论是正常执行还是异常执行代码,最后一定要执行,除非JVM退出。
- 作用:一般用于进行最后的资源释放操作(专业级做法)
finally代码块是最终一定要执行的,可以在代码执行完毕的最后用于释放资源。
2.try-with-resource
1. finally虽然可以用于释放资源,但是释放资源的代码过于繁琐?
2. 有没有办法简化?
JDK 7和JDK9中都简化了资源释放操作
示例(文件拷贝):
import java.io.*;
public class FileCopy {
public static void main(String[] args) {
String sourceFile = "path/to/source/file"; // 源文件路径
String destFile = "path/to/destination/file"; // 目标文件路径
try (InputStream in = new FileInputStream(new File(sourceFile));
OutputStream out = new FileOutputStream(new File(destFile))) {
byte[] buffer = new byte[1024]; // 缓冲区大小,可以自己调整
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意
JDK 7 以及 JDK 9的()中只能放置资源对象,否则报错
什么是资源呢?
资源都是实现了Closeable/AutoCloseable接口的类对象