File
构造方法
File(String pathname)
:给定路径字符串来创建一个FileFile(String parent,String child)
:给定父路径字符串和子路径字符串来创建一个FileFile(File parent,String child)
:给定父File和子字符串来创建一个新的File
String root = "E:/practice";
File file1 = new File(root + "/file1");
File file2 = new File(root, "/file2");
File file3 = new File(new File(root), "/file2");
常用方法
查找
获取File
String FileClass = "FileClass";
File file = new File(FileClass);
//E:\Projects\Java\JavaSE\Step\FileClass,但是这个返回的是File不是String
System.out.println(file.getAbsoluteFile());
获取路径
String FileClass = "FileClass";
File file = new File(FileClass);
//E:\Projects\Java\JavaSE\Step\FileClass,返回的是字符串,返回绝对路径
System.out.println(file.getAbsolutePath());
//FileClass,返回定义时的路径,如果当初定义的时候使用的是绝对路径,那么和getAbsolutePath一样
System.out.println(file.getPath());
获取文件名/目录名
String fileStr = "FileClass";
File file = new File(fileStr);
//FileClass,获取文件名/目录
System.out.println(file.getName());
文件列表
String file = "E:\\Projects\\Java\\JavaEE\\SpringBoot";
File file1 = new File(file);
/*
list():返回一个String[],包含其下的所有文件和目录名字字符串,不包括子目录
结果:
photo_of_the_day
springboottest
*/
Arrays.stream(file1.list()).forEach(System.out::println);
/*
list(FilenameFilter filter):指定过滤器,当且仅当过滤器返回true时返回指定的文件/目录名字
结果:photo_of_the_day
*/
Arrays.stream(file1.list((dir, name) -> name.contains("day"))).forEach(System.out::println);
String file = "E:\\Projects\\Java\\JavaEE\\SpringBoot";
File file1 = new File(file);
/*
listFiles():返回File[]
结果:
E:\Projects\Java\JavaEE\SpringBoot\photo_of_the_day
E:\Projects\Java\JavaEE\SpringBoot\springboottest
*/
Arrays.stream(file1.listFiles())
.forEach(i -> System.out.println(i.getAbsolutePath()));
/*
list(FilenameFilter filter):指定过滤器,当且仅当返回true时才返回
结果:E:\Projects\Java\JavaEE\SpringBoot\photo_of_the_day
*/
Arrays.stream(file1.listFiles((dir, name) -> name.contains("photo")))
.forEach(i -> System.out.println(i.getAbsolutePath()));
/*
listFiles(FilenameFilter filter):类似上面
结果:E:\Projects\Java\JavaEE\SpringBoot\springboottest
*/
Arrays.stream(file1.listFiles(pathname -> pathname.getName().contains("spring")))
.forEach(i -> System.out.println(i.getAbsolutePath()));
注意了,以上的三个:获取File的绝对形势,字符串形式,路径字符串,文件名等等 即使没有对应的文件,结果照样返回,比如:
String str = "G:/practice";
File file = new File(str,"file1");
System.out.println(file.getAbsoluteFile());
我的电脑中根本没有G盘,但是照样返回了对应的字符
获取文件大小
String fileStr = "E:\\practice";
File file = new File(fileStr, "practice.txt");
//10
System.out.println(file.length());
断言
文件/目录是否存在
String fileStr = "FileClass";
File file = new File(fileStr);
//true
System.out.println(file.exists());
File是否为目录/文件
String fileStr = "FileClass";
File file = new File(fileStr);
if (file.exists())
//判断是否为目录
if (file.isDirectory())
System.out.println("目录");
//判断是否为文件
else if (file.isFile())
System.out.println("文件");
创建和删除
创建目录
File root = new File("E:\\practice");
//假如没有这个目录,创建目录并返回true,否则不创建目录返回false
System.out.println(root.mkdir());
创建目录们
File file2 = new File("E:\\practice\\practice2\\practice3");
//创建文件们
System.out.println(file2.mkdirs());
这个和上一个的区别是
mkdir
只是创建一级目录mkdirs
创建这个目录,包括它的父级目录
创建文件
File root = new File("E:\\practice");
File file1 = new File(root, "practice.txt");
if (root.mkdir()) {
try {
//创建文件
System.out.println(file1.createNewFile());
} catch (IOException e) {
e.printStackTrace();
}
}
删除文件或目录
File root = new File("E:\\practice");
File file1 = new File(root, "practice.txt");
//文件可以直接删掉
System.out.println(file1.delete());
//删除,当且仅当目录下没有其他文件或者目录才可以删掉目录
System.out.println(root.delete());
IO
IO的介绍和分类
什么是IO
IO有两个单词:Input,Output。简单来讲就是输入输出。我们一般称IO为IO流。
为什么称IO为IO流
IO是一种流式结构,比如储水库到你家里必定会通一根水管,顺着这根管道,对应的水流才能到达你家。在Java中IO也是这种作用。
比如你想要在程序中,获得网络上或者本地上的某些数据,必定要从架设一根管道,从数据源到达你的程序。
管道中流通的就是我们想要的数据,我们要做的就是架设这样一个管道然后处理对应的数据。
输入输出的基准
有输入输出,肯定有一个目标,以这个目标作为输入输出,我们的这个目标就是内存。
IO的分类
根据不同的标准可以有多种分类 比如按照数据的流通方向可以分为输入流和输出流 根据数据的格式可以分为字节流和字符流 根据数据的层级关系可以分为基本流和增强流等等。。。,但是我们现在先看比较基本的分类
输入流 | 输出流 | |
---|---|---|
字节流 | 字节输入流:InputStream | 字节输出流:OutputStream |
字符流 | 字符输入流:Reader | 字符输出流:Writer |
基本流
字节流
二进制在一开始的时候就已经讲过了,我们看的文本,图片,音乐,视频等等都是由二进制的形式保存的,都是一个又一个的字节
字节输入流和字节输出流
/**
* 输入流:InputStream
* 基本方法:
* - read():读取一个字符
* - read(byte[] b)读取字节数组
* - read(byte[] b, int off, int len):指定字节数组的起始点和长度去读取
* - close():关闭流,就像水龙头一样,用完就关闭
* 输出流:OutputStream
* 基本方法:
* - write(int b):写一个字节
* - write(byte[] b):写一个字节数组
* - write(byte[] b, int off, int len):指定字节数组的起始点和长度写出
* - flush():将缓冲的所有数据写出
* - close():关闭流
*/
文件输入流和文件输出流
如果要演示的时候,我们的案例选择文件操作流,他们的体系如下:
更具体的也没啥好说的,API上也非常简单,那就直接上代码
@Test
public void Step1() {
/*图片源*/
File picIn = new File("C:\\Users\\user\\Pictures\\Win10壁纸\\2020718.jpg");
/*要输出的地址*/
File picOut = new File("E:\\Notes\\2020718.jpg");
InputStream inputStream = null;
OutputStream outputStream = null;
/*确立中转字节*/
int b = 0;
try {
/*确立输入流和输出流*/
inputStream = new FileInputStream(picIn);
outputStream = new FileOutputStream(picOut);
/*
- 是否为-1代表着是否读取出来了对应的字节,或者说还有没有字节
- 注意(b = inputStream.read()) != -1,最终来判断的是b是否为-1
- 因为inputStream.read()之后在读取就是下一个字节了,输出的时候不可能输出这一个,所以需要一个中转
*/
while ((b = inputStream.read()) != -1) {
outputStream.write(b);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
/*首先要判断是否为空,然后将流进行关闭*/
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
字符流
- 1字符==两字节
- 有些字符存储是占用两个字符的,比如中文
- 如果采用字节的方式读取,中文肯定乱码,所以需要字符流来进行读取
- 一般字符流用于读取文本文件
字符输入流和字符输出流的基本API和字节流一样,就不用再说了
下面来看体系结构
为了好看,我们现在分别以字节流和字符流的方式来读取一篇中英文混合的txt文档
天地有正气,杂然赋流形。下则为河岳,上则为日星。於人曰浩然,沛乎塞苍冥。
皇路当清夷,含和吐明庭。时穷节乃见,一一垂丹青。在齐太史简,在晋董狐笔。
在秦张良椎,在汉苏武节。为严将军头,为嵇侍中血。为张睢阳齿,为颜常山舌。
或为辽东帽,清操厉冰雪。或为出师表,鬼神泣壮烈。或为渡江楫,慷慨吞胡羯。
或为击贼笏,逆竖头破裂。是气所磅礴,凛烈万古存。当其贯日月,生死安足论。
地维赖以立,天柱赖以尊。三纲实系命,道义为之根。嗟予遘阳九,隶也实不力。
楚囚缨其冠,传车送穷北。鼎镬甘如饴,求之不可得。阴房阗鬼火,春院闭天黑。
牛骥同一皂,鸡栖凤凰食。一朝蒙雾露,分作沟中瘠。如此再寒暑,百疠自辟易。
哀哉沮洳场,为我安乐国。岂有他缪巧,阴阳不能贼。顾此耿耿存,仰视浮云白。
悠悠我心悲,苍天曷有极。哲人日已远,典刑在夙昔。风檐展书读,古道照颜色。
字节输出流 ```java @Test public void Step1() {
File fileIn = new File("E:\\Notes\\In.txt");
File fileOut = new File("E:\\Notes\\Out.txt");
InputStream inputStream = null;
OutputStream outputStream = null;
int b = 0;
byte[] mid = new byte[1024];
try {
inputStream = new FileInputStream(fileIn);
outputStream = new FileOutputStream(fileOut);
while ((b = inputStream.read(mid)) != -1) {
outputStream.write(mid);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- 字符输出流
```java
@Test
public void Step2() {
File fileIn = new File("E:\\Notes\\In.txt");
File fileOut = new File("E:\\Notes\\Out2.txt");
Reader reader = null;
Writer writer = null;
int b = 0;
char[] mid = new char[1024];
try {
reader = new FileReader(fileIn);
writer = new FileWriter(fileOut);
while ((b = reader.read(mid)) != -1) {
writer.write(mid);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
可以看到,在这里我全部都使用了数组的方式,因为只有这样才会乱码,否则一个字节一个字节来读永远不会乱码 而且使用数组的方式是提升效率的一种方式,如果一个字节一个字节来读虽然不会出错但是耗费的时间太长
增强流
增强流介绍
增强流,顾名思义是用来增强我们之前的基本流的 增强流可以理解为一个套子,套在我们之前的基本流的。 通过增强流可以得到很多不同的功能
缓冲流
缓冲流介绍
缓冲流是对文件操作流的一个增强。 可以理解为一个蓄水池,当蓄水池满了之后一下子进行处理,而不是对水滴一个一个处理。 缓冲流底层内置了一个默认大小的缓冲数组,通过缓冲区来进行处理,减少系统的IO次数,提高读写效率。
- 源码说明
public BufferedOutputStream(OutputStream out) {
this(out, 8192);
}
public BufferedOutputStream(OutputStream out, int size) {
super(out);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
我们以
BufferedOutputStream
打个比方,这里很清晰的说明了,默认的字节数组是8192
,当然了,我们也可以自己自定义数组,只要输入size
数值就好了
字节缓冲流
@Test
public void Step4() {
InputStream inputStream = null;
OutputStream outputStream = null;
BufferedInputStream bufferedInputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
inputStream = new FileInputStream("E:\\Notes\\In.txt");
outputStream = new FileOutputStream("E:\\Notes\\Out.txt");
/*既然是要对文件操作流进行增强,那么肯定是需要原本的文件操作流*/
bufferedInputStream = new BufferedInputStream(inputStream);
bufferedOutputStream = new BufferedOutputStream(outputStream);
int b;
while ((b = bufferedInputStream.read()) != -1) {
bufferedOutputStream.write(b);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bufferedInputStream != null) {
try {
bufferedInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedOutputStream != null) {
try {
bufferedOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
API什么的就不用说了,和之前的一样
字符缓冲流
@Test
public void Step5() {
Reader reader = null;
Writer writer = null;
BufferedReader bufferedReader = null;
BufferedWriter bufferedWriter = null;
try {
reader = new FileReader("E:\\Notes\\In.txt");
writer = new FileWriter("E:\\Notes\\Out.txt");
bufferedReader = new BufferedReader(reader);
bufferedWriter = new BufferedWriter(writer);
String str;
/*readLine:一次读一行*/
while ((str = bufferedReader.readLine()) != null) {
bufferedWriter.write(str);
/*newLine:一个回车*/
bufferedWriter.newLine();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedWriter != null) {
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
主要注意两个特有的方法:
- readLine:一次读一行
- newLine:写一个回车
我们可以使用read(),但是这样做的效率很低,所以有了readLine和newLine
转换流
字符编码和字符集
字符集和字符编码的介绍
- 字符集:或者叫编码表,现实世界中的字符的集合,包括但不限制文字,标点符号,图形,数组等等
- 字符编码:一套二进制和字符之间相互转换的规则
- 一个字符集对应着一个或多个字符编码
常见的字符集和字符编码
常见的字符集和字符编码有:
- ASCII字符集-ASCII字符编码
- GBK字符集-GBK字符编码
- Unicode字符集-UTF8/UTF16/UTF32字符编码
现如今,我们最常使用的是Unicode字符集-UTF8字符编码,IDEA默认的也就是这一套
编码带来的问题
简单两个字:乱码,比如文件原来是GBK的编码,但是IDEA读取是UTF8,这就会导致乱码错误 我们可以简单模拟一下这个过程,我们使用VSCode或者其他工具将In.txt转变为GBK编码,然后运行的缓冲流写的程序,发现:
解决乱码问题也简单,只需要字符输入转换流流和字符输出转换流流即可,为啥说只有字符呢?因为字节没有这个问题
字符输入流和字符输出流
InputStreamReader
:字节–>字符OutputStreamWriter
:字符–>字节注意了,这两个只能作为字节和字符的相互转换,并没有对文件进行操作的能力 不使用字节流对文件进行操作要么字符流,要么字符缓冲流
@Test
public void Step6() {
InputStreamReader inputStreamReader = null;
OutputStreamWriter outputStreamWriter = null;
BufferedReader reader = null;
BufferedWriter writer = null;
try {
/*读取要指定编码*/
inputStreamReader = new InputStreamReader(new FileInputStream("E:\\Notes\\In.txt"), "GBK");
/*写出也要指定编码*/
outputStreamWriter = new OutputStreamWriter(new FileOutputStream("E:\\Notes\\Out.txt"), "UTF-8");
reader = new BufferedReader(inputStreamReader);
writer = new BufferedWriter(outputStreamWriter);
String str;
while ((str = reader.readLine()) != null) {
writer.write(str);
writer.newLine();
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
序列化流
序列化流介绍
首先要介绍一下序列化和反序列化
- 序列化:持久化的过程,可以理解为将数据变为一个文件
- 反序列化:从文件读取数据
比如一个对象 我们可以使用序列化将这个对象的所有信息都变为一个字节序列存储起来为一个文件,这是序列化。 我们也可以从文件中将数据读取出来形成这个对象的信息,这叫反序列化
序列化输入流和输出流
ObjectOutputStream
:输出流ObjectInputStream
:输入流
序列化
- 对象实现序列化需要实现Serializable接口
- 如果对象的某些属性不需要序列化,则要使用
transient
关键字修饰
对象
@Data @AllArgsConstructor @NoArgsConstructor class Person implements Serializable { private String name; private transient int age;//不进行序列化 }
序列化 ```java @Test public void Step7() {
Person person = new Person("张三", 20);
ObjectOutputStream outputStream = null;
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream("E:\\Notes\\Out.txt");
outputStream = new ObjectOutputStream(fileOutputStream);
outputStream.writeObject(person);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- 反序列化
```java
@Test
public void Step8(){
FileInputStream fileInputStream = null;
ObjectInputStream inputStream = null;
try {
fileInputStream = new FileInputStream("E:\\Notes\\Out.txt");
inputStream = new ObjectInputStream(fileInputStream);
Person person = (Person) inputStream.readObject();
//Person(name=张三, age=0)
System.out.println(person.toString());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Properties
properties
,在你们日后的Java编程中这个东西将会一直伴随你们,所以现在赶快来混个脸熟
properties
是一种文件类型,和你们之前使用的.txt
,.java
,.doc
等等文件相似,它以.properties
结尾 它的持久化是一个基础功能,而主要作用就是作为配置文件,你们以后会经常和这个打交道的 Java中的properties类,主要就是读取Java的配置文件体系结构:
要是论辈分的话,
Properties
是Map家族的一员,更是HashTable的儿子,而它的优势就是可以操作文件,而HashTable不行
- 首先给出一个文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssmbuild?useSSL=true&useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=root
常用构造和方法
/** * properties: * 构造: * - Properties():创建空properties * - Properties(Properties defaults):创建有默认值的构造 * 常用方法: * - load(InputStream inStream):加载,源为输入流 * - load(Reader reader):加载,源为输入流 * - loadFromXML(InputStream in):加载,源为输入流,文件格式可以为xml * - stringPropertyNames():键,以字符串形式表示 * - list(PrintStream out):将此属性列表打印到指定的输出流 * - list(PrintWriter out):打印到指定的输出流 * - setProperty(String key, String value):设置值 * - getProperty(String key):根据键获取值 * - getProperty(String key, String defaultValue):根据键获取值,如果没有指定默认值 */
代码案例 ```java @Test public void Step3() { File file = new File(“E:\Notes\config.properties”);
InputStream stream = null;
PrintWriter writer = null;
try {
stream = new FileInputStream(file);
Properties properties = new Properties();
//加载指定的文件
properties.load(stream);
/*
取得键列表
jdbc.url
jdbc.username
jdbc.driver
jdbc.password
*/
properties.stringPropertyNames().stream().forEach(System.out::println);
/*
根据键获取值:jdbc:mysql://localhost:3306/ssmbuild
*/
System.out.println(properties.get("jdbc.url"));
/*设置参数*/
properties.setProperty("server.port", "8080");
writer = new PrintWriter("E:\\Notes\\config1.properties");
properties.list(writer);
writer.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (writer != null) {
writer.close();
}
}
}
- 结果
> 
---
<a name="4ea46762"></a>
#### **JSON**
> JSON,一种比序列化更加轻量,更加友好的数据交换的格式,现如今都替代了XML
> 更加轻量也就代表着有些功能被阉割了,比如无法存储对象,而且只能用于UTF-8
> 今天我们只是了解一下有JSON这个东西,具体等以后再说
---
---
<a name="bb2437e1"></a>
### **打印流**
<a name="22ee2b92"></a>
#### **打印流介绍**
> 为什么有了输出流,还要学习打印流呢?
> 因为打印流是整个IO包中信息输出最方便的类,没有之一,输出流也比不上他。
> 我们之前用的`System.out.println()`就属于打印流,或者说`println`属于打印流
> 打印流可以打印任何类型的数据信息,比如小数,整数,字符串
---
<a name="2148d736"></a>
#### **打印字节流和打印字符流**
> - 打印字节流:`PrintStream`
> - 打印字符流:`PrintWriter`
```java
@Test
public void Step9(){
OutputStream outputStream = null;
PrintStream printStream = null;
try {
outputStream = new FileOutputStream("E:\\Notes\\Out.txt");
printStream = new PrintStream(outputStream);
//设置流向
System.setOut(printStream);
//流向E:\\Notes\\Out.txt
System.out.println(97);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}