文章目录
Lambda表达式
-
应用:简化匿名内部的代码书写
- 要求:只能针对函数式接口进行操作
-
语法:
-
(参数列表) -> { //方法体代码 }
-
//针对函数式接口:Comparator,使用匿名内部类 Collections.sort(list, new Comparator<String,String>(){ //重写compare方法 public int compare(String s1, String s2){ //.... } }); //针对函数式接口:Comparator,使用Lambda Collections.sort(list, (String s1, String s2) -> { //.... } );
-
-
基于标准语法,进行省略:
-
//省略:参数 //1、省略参数列表中所有的参数类型 //2、当参数列表中仅有一个参数时,可以省略参数类型、小括号 //省略:方法体 //当方法体中仅有一个行代码时:可以省略 大括号、return、分号
-
Stream流
-
应用:针对集合、数组进行操作
-
Stream流:获取流、中间操作、终端操作
-
获取流:
-
//集合 Stream s1 = list.stream(); Stream s2 = set.stream(); Stream s3 = map.keySet.stream(); Stream s4 = map.entrySet().stream(); //数组 Stream s = Stream.of(数组[]);
-
-
中间操作(常用API方法)
-
filter() limit(n) skip(n) distinct() map() sorted(Comparator c)
-
-
终端操作(API方法)
-
forEach() count() collect( toList )
-
-
File类
-
应用:为了创建一个基于硬盘上的文件和目录的对象
-
//用户类 public class User{ String name;//登录名 String passwd;//密码 Date registerDate; //用户的注册时间 File file; //用户肖像 }
-
-
构造方法:
-
public File(String path) public File(String parent , String child) public File(File parent , String child)
-
-
常用方法:
-
获取功能
-
//文件名 String getName() //文件大小 long length() //文件修改时间 long lastModified()
-
-
判断功能
-
//文件是否存在 boolean exists() //是文件 boolean isFile
-
-
创建删除功能
-
//创建文件 createNewFile() //创建目录 mkdir() //要求:父路径必须存在 mkdirs() //父路径不存在时,会先创建父路径 //删除目录、文件 delete()
-
-
目录遍历
-
String[] list() //获取目录下所有文件或文件夹的名称 File[] listFiles() //获取当前目录下所有文件或目录的对象
-
-
递归
- 概念: 递归是应用在方法上的, 方法自己调用自己
- 递归实现:
- 递进
- 边界值 (为了约束递归,不能让递归实现死循环)
- 回归
- 递归的弊端:递归时会调用方法入栈执行,当递归次数过多时会造成栈内存空间占满,造成内存溢出
今天内容:
- IO:字节流 (重点)
- IO:字符流 (重点)
- Properties属性集
- ResourceBundle(类似于Properties)
一、IO流
IO概念:
- IO:计算机中设备之间数据传输使用的技术
- Java中的IO: 都在java.io包下
- 字节流:
- 字节输入流
- 字节输出流
- 字符流:
- 字符输入流
- 字符输出流
- 字节流:
- IO流分类:
- 字节输入流
- 字节输出流
- 字符输入流
- 字符输出流
- IO流的父类:
- 字节输入流:java.io.InputStream
- 字节输出流:java.io.OutputStream
- 字符输入流:java.io.Reader
- 字符输出流:java.io.Writer
1、IO概述
在操作计算机时,把数据存储到计算机的硬盘上,从硬盘上某个文件中读取数据,
都是需要使用IO流来实现的。
结论:IO流就是实现设备之间的数据传输。(计算机之间进行数据交互,需要借助IO流)
1)什么叫IO
I 就是Input, 表示输入,数据从硬盘(或者外部存储设备)输入 到内存 (读取文件)
O 就是Output,表示输出,数据从内存中输出到外部存储设备 (写入文件)
结论:IO是以内存为基准,数据流向内存时为input,数据从内存中流出时为output
2)Java中I/O操作主要是指使用java.io
包下的内容,进行输入、输出操作。
输入也叫做读取数据,输出也叫做作写出数据。
java.io.File类:是用来操作文件或目录的 (不能对文件中存储的内容进行操作)
如果要对文件中存储的内容进行操作:读、写 ,需要使用java.io包下的InputStream、OutputStream
3)IO流分类
根据数据的流向分为:输入流和输出流。
- 输入流 :把数据从
其他设备
上读取到内存
中的流。 读数据 - 输出流 :把数据从
内存
中写出到其他设备
上的流。 写数据
根据数据的类型分为:字节流和字符流。
- 字节流 :以字节为单位,读写数据的流。(万能流:可以对任何类型的文件进行读写操作)
- 字符流 :以字符为单位,读写数据的流。(只能针对文本文件进行读写操作)
2、字节流(一切皆字节)
一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都是一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。
1)OutputStream字节输出流
java.io.OutputStream
抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。
public void close() // 关闭此输出流并释放与此流相关联的任何系统资源。
public void flush() // 刷新此输出流并强制任何缓冲的输出字节被写出。
public void write(byte[] b) // 将 b.length 字节从指定的字节数组写入此输出流。
public void write(byte[] b, int off, int len) // 从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
public abstract void write(int b) // 指定的字节输出流。
**注意:**close() 方法,当完成流的操作时,必须调用此方法,释放系统资源。
01、FileOutputStream类
java.io.FileOutputStream
类是文件输出流,用于将数据写出到文件。(是OutputStream
的子类)
构造方法
public FileOutputStream(File file) // 创建文件输出流以写入由指定的[File对象]表示的文件。
public FileOutputStream(String name) // 创建文件输出流以指定的[名称]写入文件。
// 1. 使用File对象创建流对象
File file = new File("a.txt");
FileOutputStream fos = new FileOutputStream(file);
// 2. 使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("b.txt");
写出字节数据
写出一个字节:
write(int b)
方法写出字节数组:
write(byte[] b)
方法写出指定长度字节数组:
write(byte[] b, int off, int len)
方法
// 1. write(int b) 写数据
// 使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("fos.txt");
// 虽然参数为int类型四个字节,但是只会保留一个字节的信息写出。
fos.write(97); // 写出第1个字节
fos.write(98); // 写出第2个字节
// 2. write(byte[] b)方法
FileOutputStream fos = new FileOutputStream("fos.txt");
// 字符串转换为字节数组
byte[] b = "祖国你好".getBytes();
// 写出字节数组数据
fos.write(b);
// 3. write(byte[] b, int off, int len) 方法
FileOutputStream fos = new FileOutputStream("fos.txt");
// 字符串转换为字节数组
byte[] b = "abcde".getBytes();
// 写入在b数组中-》从索引2开始,取长度为2个字节
fos.write(b,2,2);
fos.close();
数据追加续写
每次程序运行,创建输出流对象,都会清空目标文件中的数据。如何保留目标文件中数据,还能继续添加新数据呢?
public FileOutputStream(File file, boolean append) // 创建文件输出流以写入由指定的 File对象表示的文件。
public FileOutputStream(String name, boolean append) // 创建文件输出流以指定的名称写入文件。
// 例如:
// 使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("fos.txt",true);
// 字符串转换为字节数组
byte[] b = "追加数据".getBytes();
// 把数组中的数据写入文件中
fos.write(b);
// 关闭资源
fos.close();
true
表示追加数据,false
表示清空原有数据。这样创建的输出流对象,就可以指定是否追加续写了。
注意:
Windows系统里,换行符号是
\r\n
。Unix系统里、Mac系统里
\n
回车符
\r
和换行符\n
- 回车符:回到一行的开头(return)
- 换行符:下一行(newline)
写出一个换行, fos.write("\r\n".getBytes());
2)InputStream字节输入流
java.io.FileInputStream
抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。(是OutputStream
的子类)
public void close()
:关闭此输入流并释放与此流相关联的任何系统资源。public abstract int read()
: 从输入流读取数据的下一个字节。public int read(byte[] b)
: 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。
01、FileInputStream类
构造方法
File file = new File("a.txt");
FileInputStream fos = new FileInputStream(file); // 使用File对象创建流对象
FileInputStream fos = new FileInputStream("b.txt"); // 使用文件名称创建流对象
tip:创建一个流对象时,必须传入一个文件路径。
该路径下,如果没有该文件,会抛出
FileNotFoundException
读取字节数据
read
方法,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回-1
read(byte[] b)
,每次读取b的长度个字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回-1
// 1.没次读取一个字节
FileInputStream fis = new FileInputStream("read.txt"); // 文件中为abcde
int read = fis.read();
System.out.println((char) read);
// 定义变量,保存数据
int b ;
// 循环读取 --》 读取到文件末尾(循环结束)
while ((b = fis.read())!=-1) {
System.out.println((char)b);
}
// 2. 每次读取b的长度个字节到数组中
FileInputStream fis = new FileInputStream("read.txt"); // 文件中为abcde
// 定义变量,作为有效个数
int len ;
// 定义字节数组,作为装字节数据的容器
byte[] b = new byte[2];
// 循环读取(可能会有错误!!)
while (( len= fis.read(b))!=-1) {
// 每次读取后,把数组变成字符串打印
System.out.println(new String(b));
}
----------
输出结果:
ab
cd
ed // d 为无效字符
// 3. 避免 2 中的无效输出 字符
// 循环读取的改进
while (( len= fis.read(b))!=-1) {
// 每次读取后,把数组的有效字节部分,变成字符串打印
System.out.println(new String(b,0,len)); // len 每次读取的有效字节个数
}
// 关闭资源
fis.close(); // 操作结束后一定不要忘了这句
-----------
输出结果:
ab
cd
e
tip1:错误数据
d
,是由于最后一次读取时,只读取一个字节e
,数组中,上次读取的数据没有被完全替换,所以要通过len
,获取有效的字节。tip2:使用数组读取,每次读取多个字节,减少了系统间的IO操作次数,从而提高了读写的效率,建议开发中使用。
3)复制图片文件(案例)
public class Copy {
public static void main(String[] args) throws IOException {
// 1.创建流对象
// 1.1 指定数据源
FileInputStream fis = new FileInputStream("D:\\test.jpg");
// 1.2 指定目的地
FileOutputStream fos = new FileOutputStream("./test_copy.jpg");
// 2.读写数据
// 2.1 定义数组
byte[] b = new byte[1024];
// 2.2 定义长度
int len;
// 2.3 循环读取
while ((len = fis.read(b))!=-1) {
// 2.4 写出数据
fos.write(b, 0 , len);
}
// 3.关闭资源
fos.close();
fis.close();
}
}
3、字符流
当使用字节流读取文本文件时,遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储。所以Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。
1)Reader 字符输入流
java.io.Reader
抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。
public void close()
:关闭此流并释放与此流相关联的任何系统资源。public int read()
: 每次可以读取一个字符的数据,提升为int类型,读取到文件末尾,返回-1
public int read(char[] cbuf)
: 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中
FileReader类
java.io.FileReader
类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。tips:
字符编码:字节与字符的对应规则。Windows系统的中文编码默认是GBK编码表。
idea中UTF-8
字节缓冲区:一个字节数组,用来临时存储字节数据。
当创建一个流对象时,必须传入一个文件路径。类似于FileInputStream 。该路径下,如果没有该文件,会抛出
FileNotFoundException
构造方法
// 使用File对象创建流对象
File file = new File("a.txt");
FileReader fr = new FileReader(file);
// 使用文件名称创建流对象
FileReader fr = new FileReader("b.txt");
// 使用文件名称创建流对象
FileReader fr = new FileReader("read.txt");
// 定义变量,保存有效字符个数
int len ;
// 定义字符数组,作为装字符数据的容器
char[] cbuf = new char[2];
// 循环读取
while ((len = fr.read(cbuf))!=-1) {
System.out.println(new String(cbuf,0,len));
}
// 关闭资源
fr.close();
2)Writer字符输出流
java.io.Writer
抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。
public abstract void close()
:关闭此输出流并释放与此流相关联的任何系统资源。public abstract void flush()
:刷新此输出流并强制任何缓冲的输出字符被写出。public void write(int c)
:写出一个字符。public void write(char[] cbuf)
:将 b.length字符从指定的字符数组写出此输出流。public abstract void write(char[] b, int off, int len)
:从指定的字符数组写出 len字符,从偏移量 off开始输出到此输出流。public void write(String str)
:写出一个字符串。
FileWriter类
java.io.FileWriter
类是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。tip:当你创建一个流对象时,必须传入一个文件路径,类似于FileOutputStream。
构造方法
// 使用File对象创建流对象
File file = new File("a.txt");
FileWriter fw = new FileWriter(file);
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("b.txt");
写出字符:
write(int b)
方法,每次可以写出一个字符数据tips:
- 虽然参数为int类型四个字节,但是只会保留一个字符的信息写出。
- 未调用close方法,数据只是保存到了缓冲区,并未写出到文件中。
flush
:刷新缓冲区,流对象可以继续使用。close
:关闭流,释放系统资源。关闭前会刷新缓冲区。tip:即便是flush方法写出了数据,操作的最后还是要调用close方法,释放系统资源。
write(char[] cbuf)
write(char[] cbuf, int off, int len)
,每次可以写出字符数组中的数据,用法类似FileOutputStream
tip:字符流,只能操作文本文件,不能操作图片,视频等非文本文件。
当我们单纯读或者写文本文件时 使用字符流 其他情况使用字节流
二、IO资源处理
JDK7以前异常处理方式
try{
IO资源的访问代码
}catch(IOException e){
处理异常
}finally{
释放IO资源(调用close)
}
JDK7版本开始
对于IO资源的处理有种新的方式:try-with-resource
这种方式最大的好处是,不用程序员自己调用close方法释放资源了,会自动释放资源
格式:
try(资源1;资源2;资源3){
//操作资源
}catch(IOException e){
//处理异常
}
//注:创建资源如果有多个,使用分号进行分割
如果一个资源的类型是AutoCloseable接口的实现类,就可以去使用try-with-resource方式处理
结论:字节流、字符流都可以使用try-with-resource方式进行释放资源
tip:流对象必须有实现AutoCloseable接口,才可以激活使用:try…with…resource
三、Properties属性集
-
java.uitl.Properties
类表示了一个持久的属性集(属性列表) -
Properties
中的数据以K-V形式存储 -
Properties
可保存在流中或从流中加载
继承体系:
结论:Properties就是一个Map的实现类,维护的数据也是键值对信息。键和值都是String类型
Properties类中方法
构造方法:
Properties() //创建一个无默认值的空属性列表
常用方法: (和流无关的方法)
Object setProperty(String key, String value) //存储K-V数据 相当于Map中的put方法
String getProperty(String key) //根据给定的key,获取对应的Value元素 相当于Map中get方法
Set<String> stringPropertyNames() //获取所有Key元素的集合 //相当于Map中keySet方法
案例代码
public class PropertiesDemo1 {
//案例:使用Properties类存储的数据并遍历
public static void main(String[] args) {
//创建Properties对象
Properties pro = new Properties();
//添加KV元素
pro.setProperty("name","com.Student");
pro.setProperty("method","study");
pro.setProperty("paramter","java.lang.String");
//获取所有的Key元素
Set<String> set = pro.stringPropertyNames();
//遍历Set集合
for(String key : set){
//通过key元素,获取Value元素
String value = pro.getProperty(key);
System.out.println(key+"="+value);
}
//set.stream().forEach((String s) -> System.out.println(s));
}
}
Properties的流方法
Properties类可以去借助输入流或输出流去保存(写)或者加载(读)属性集文件信息
属性集文件,就是由键值对格式形成的文件。 如:mysql.properties
username=root
password=1234
和流有关的方法:
void load(InputStream inStream)
//从输入流中读取属性列表(键值对)
void load(Reader reader)
//按简单的面向行的格式从字符输入流中读取属性列表(键值对)
//扩展方法:
void store(OutputStream out, String comments)
//将Properties中的属性列表(键值对)写入输出流
void store(Writer writer, String comments)
//将Properties中的属性列表(键值对)写入输出流
//说明:
out/writer: 输出流,关联保存数据的文件
comments: 注释
案例代码
需求:加载属性集文件
public class PropertiesDemo2 {
public static void main(String[] args) {
try {
method();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void method() throws IOException {
//创建Properties对象
Properties pro = new Properties();
//使用load方法,加载pro.properties文件
//相对路径:相对当前项目工程
pro.load(new FileInputStream("javase_day12/src/pro.properties"));
//从Properties对象中获取属性
String location = pro.getProperty("location");
String fileName = pro.getProperty("filename");
String length = pro.getProperty("length");
System.out.println(location);
System.out.println(fileName);
System.out.println(length);
}
}
tip:文本中的数据,必须是键值对形式,可以使用空格、等号、冒号等符号分隔。
四、 ResourceBundle工具类
Properties工具类,它能够读取资源文件,当资源文件是以.properties结尾的文件时,
我们可以使用JDK提供的另外一个工具类ResourceBundle来对文件进行读取,使得操作更加简单。
java.util.ResourceBundle它是一个抽象类,我们可以使用它的子类PropertyResourceBundle来读取以.properties结尾的配置文件。
-
获取ResourceBundle对象
ResourceBundle bundle = ResourceBundle.getBundle("属性文件名称")//名称不能包含后缀名 //属性集文件必须存放在src目录下
-
使用ResourceBundle对象中的getString()方法,获取属性的值(key对应的value)
String value = bundle.getString("属性名");
//第一种方式:多态
//ResourceBundle rb = new PropertyResourceBundle();
static ResourceBundle getBundle(String baseName) //根据名字直接获取属性资源
//参数说明:baseName
//1. 属性集名称不含扩展名 //例:mysql.properties文件 baseName取:mysql
//2. 属性集文件是在src目录中的
//示例:src中存在一个文件 mysql.properties
ResourceBundle bundle = ResourceBundle.getBundle("mysql");
常用方法:
String getString(String key) //通过键,获取对应的值