6、Stream流
6.1 Stream流的概述
对于ArrayList来说有时候的需求直接使用list的API会很麻烦,而Stream流可以简化其需求
1、数组获取流的方式
int[] arr = {1,2,3}
Stream<Integer> stream1 = Stream.of(1,2,3);
Stream stream3 = (Stream) Arrays.stream(arr);
2、ArrayList集合获取流的方式
ArrayList<String> one = new ArrayList<>();
Stream<String> stream = one.stream();
3、HashMap获取流的方式
// 获取key流
Stream<String> stream3 = map.keySet().stream();
// 获取value流
Stream<String> stream4 = map.values().stream();
// 获取键值对的Stream流
Stream<Map.Entry<String, String>> stream5 = map.entrySet().stream();
6.2 Stream流的常用API
其支持链式编程
流的终结方法(使用该方法之后就不能链式编程了):
forEach
:逐一遍历count
:统计个数
非终结方法:
filter
:过滤元素limit
: 取前几个元素skip
:跳过前几个元素map
: 加工元素concat
:合并流
6.3 Stream流的收集
1、将Stream流收集成Set集合
ArrayList<String> list = new ArrayList();
list.add("a");
// 获取list流
Stream<String> listStream = list.stream();
// 收集流:将list流转成Set集合
Set<String> collect = listStream.collect(Collectors.toSet());
2、 将Stream流转为List集合
List<String> collect1 = listStream.collect(Collectors.toList());
3、将stream转为数组
// 这里的数组类型必须用Object
Object[] objects = listStream.toArray()
// 若是想将listStream转换成对于数组类型的流,则需要用“构造器引用申明”转换数组类型
String[] strings = stream.toArray(String[]::new);
6.4 File
6.4.1 创建文件夹对象
// 使用File构造器传入文件的相对路径,或绝对路径
File file = new File(String AbsolutePathName)
File file = new File(String PathName)
6.4.2 File文件常用的API
1、public String getName
: 获取目录或文件名称
2、public String getPath
: 获取文件或目录的相对路径
3、public String getAbsolute
: 获取文件或目录的绝对路径
4、public boolean exists
:判断目标文件或目录是否存在
5、public boolean isDirectory
判断目标文件是否是目录
6、public long length
返回文件的长度
7、public String[] list
返回该目录下的所有文件名称组成字符串数组
8、public File[] listFiles
返回一个抽象路径名称的数组
9、public boolean mkdir
在此路径一级目录下创建文件
10、public boolean mkdirs
可以创建一级或多级目录文件
11、public boolean renameTo(File dest)
重命名文件夹 dest - 指定文件的新抽象路径名
6.4.3 关于字符
1 个字节 = 8 位(8个开关)
1、ASCII编码:英文数字都采用1个字节表示 (美国)
2、GBK编码:汉字采用2个字节表示 (中国)
3、Unicode编码(UTF-8):统一采用3个字节表示 美国统一编码(万国码)
6.4.4 FileInputStream(字节流)
1、获取文件输入流
FileInputStream fileInputStream = new FileInputStream(file);
2、读取文件内容
2.1 单个字符分别读取
// read() 默认读取1个字节 若流读取完,在读取则返回-1
int code1 = fileInputStream.read();
System.out.println((char) code1);
2.2 使用while循环读取字符
FileInputStream fileInputStream = new FileInputStream("src\\javaSE\\高级教程\\_11Stream流\\_03文件Stream流\\test.txt");
int read = fileInputStream.read();
int len;
while((len = fileInputStream.read()) != -1){
System.out.print((char) len);
}
6.4.5 FileOutputStream(字节流)
1、向文件中写入文本的方法
-
write(int b)
-
write(byte[] b)
-
write(byte[] b, int off, int len)
off:写入字节的初始位置 len:写入字节的长度
final FileOutputStream os = new FileOutputStream("src\\javaSE\\高级教程\\_11Stream流\\_03文件Stream流\\test.txt");
os.write(111);
os.write("河畔景苑".getBytes());
os.write("大风车哈哈哈".getBytes(),0,9);
os.flush();
os.close();
// test.txt :
// o河畔景苑大风车
6.4.6 FileReader(字符流)
1、一个字符一个字符读取
File file = new File("src\\javaSE\\高级教程\\_11Stream流\\FileStream\\test.txt");
FileReader fr = new FileReader(file);
int read = fr.read();
System.out.println((char) read);
// 循环读取
int ch;
while((ch = fr.read()) != -1){
System.out.print((char) ch);
}
2、使用字符串数组,实现多个字符读取
File file = new File("src\\javaSE\\高级教程\\_11Stream流\\FileStream\\test.txt");
FileReader fr = new FileReader(file);
char[] chBuffer = new char[3];
int len;
while((len = fr.read(chBuffer)) != -1){
System.out.println("读取:"+len);
String s = new String(chBuffer, 0, len);
System.out.println(s);
}
6.4.6 FileWriter(字符流)
1、向指定文件中写入文本
File file = new File("src\\javaSE\\高级教程\\_11Stream流\\FileStream\\test.txt");
FileWriter fw = new FileWriter(file);
// 1、写一个字符出去
fw.write(123);
fw.write("我");
fw.write("\r\n"); // 换行 这样子写,对不同操作系统的兼容性好
// 2、写入字符串
fw.write("使用");
// 3、写一个字符数组出去
fw.write("字符数组".toCharArray());
// 4、写字符串的一部分出去
fw.write("我爱中国", 2,2);
// 5、写字符数组的一部分出去
fw.write("我爱中国".toCharArray(), 0,2);
fw.flush();
fw.close();
6.5 Buffer缓冲流
1、Buffer缓冲流的读写性能要好于 FileInputStream、FileOutputStream、FileReader、FileWriter
原因就是在缓冲流会有一个8kb的缓冲区,而这个缓冲区实在内存里面的,所以这样读取就比直接读写硬盘要快,性能就要好很多
2、Buffer缓冲流的使用与 FileInputStream、FileOutputStream、FileReader、FileWriter
的使用几乎差不多,区别就是Buffer缓冲流需要将FileInputStream、FileOutputStream、FileReader、FileWriter
普通流包装成Buffer缓冲流
6.5.1 BufferedInputStream(字节缓冲流)
// 1、创建文件输入流
FileInputStream is = new FileInputStream("src\\javaSE\\高级教程\\_11Stream流\\FileStream\\test.txt");
// 2、将文件输入流包装成缓冲输入流提高输入性能
BufferedInputStream bis = new BufferedInputStream(is);
int len;
byte[] buffer = new byte[is.available()];
while((len = bis.read(buffer)) != -1){
String s = new String(buffer, 0, len);
System.out.print(s);
}
}
6.5.2 BufferedOutputStream(字节缓冲流)
// 创建一个文件输出流
FileOutputStream os = new FileOutputStream("src\\javaSE\\高级教程\\_11Stream流\\FileStream\\test.txt");
// 使用缓存输出流包装文件输出流
BufferedOutputStream bos = new BufferedOutputStream(os);
// 输出一个整型
bos.write(100);
bos.write("我爱我国".getBytes());
bos.flush();
bos.close();
}
6.5.3 BufferedReader(字符缓冲流)
相对于Reader新增的API
1、public String readLine()
:读取一行数据返回,读取完毕返回null
try(
FileReader fr = new FileReader("src\\javaSE\\高级教程\\_11Stream流\\FileStream\\test.txt");
BufferedReader bfr = new BufferedReader(fr)
){
int len;
char[] buffer = new char[3];
// 普通读取
while((len = bfr.read(buffer)) != -1){
String s = new String(buffer, 0 ,len);
System.out.print(s);
}
// 一行一行读取
String line;
while((line = bfr.readLine()) != null){
System.out.println(line);
}
System.out.println("\n读取完毕!");
} catch (Exception e) {
e.printStackTrace();
}
}
6.5.4 BufferedWriter(字符缓冲流)
try(
final FileWriter fw = new FileWriter("src\\javaSE\\高级教程\\_11Stream流\\FileStream\\test.txt");
final BufferedWriter bfw = new BufferedWriter(fw)
){
bfw.write(1000);
bfw.write("中国".toCharArray());
}catch(Exception e){
e.printStackTrace();
}
}
6.5.5 普通流与Buffer缓冲流性能测试
public class BufferPerformanceTest {
public static void main(String[] args) {
// fileOneCharCopy();
fileCharArrayCopy();
bufferOneCharCopy();
bufferCharArrayCopy();
}
final static String OLD_FILE_PATH = "D:\\杂七杂八的文件\\淘宝旺旺\\Download\\专升本高数视频\\【2022】【专升本高等数学】【基础全程班】【专升本高数】 - 28.28、第一章 利用极限求曲线渐近线、(第一章完犊子了)(Av969422474,P28).mp4";
final static String NEW_FILE_PATH = "D:\\杂七杂八的文件\\淘宝旺旺\\Download\\Test\\";
/**
* 一个字节一个字节复制
*/
public static void fileOneCharCopy(){
long startTime = System.currentTimeMillis();
try(
final FileInputStream is = new FileInputStream(OLD_FILE_PATH);
final FileOutputStream os = new FileOutputStream(NEW_FILE_PATH+"1.mp4")
) {
int ch;
while((ch = is.read()) != -1){
try{
os.write(ch);
}catch (Exception e){
e.printStackTrace();
}
}
}catch (Exception e){
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("一个一个字节复制消耗时间:"+(endTime-startTime)/1000.0);
}
/**
* 使用字节数组传输
*/
public static void fileCharArrayCopy(){
long startTime = System.currentTimeMillis();
try(
final FileInputStream is = new FileInputStream(OLD_FILE_PATH);
final FileOutputStream os = new FileOutputStream(NEW_FILE_PATH+"2.mp4")
) {
System.out.println("开始复制...");
int len;
final byte[] buffer = new byte[1024];
System.out.println("buffer:"+is.available());
while((len = is.read(buffer)) != -1){
try{
// System.out.println(new String(buffer));
os.write(buffer, 0, len);
}catch (Exception e){
e.printStackTrace();
}
}
}catch (Exception e){
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("字节数组传输复制消耗时间:"+(endTime-startTime)/1000.0);
}
/**
* 使用Buffer一个一个字节传输
*/
public static void bufferOneCharCopy(){
long startTime = System.currentTimeMillis();
try(
final FileInputStream is = new FileInputStream(OLD_FILE_PATH);
final BufferedInputStream bis = new BufferedInputStream(is);
final FileOutputStream os = new FileOutputStream(NEW_FILE_PATH+"3.mp4");
final BufferedOutputStream bos = new BufferedOutputStream(os)
) {
int ch;
while((ch = bis.read()) != -1){
try{
bos.write(ch);
}catch (Exception e){
e.printStackTrace();
}
}
}catch (Exception e){
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("Buffer一个一个字节复制消耗时间:"+(endTime-startTime)/1000.0);
}
/**
* 使用Buffer字节数组传输
*/
public static void bufferCharArrayCopy(){
long startTime = System.currentTimeMillis();
try(
final FileInputStream is = new FileInputStream(OLD_FILE_PATH);
final BufferedInputStream bis = new BufferedInputStream(is);
final FileOutputStream os = new FileOutputStream(NEW_FILE_PATH+"4.mp4");
final BufferedOutputStream bos = new BufferedOutputStream(os)
) {
int len;
final byte[] buffer = new byte[1024];
while((len = bis.read(buffer)) != -1){
try{
bos.write(buffer, 0, len);
}catch (Exception e){
e.printStackTrace();
}
}
}catch (Exception e){
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("Buffer字节数组传输复制消耗时间:"+(endTime-startTime)/1000.0);
}
}
// 【结果】:
// 一个字节一个字节复制及其慢,就没跑
// 字节数组传输复制消耗时间:0.649
// Buffer一个一个字节复制消耗时间:1.812
// Buffer字节数组传输复制消耗时间:0.141 【性能挺好】
6.6 字符转换流
6.6.1 InputStreamReader
字符输入转换流,可以在读取时,按照程序员指定的编码格式进行读取文件,这样代码与文件格式不一致时就不会出现乱码的问题了
具体代码如下:
final File file = new File("src\\javaSE\\高级教程\\_11Stream流\\_03文件Stream流\\test.txt");
final FileInputStream is = new FileInputStream(file);
final InputStreamReader isr = new InputStreamReader(is, "GBK");
int ch;
final char[] buffer = new char[3];
while((ch = isr.read(buffer)) != -1){
System.out.print(buffer);
}
6.6.2 OutputStreamWriter
字符输出转换流,在写入时,可以按照指定的编码格式将字符写入文件
具体代码如下:
final FileOutputStream os = new FileOutputStream("src\\javaSE\\高级教程\\_11Stream流\\_03文件Stream流\\test.txt");
final OutputStreamWriter osw = new OutputStreamWriter(os, "GBK");
osw.write("字符输出转换流");
osw.close();
6.7 打印流
打印流可以方便且高效的打印各种数据。
6.7.1 PrintStream
打印流可以支持打印所有基本类型数据
final PrintStream ps = new PrintStream("src\\javaSE\\高级教程\\_11Stream流\\_03文件Stream流\\打印流\\print.txt");
ps.println(11);
ps.println(110);
ps.println("aa我爱中国");
ps.println(33.3);
ps.println(false);
ps.println('徐');
ps.println("aa".getBytes());
ps.close();
6.7.2 打印流重定向
我们通常在写程序的时候,有控制台,日志都是可以在控制台看见的,但是在服务器上是没有控制台的,所以我们在输出日志之前,将打印流重定向,就可以将打印的内容,记录在指定的文件内
final PrintStream ps = new PrintStream("src\\javaSE\\高级教程\\_11Stream流\\_03文件Stream流\\打印流\\print.txt");
System.out.println("=====Demo01=====");
System.out.println("=====Demo02=====");
// 打印流重定向 PrintStreamRedirection
System.setOut(ps);
System.out.println("=====Demo03=====");
System.out.println("=====Demo04=====");
System.out.println("=====Demo05=====");
System.out.println("=====Demo06=====");
System.out.println("=====Demo07=====");
6.8 序列化
6.8.1 对象序列化
对象序列化,该对象必须实现Serializable接口才能被序列化进文件,否则会报NotSerializableException异常
package javaSE.高级教程._11Stream流._03文件Stream流.对象序列化;
import java.io.Serializable;
public class Student implement Serializable {
private String name;
private String age;
private String sex;
// 省略有参无参构造器、getter喝setter
// ...
}
// 准备序列化的对象
final Student student = new Student("李文杰", "22", "男");
// 建立文件输出流
final FileOutputStream os = new FileOutputStream("src\\javaSE\\高级教程\\_11Stream流\\_03文件Stream流\\对象序列化\\serialize.dat");
// 建立对象序列化输出流
final ObjectOutputStream oos = new ObjectOutputStream(os);
// 写入
oos.writeObject(student);
oos.close();
System.out.println("对象序列化成功!");
1、加入序列化版本号,来控制不同的序列化方式。但是在反序列化时,对象的序列号版本与序列化时的版本一致。否则会报错InvalidClassException异常错误
public class Student implement Serializable {
// 加入序列化版本号
private static final long serialVersionUID = 1L;
private String name;
private String age;
private String sex;
// 省略有参无参构造器、getter喝setter
// ...
}
2、如果不想将某个属性序列化,则可以使用transient
修饰该私有变量
private transient String age;
6.8.2 对象反序列化
将对象的序列化文件读出来,此时对象内的序列化版本号必须与之前序列化的版本号一致。
/**
* 对象反序列化
*/
final FileInputStream is = new FileInputStream("src\\javaSE\\高级教程\\_11Stream流\\_03文件Stream流\\对象序列化\\serialize.dat");
final ObjectInputStream ois = new ObjectInputStream(is);
// 默认使用Object类型,可以强转成Student类型
final Student student = (Student) ois.readObject();
System.out.println(student);
System.out.println("反序列化成功!");
6.9 properties属性集文件
6.9.1 将属性写入属性集文件
public static void main(String[] args) throws Exception {
// 1、创建一个属性集对象,Properties对象
final Properties properties = new Properties();
properties.setProperty("username", "lina");
// 2、创建一个字节输出流
final FileOutputStream os = new FileOutputStream("src\\javaSE\\高级教程\\_11Stream流\\_03文件Stream流\\properties属性文件\\user.properties");
// 3、保存properties属性集文件 参数一: 字节输出流对象,参数二:说明
properties.store(os, "保存properties属性");
// properties会自动关闭字节输出流
}
6.9.2 读取properties属性文件
public static void main(String[] args) throws Exception{
// 1、创建一个属性集对象
final Properties properties = new Properties();
// 2、创建一个字节输出流 加载-> user.properties属性文件的数据 到-> 属性集对象properties中去
properties.load(new FileInputStream("src\\javaSE\\高级教程\\_11Stream流\\_03文件Stream流\\properties属性文件\\user.properties"));
System.out.println(properties.getProperty("username"));