Java高级03-API

目录

一、Stream流

1.stream流思想

2.Stream的三类方法

(1)获取方法

使用场景

(2)中间方法

常见中间方法

(3)终结/结束方法

(4)收集方法

(5)综合练习

二、File

1.File类概述

2.主要方法

(1)构造方法

(2)绝对路径和相对路径

①绝对路径

②相对路径

(3)成员方法

(4)练习

三、IO(读/写)

1.IO概述

2.IO分类

3.字节流

(1)写:

(2)写:多种参数

(3)换行

(4)追加写

(5)读:

(6)读:完整读完一个文件

(7)文件复制

4.字节缓冲流

5.字符流

(1)字符流的必要性

(2)基础知识

(3)字符串的编码解码

(4)乱码原因

(5)字符流组成

(6)字符流写数据

(7)字符流读数据

6.字符缓冲流

(1)字符缓冲流特有功能

7.字节流和字符流的使用场景

8.练习

(1)将用户录入的账号和密码保存到本地,实现永久化存储

(2)读取文件的数据,并将其排序后再次写入到本地

9.转换流

(1)使用场景

10.对象操作流

(1)作用

(2)序列化(对象操作输出流)

(3)反序列化(对象操作输入流)

(4)对象操作流注意点

①serialversionUID :序列号

(5)练习

11.Properties(集合体系的,有IO相关的方法)

(1)概述

(2)主要方法

12.自动关闭流


一、Stream流

1.stream流思想

就跟工厂流水线一样

代码对比:

package stream;
​
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
​
public class StreamDemo01 {
    public static void main(String[] args) {
        //创建一个集合
        //随便加点元素
        //把集合中以?(自己定)开头的元素存储到list2集合中
        //再把list2中长度为3的元素保存到list3中
        //最后遍历list3
        ArrayList<String> list1 = new ArrayList<>();
​
        /*
        List.of:JDK9才有,前面写过,后面就不说了
        ArrayList<String> list1 = new ArrayList<>(List.of("张三","张三","张三","张三","张三"));
         */
​
​
        list1.add("张三");
        list1.add("李四");
        list1.add("王五");
        list1.add("张萨达");
        list1.add("赵六");
        list1.add("张飞");
        list1.add("张安风");
        list1.add("张德龙");
​
        ArrayList<String> list2 = new ArrayList<>();
        //把集合中所有以“张”开头的元素存储到一个集合
​
        for (String s : list1) {
            if (s.startsWith("张")){
                list2.add(s);
            }
        }
        ArrayList<String> list3 = new ArrayList<>();
        for (String s : list2) {
            if (s.length() == 3){
                list3.add(s);
            }
        }
​
        for (String s : list3) {
            System.out.println(s);
        }
​
        System.out.println("------------------------------------------------");
        //stream流
        list1.stream().filter(s -> s.startsWith("张"))
                      .filter(s -> s.length() == 3)
                      .forEach(System.out::println);
    }
}

lambda表达式:

//正常写法
Stream.of(1,2,3,4,5,6).filter(
        new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                if (integer == 3){
                    return false;
                }
                return true;
            }
        }
);

简化:

//因为Predicate接口只有一个抽象方法
        //lambda简化
        //格式  () -> {}
        Stream.of(1,2,3,4,5,6).filter((Integer n)
                -> {
            if (n == 3){
                return false;
            }
            return true;
        }).forEach(n -> System.out.println(n));

如果形参只有一个,数据类型可以省略,小括号可以省略

如果方法体只有一行,return可以省略,大括号可以省略,分号可以省略

Stream.of(1,2,3,4,5,6).filter(n -> n!=3).forEach(n -> System.out.println(n));

2.Stream的三类方法

(1)获取方法

创建流水线,将准备好的数据放入流水线中

使用场景
  • 单/双列集合

单列:Collection接口中的默认方法stream

        ArrayList<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.stream().forEach(s -> System.out.println(s));

双列:间接获取,通过keySet或者entrySet获取一个Set集合,再获取Stream流

HashMap<Integer,String> map = new HashMap<>();
map.put(1,"aaa");
map.put(2,"bbb");
map.put(3,"ccc");
​
final Set<Map.Entry<Integer, String>> entries = map.entrySet();
entries.stream().forEach(s -> System.out.println(s));
​
final Set<Integer> integers = map.keySet();
integers.stream().forEach(s -> System.out.println(s+":"+map.get(s)));
  • 数组

Arrays中的静态方法stream

int[] arr = {1,2,3,4,5};
Arrays.stream(arr).forEach(n -> System.out.println(n));
  • 多个同数据类型

Stream.of(V)方法

Stream.of(1, 2, 3, 4, 5, 6).forEach(n -> System.out.println(n));

(2)中间方法

流水线操作(可多个操作,A结束B开始)

常见中间方法
方法名返回值类型说明
filter((流中数据)-> {筛选条件})一个新的Stream实例流中数据过滤 Predicate接口中的方法boolean test()方法 Predicate的test方法返回true,则该元素会被保留在新的Stream中;如果返回false,则该元素会被舍弃。
limit(long maxSize)截取指定参数个数的数据
skip(long n)跳过指定参数个数的数据
concat(Stream A,Stream B)合并流(A和B)
distinct()去重 依赖hashCode和equals

(3)终结/结束方法

只有一个,最后一个操作

方法名返回值类型说明
forEachvoid对此流的每个数据进行操作 Consumer接口中的方法 void accept();对给定的元素进行操作
countlong返回此流中的元素个数

注意:Stream流中无法直接修改集合,数组等数据源中的数据

(4)收集方法
方法名返回值类型说明
collect(Collector c)收集方法(不创建容器和添加数据,只收集)

具体收集方法:Collectors的

静态方法名返回值类型说明
toList把元素放到List集合中
toSet把元素放到Set集合中
toMap(K,V)把元素放到Map集合中

(5)综合练习

定义一个集合

添加1,2,3,4,5

再定义一个集合

添加6,7,8,9,10

将俩集合合并,删除其中的奇数并输出

package stream;
​
import java.util.ArrayList;
import java.util.stream.Stream;
​
public class StreamDemo03 {
    public static void main(String[] args) {
        ArrayList<Integer> list1 = new ArrayList();
        ArrayList<Integer> list2 = new ArrayList();
        ArrayList<Integer> list3 = new ArrayList<>();
​
        for (int i = 1; i <= 5; i++) {
            list1.add(i);
            list2.add(i+5);
        }
        System.out.println(list1);
        System.out.println(list2);
        //------------------------------------------------
        Stream.concat(list1.stream(),list2.stream())
                .filter(n -> n%2==0)
                .forEach(n -> {
                    list3.add(n);
                });
​
        System.out.println(list3);
        list3.forEach(n -> System.out.println(n));
        //--------------------------------------------------
        List<Integer> list = Stream.concat(list1.stream(), list2.stream())
                .filter(n -> n % 2 == 0)
                .collect(Collectors.toList());
        System.out.println(list);
    }
}

二、File

1.File类概述

它是文件或目录路径名的抽象表示

  • 文件和目录可以通过File封装成对象

  • File封装的对象仅仅是一个路径名,它可以是存在的,亦可是不存在的

2.主要方法

(1)构造方法
方法名返回值类型说明
File(String pathname)通过给定的路径名字符串转换为抽象路径名来创建新的File实例
File(String parent,String child)从父路径名字符串和子路径名字符串创建新的 File实例。
File(File parent,String child)从父抽象路径名和子路径名字符串创建新的 File实例
(2)绝对路径和相对路径
①绝对路径

从盘符开始

②相对路径

相对当前项目下的路径

(3)成员方法
方法名返回值类型说明
createdNewFile()boolean创建一个新的空文件,文件所在的文件夹必须存在
mkdir()boolean创建一个单级文件夹
mkdirs()boolean创建一个多级文件夹,亦可单级
delete()boolean删除的文件/文件夹(空)不会在回收站
isDirectory()boolean判断是否为目录
isFile()boolean判断是否为文件
exists()boolean判断是否存在
getName()String获取文件或文件夹(目录)的名称
listFile()File[]返回此抽象路径名表示的目录中的文件和文件夹(目录)的File对象数组,包括隐藏文件和文件夹 调用者有四种情况: 1.文件:返回null 2.空文件夹:返回0 3.文件夹:返回File[] 4.权限文件夹:返回null
getName()String返回由此抽象路径名表示的文件或目录的名称。
getPath()String将此抽象路径名转换为路径名字符串。
(4)练习

1.在当前项目目录下创建名为aaa的文件夹,并在其中创建a.txt文件

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File file = new File("stream\\aaa");
        if (!file.exists()){
            file.mkdirs();
        }
        File file1 = new File(file,"a.txt");
        file1.createNewFile();
    }

2.删除多级文件夹,一个文件夹和其所有子文件夹和文件

package file;
​
import java.io.File;
import java.io.IOException;
​
public class FileDemo02 {
    public static void main(String[] args) throws IOException {
        File file = new File("stream\\aaa");
        if (!file.exists()){
            file.mkdirs();
        }
        File file1 = new File(file,"aaa.txt");
        File file2 = new File(file,"bbb.txt");
        File file3 = new File(file,"ccc.txt");
        File file4 = new File("stream\\aaa\\bbb");
        File file5 = new File("stream\\aaa\\bbb\\ccc");
​
        file1.createNewFile();
        file2.createNewFile();
        file3.createNewFile();
        file4.mkdir();
        file5.mkdir();
​
        System.out.println(file);
        deleteAll(file);
    }
​
    private static void deleteAll(File file){
        if (file.isFile()){
            file.delete();
            deleteAll(file);
        }else if (file.isDirectory()){
            File[] files = file.listFiles();
            for (File file1 : files) {
                if (file1.isFile()){
                    file1.delete();
                }else {
                    deleteAll(file1);
                }
            }
        }
        file.delete();
​
​
​
    }
}

3.统计该文件夹下各种文件类型的个数

File file6 = new File("???");
countAll(file6,map);
System.out.println(map);
private static void countAll(File file,HashMap<String,Integer> map){
​
        File[] files = file.listFiles();
        if (files == null){
            return;
        }
        for (File file1 : files) {
            if (file1.isFile()){
//                System.out.println(file1.getName());
                String[] strings = file1.getName().split("\\.");
//                System.out.println(strings.length);
​
                String nameSuffix = strings[strings.length-1];
                if (map.containsKey(nameSuffix)){
                    Integer count = map.get(nameSuffix);
                    count++;
                    map.put(nameSuffix,count);
                }else{
                    map.put(nameSuffix,1);
                }
​
            }else {
                countAll(file1,map);
            }
        }
​
    }

三、IO(读/写)

1.IO概述

I:input,读,数据从硬盘到内存

O:output,写,数据从内存到硬盘

以内存为参照物,内存读,内存写

2.IO分类

按流向分:

按数据类型分:

纯文本文件:能用window记事本打开且能看得懂的

3.字节流

FileOutputStream类

方法名返回值类型说明
write(int b)void一次写一个字节数据
write(byte[] b)void一次写一个字节数组的数据
write(byte[] b,int off(索引),int len(个数))void一次写一个字节数组(部分)的数据

FileInputStream类

方法名返回值类型说明
read()int一次读取一个字节数据
read(byte[] b)int一次读取一个字节数组长度的数据
read(byte[] b,int off(索引),int len(个数))int一次读取一个字节数组长度(部分)的数据

(1)写:
public class OutputDemo {
    public static void main(String[] args) throws IOException {
        File file = new File("stream\\src\\io\\a.txt");
        //创建字节输出流对象-----------告诉虚拟机要往哪个文件写数据
        //如果文件不存在,会创建
        //如果文件存在,会清空文件内容
        FileOutputStream fileOutputStream1 = new FileOutputStream(file);
        FileOutputStream fileOutputStream2 = new FileOutputStream("stream\\src\\io\\b.txt");
        //写数据
        fileOutputStream1.write(97);
        //释放资源
        fileOutputStream1.close();
​
    }
}
(2)写:多种参数
package io;
​
import java.io.*;
​
/**
 * @author LEGION
 */
public class OutputDemo {
    public static void main(String[] args) throws IOException {
        File file = new File("stream\\src\\io\\a.txt");
        //创建字节输出流对象-----------告诉虚拟机要往哪个文件写数据
        FileOutputStream fileOutputStream1 = new FileOutputStream(file);
        FileOutputStream fileOutputStream2 = new FileOutputStream("stream\\src\\io\\b.txt");
        //写数据
        byte[] bytes = {91,92,93,94,89,96,103};
        fileOutputStream1.write(97);
        fileOutputStream1.write(bytes);
        fileOutputStream1.write(bytes,0,3);
        //释放资源
        fileOutputStream1.close();
​
    }
}
(3)换行

写完数据后,加换行符

window:\r\n

linux:\n

mac:\r

(4)追加写
//第二个参数默认为false
//如果为true不会清空文件内容
FileOutputStream fileOutputStream1 = new FileOutputStream(file,true);

(5)读:
public class InputDemo {
    public static void main(String[] args) throws IOException {
        //创建FileInputStream对象
        //文件不存在就会报错
        FileInputStream fileInputStream = new FileInputStream("stream\\src\\io\\a.txt");
        //读
        //一次读取一个字节,返回的值为码表中所对应数字,如果没有数据,则返回-1
        //如果想看字符数据,必须强转为char
        final int read = fileInputStream.read();
        //释放资源
        fileInputStream.close();
    }
}
(6)读:完整读完一个文件
public class InputDemo02 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("stream\\src\\io\\a.txt");
​
        int code;
        while ( (code=fis.read())!= -1){
            System.out.print((char) code);
        }
        fis.close();
​
    }
}
(7)文件复制

复制文件:其实就是把文件内容读取出来(数据源),然后写入到另一个文件中(目的地)

public class CopyDemo02 {
    public static void main(String[] args) throws IOException {
        
        FileInputStream fileInputStream = new FileInputStream("stream\\src\\io\\music.mp3");
        FileOutputStream fileOutputStream = new FileOutputStream("stream\\aaa\\c.mp3");
        int n;
        while ((n=fileInputStream.read())!= -1){
            fileOutputStream.write(n);
        }
        fileInputStream.close();
        fileOutputStream.close();
​
    }
}

优化版:

public class CopyDemo02 {
    public static void main(String[] args) throws IOException {
    
        FileInputStream fileInputStream = new FileInputStream("stream\\src\\io\\music.mp3");
        FileOutputStream fileOutputStream = new FileOutputStream("stream\\aaa\\c.mp3");
        byte[] bytes = new byte[1024];
        //n:读到的有效字节个数
        int n;
        while ((n=fileInputStream.read(bytes))!= -1){
            fileOutputStream.write(bytes,0,n);
        }
        fileInputStream.close();
        fileOutputStream.close();
​
    }
}

4.字节缓冲流

(仅提供缓冲区,需要接入字节流使用)

BufferedOutputStream:字节缓冲输出流

BufferedInputStream:字节缓冲输入流

缓冲流:

  • 会默认创建一个8192大小的byte[]数组

  • close后其内的字节流也会关闭

        FileInputStream fis = new FileInputStream("stream\\src\\io\\music.mp3");
        FileOutputStream fos = new FileOutputStream("stream\\src\\io\\music.mp3");
        BufferedInputStream bis = new BufferedInputStream(fis);
        BufferedOutputStream bos = new BufferedOutputStream(fos);

5.字符流

(1)字符流的必要性
  • 如果利用字节流,把文本文件中的中文,读取到内存中,有可能出现乱码。

  • 如果利用字节流,把中文写到文本文件中,也有可能出现乱码。

(2)基础知识
  • 计算机中储存的信息都是用二进制数表示的

  • 按照某种规则,将字符变成二进制,再存储到计算机中,称为编码

  • 按照同样的规则,将存储在计算机中的二进制数解析显示出来,称为解码

  • 编码和解码的方式必须一致,否则会导致乱码。

编码表:

ASCII字符集:数字,大小写字符和一些常见的标点符号

GBK:兼容ASCII,也包含了21003个汉字,支持繁体和部分日韩文字

注:GBK是中国的码表,一个中文以两个字节的形式存储。但不包含世界上所有国家的文字.

Unicode码表:由国际组织ISO制定,是统一的万国码,计算机科学领域里的一项业界标准,容纳世界上大多数国家的所有常见文字和符号。

但是因为表示的字符太多,所以Unicode码表中的数字不是直接以二进制的形式存储到计算机的。会先通过UTF-7,UTF-7.5,UTF-8,UTF-16,以及UTF-32进行编码,再存储到计算机,其中最为常见的就是UTF-8.

注意:Unicode是万国码,以UTF-8编码后一个中文以三个字节的形式存储,UTF-8是一种编码格式

(3)字符串的编码解码

都是String类中的

编码:

方法名返回值类型说明
getBytes()byte[]使用平台的默认字符集将该 String编码为一系列字节,将结果存储到新的字节数组中。
getBytes(String charsetName)byte[]使用命名的字符集将此 String编码为字节序列,将结果存储到新的字节数组中。
getBytes(Charset charset)byte[]使用给定的charset将此String编码为字节序列,将结果存储到新的字节数组中。

public class CodeDemo {
    public static void main(String[] args) throws UnsupportedEncodingException {
        String s = "编码测试";
        final byte[] bytes1 = s.getBytes();
        System.out.println(Arrays.toString(bytes1));
​
        final byte[] bytes2 = s.getBytes(StandardCharsets.UTF_8);
        System.out.println(Arrays.toString(bytes2));
​
        final byte[] bytes3 = s.getBytes("GBK");
        System.out.println(Arrays.toString(bytes3));
​
​
    }
}

解码:String类的构造

方法名返回值类型说明
String(byte[] bytes)通过使用平台的默认字符集解码指定的字节数组来构造新的 String
String(byte[] bytes, String charsetName)构造一个新的String由指定用指定的字节的数组解码charset
//UTF-8
byte[] bytes1 = {-25, -68, -106, -25, -96, -127, -26, -75, -117, -24, -81, -107};
//GBK
byte[] bytes2 = {-79, -32, -62, -21, -78, -30, -54, -44};
​
String s = new String(bytes1);
System.out.println(s);
s = new String(bytes2);
System.out.println(s);
​
s = new String(bytes2,"GBK");
System.out.println(s);

(4)乱码原因

因为字节流一次读一个字节,而不管GBK还是UTF-8一个中文都是多个字节,用字节流每次只能读其中的一部分,所以就会出现乱码问题。

(5)字符流组成

字节流 + 编码表

不管是在哪张码表中,中文的第一个字节一定是负数

(6)字符流写数据

FileWriter

构造方法返回值类型说明
FileWriter(File file)
FileWriter(String fileName)

主要方法:

方法名返回值类型说明
write(int n)void写出一个字符
write(char[] chars)void写出一个字符数组
write(char[] chars,int off,int len)void写出一个字符数组(部分)
write(String str)void写出一个字符串
write(String str,int off,int len)void写出一个字符串(部分)
flush()void刷新流,还可以继续写
close()void关闭流,释放资源,关闭之前会进行一次刷新流操作,关闭后就不能再写数据了
public class CharacterStreamDemo {
    public static void main(String[] args) throws IOException {
        //创建FileWriter对象
        //如果文件不存在,就创建。但是要保证父级路径存在
        //如果文件存在就清空
        FileWriter fileWriter = new FileWriter("stream\\src\\io\\b.txt");
        //写出数据
        //如果写出的是int类型的整数,实际写出的是该整数在码表上对应的字母
        //如果写出字符串数据,是把字符串本身原样写出。
        fileWriter.write("你好世界");
        //释放资源
        fileWriter.close();
    }
}

(7)字符流读数据

FileReader

构造方法返回值类型说明
FileReader(File file)
FileReader(String fileName)
FileReader fileReader = new FileReader("stream\\src\\io\\b.txt");
 //一次一个字符
int b;
while ((b = fileReader.read()) != -1){
    System.out.println((char) b);
}
fileReader.close();
FileReader fileReader = new FileReader("stream\\src\\io\\b.txt");
//创建数组
char[] chars = new char[1024];
int len;
while ((len = fileReader.read(chars)) != -1){
    System.out.println(new String(chars,0,len));
}
fileReader.close();

6.字符缓冲流

BufferedWriter(Writer out):高效写

public class BufferedWriterDemo {
    public static void main(String[] args) throws IOException {
        FileWriter fileWriter = new FileWriter("stream\\test.txt");
        BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
​
        char[] chars = {91,92,93,94,95};
        bufferedWriter.write(96);
        bufferedWriter.write(chars);
        bufferedWriter.write("测试");
        
        bufferedWriter.close();
    }
}

BufferedReader(Reader in):高效读,也有叫块读

public class BufferedReaderDemo {
    public static void main(String[] args) throws IOException {
        FileReader fileReader = new FileReader("stream\\aaa\\users\\user01.txt");
        BufferedReader bufferedReader = new BufferedReader(fileReader);
        char[] chars = new char[1024];
        int len;
        while ( (len = bufferedReader.read(chars)) != -1){
            System.out.println(new String(chars,0,len));
        }
        bufferedReader.close();
​
​
    }
}
(1)字符缓冲流特有功能

BufferedWriter

方法名返回值类型说明
newLine()void写一行行分隔符,其分隔符由系统定义

bw.write(97);

bw.newLine();

BufferedReader

方法名返回值类型说明
readLine()String读一行,没有内容会返回null
//读到回车换行符为止,但不会读到回车换行符
String s;
while ( (s = bufferedReader.readLine()) != null){
    System.out.println(s);
}

7.字节流和字符流的使用场景

  • 想要进行拷贝,一律使用字节流或者字节缓冲流

  • 想要把文本文件中的数据读到内存中,请使用字符输入流想要把内存中的数据写到文本文件中,请使用字符输出流

  • GBK码表(windows默认)一个中文两个字节,UTF-8编码格式一个中文3个字节

8.练习

代码仅供参考

(1)将用户录入的账号和密码保存到本地,实现永久化存储

要求:用户名独占一行,密码独占一行

public class Exercise {
    public static void main(String[] args) throws IOException {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入账号");
        String userName = scanner.nextLine();
        System.out.println("请输入密码");
        String passWord = scanner.nextLine();
​
​
​
        File file1 = new File("stream\\aaa\\users");
        if (!file1.exists()){
            file1.mkdirs();
            
        }
        File file2 = new File(file1,"user01.txt");
        System.out.println(file2.createNewFile()?"创建文件成功":"创建文件失败");
​
        FileWriter fileWriter = new FileWriter(file2,true);
        fileWriter.write(userName+"\r\n");
        fileWriter.write(passWord+"\r\n");
        fileWriter.close();
​
    }
}

(2)读取文件的数据,并将其排序后再次写入到本地
package io;
​
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
​
​
public class Exercise02 {
    public static void main(String[] args) throws IOException {
        //文件创建
        File file = fileCreate();
        //数据准备
        ArrayList<Integer> arrayList = new ArrayList<>(Arrays.asList(5, 8, 7, 9, 53, 21, 5, 4, 1553, 45, 231));
        //写入数据
        fileWrite(file,arrayList);
        //读数据+排序
        arrayList = fileRead(file);
        //再次写入
        fileWrite(file,arrayList);
​
    }
​
    /**
     * 文件读取+排序
     * @param file 要读取的文件对象
     * @return  排完序的ArrayList
     * @throws IOException IO异常
     */
    private static ArrayList<Integer> fileRead(File file) throws IOException {
        ArrayList<Integer> list = new ArrayList<>();
        FileReader fileReader = new FileReader(file);
        BufferedReader bufferedReader = new BufferedReader(fileReader);
        String s;
        String[] strings;
        while ( (s = bufferedReader.readLine()) != null ){
            for (String s1 : strings = s.split(" ")) {
                list.add(Integer.valueOf(s1));
            }
        }
​
        bufferedReader.close();
        list.sort(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        });
​
        System.out.println(list);
        return list;
    }
​
    /**
     * 将数据写入到文件中
     * @param file 要写入的文件对象
     * @param nums 数据
     * @throws IOException IO异常
     */
    private static void fileWrite(File file,ArrayList<Integer> nums) throws IOException {
​
​
        FileWriter fileWriter = new FileWriter(file);
        BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
​
        //写入数据
        for (int num : nums) {
            bufferedWriter.write(String.valueOf(num));
            bufferedWriter.write(" ");
        }
        bufferedWriter.close();
    }
​
    /**
     * 文件创建
     * @return File对象
     * @throws IOException IO异常
     */
    private static File fileCreate() throws IOException {
        File mkDir = new File("stream\\src\\io\\Exercise");
        if (!mkDir.exists()){
            System.out.println(mkDir.mkdirs()?"创建文件夹成功":"创建文件夹失败");
        }
​
        File mkFile = new File(mkDir,"content.txt");
        if (!mkFile.exists()){
            System.out.println(mkFile.createNewFile()?"创建文件成功":"创建文件失败");
        }
        return mkFile;
    }
}

9.转换流

(1)使用场景

在JDK11之前,指定编码读/写

如:GBK编码的文件直接用字符流读取的话可能会乱码,因为IDEA默认编码是UTF-8的编码格式,JDK11以前,字符流是无法指定编码格式的

使用方式可自行查阅JDK帮助文档

 InputStreamReader inputStreamReader = new InputStreamReader(
            new FileInputStream("src/io/Exercise/content.txt"),"GBK");
}

在JDK11之后,字符流新出一个构造,可以指定编码读/写

FileReader fileReader = new FileReader("stream\\aaa\\users\\user01.txt", Charset.forName("GBK"));

10.对象操作流

(1)作用

可以把对象以字节的形式写到本地文件,直接打开文件,是读不懂的,需要再次用对象操作流读到内存中。(数据安全)

(2)序列化(对象操作输出流)

就是将对象写到本地文件中,或者在网络中传输对象

public class SerializableDemo {
    public static void main(String[] args) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.txt"));
        oos.writeObject(对象【对象需要实现Serializable接口】);
        oos.close();
    }
}

serializable 接口的意义:

称之为是一个标记性接口,里面没有任何的抽象方法

只要一个类实现了这个serializable接口,那么就表示这个类的对象可以被序列化

(3)反序列化(对象操作输入流)

把写到本地文件中的对象读到内存中,或者接收网络中传输的对象

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.txt"));
【要转的对象类型】 object = (要转的对象类型) ois.readObject();
ois.close();

(4)对象操作流注意点
①serialversionUID :序列号

如果我们自己没有定义,那么虚拟机会根据类中的信息会自动的计算出一个序列号

问题1:如果我们修改了类中的信息.那么虚拟机会再次计算出一个,进而导致再次读取该本地文件时报错

解决:自己创建一个serialversionUID,不用虚拟机生成即可,以后只要不修改序列号即可避免此问题

private static final long SERIAL_VERSION_UID = 123456;

问题2:如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?

解决:使用transient关键字即可,该关键字标记的成员变量不参与序列化过程

private  transient Integer age;

(5)练习

User对象:

package io.serializ;
​
import java.io.Serializable;
import java.math.BigDecimal;
​
public class User implements Serializable {
    private static final long SERIAL_VERSION_UID = 123456;
    private String name;
    private  transient Integer age;
    private BigDecimal money;
​
    public User() {
    }
​
    public User(String name, Integer age, BigDecimal money) {
        this.name = name;
        this.age = age;
        this.money = money;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public Integer getAge() {
        return age;
    }
​
    public void setAge(Integer age) {
        this.age = age;
    }
​
    public BigDecimal getMoney() {
        return money;
    }
​
    public void setMoney(BigDecimal money) {
        this.money = money;
    }
​
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                ", money=" + money +
                '}';
    }
}
package io.serializ;
​
import java.io.*;
import java.math.BigDecimal;
import java.util.ArrayList;
​
import java.util.Collections;
​
public class SerializableDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
​
        ArrayList<User> users = new ArrayList<>();
        User user1 = new User("张三",45,new BigDecimal("123456"));
        User user2 = new User("张四",35,new BigDecimal("1234.56"));
        User user3 = new User("张五",25,new BigDecimal("123.456"));
​
        Collections.addAll(users,user1,user2,user3);
​
​
        //序列化:将对象写出到本地
        method01(users);
        //反序列化:
        method02();
​
​
​
​
    }
​
    private static void method02() throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.txt"));
​
        ArrayList<User> users = (ArrayList<User>) ois.readObject();
        for (User user : users) {
            System.out.println(user);
        }
    }
​
    private static void method01(ArrayList<User> users) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.txt"));
        oos.writeObject(users);
        oos.close();
    }
}

11.Properties(集合体系的,有IO相关的方法)

(1)概述

就是一个map集合,但是没有泛型,一般只存字符串

public class PropertiesDemo {
    public static void main(String[] args) {
        Properties properties = new Properties();
        //增
        properties.put("aaa","bbb");
        properties.put("ccc","ddd");
        properties.put("eee","fff");
        properties.put("aab","ddd");
        //删
        properties.remove("aaa");
        //改
        properties.put("ccc","eee");
        //查
        properties.get("ccc");
​
        Set<Object> keys = properties.keySet();
        for (Object key : keys) {
            System.out.println(properties.get(key));
        }
​
        Set<Map.Entry<Object, Object>> entries = properties.entrySet();
        for (Map.Entry<Object, Object> entry : entries) {
            System.out.println(entry.getKey()+":"+entry.getValue());
        }
    }
}

(2)主要方法
方法名返回值类型说明
setProperties(String key,String value)Object设置集合的键和值,都是String类型,底层调用Hashtable方法 put
getProperties(String key,String value)String使用此属性列表中指定的键搜索属性
stringPropertyNames()Set< String >从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串
load(InputStream is) 将本地文件中的键值对【userName=XXX】数据读取到集合中void从输入字节流读取属性列表(键和元素对)
load(Reader reader)void从输入字符流读取属性列表(键和元素对)
store(OutputStream os,String comments【注释】) 将集合中的数据以键值对形式保存在本地void将此属性列表(键和元素对)写入此 Properties表中, 以适合于使用load(lnputStream)方法的格式写入输出字节流
store(Writer writer,String comments)void将此属性列表(键和元素对)写入此 Properties表中, 以适合于使用load(lnputStream)方法的格式写入输出字符流

12.自动关闭流

JDK7之后可以自动关闭流,仅需把要关闭的流对象放入到try(需要关闭的流)之中即可,更多说明可自行查阅JDK帮助文档

try(最后需要关闭的流) {
    //执行代码
} catch (IOException e) {
   //捕获到异常的操作
}

  • 21
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值