IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 一篇文章总结java IO流(File、字节流、字符流、特殊操作流) -> 正文阅读

[Java知识库]一篇文章总结java IO流(File、字节流、字符流、特殊操作流)

目录

1.File

1.1 File类概述和构造方法

1.2 File类创建功能

?1.3 File类删除功能

1.4 File类判断和获取功能

2.字节流

2.1 IO流概述和分类

2.2 字节流写数据

?2.3 字节流写数据的3种方式

2.4 字节流写数据的两个小问题

2.5 字节流写输入加异常处理

?2.6 字节流读数据(一次读一个字节数据)

?2.7 字节流读数据(一次读一个字节数组的数据)

?2.8 案例:复制图片

2.9 字节缓冲流

?2.10 案例:复制视频

3.字符流

3.1 为什么会出现字符流

3.2 编码表

3.3 字符串中的编码解码问题

3.4 字符流中的编码解码问题

3.5 字符流写数据的五种方式

?3.6 字符流读数据的两种方式

3.7 案例:复制java文件

3.8 字符缓冲流

3.9 案例:复制java文件(字节缓冲流改进版)

3.10 字符缓冲流特有功能

3.11 IO流小结

?

4.特殊操作流

4.1 标准输入输出流

?4.2 打印流

4.3 对象序列化流

4.4 Properties


1.File

1.1 File类概述和构造方法

File:它是文件和目录路径名的抽象表示

  • 文件和目录是可以通过File封装成对象的
  • 对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已。它可以是存在的,也可以是不存在的。将来是要通过具体的操作把这个路径的内容转换为具体存在的。
方法名说明
public File(String pathname)
通过将给定的路径名字符串转换为抽象路径名来创建新的File实例
public File(String parent, String child)
从父路径名字符串和子路径名字符串创建新的File实例
public File(File parent, String child)
从父抽象路径名和子路径名字符串创建新的File实例

实例:

public class FileTest {
    public static void main(String[] args) {
        File f1 = new File("F:\\project\\Java\\java-03-IO\\java.txt");
        System.out.println(f1);

        File f2 = new File("F:\\project\\Java\\java-03-IO", "java.txt");
        System.out.println(f2);

        File f3 = new File("F:\\project\\Java\\java-03-IO");
        File f4 = new File(f3, "java.txt");
        System.out.println(f4);
    }
}

控制台输出:

1.2 File类创建功能

方法名说明
public boolean createNewFile()
当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件
public boolean mkdir()
创建由此抽象路径名命名的目录
public boolean mkdirs()
创建由此抽象路径名命名的目录,包括任何必须但不存在的父目录

实例:

public class FileTest2 {
    public static void main(String[] args) throws IOException {
        File f1 = new File("F:\\project\\Java\\java-03-IO\\java2.txt");
        System.out.println(f1.createNewFile());

        File f2 = new File("F:\\project\\Java\\java-03-IO\\test");
        System.out.println(f2.mkdir());

        File f3 = new File("F:\\project\\Java\\java-03-IO\\test\\test2\\test3");
        System.out.println(f3.mkdirs());
    }
}

控制台输出:

?1.3 File类删除功能

方法名说明
public boolean delete() 
删除由此抽象路径名表示的文件或目录

绝对路径和相对路径的区别

  • 绝对路径:完整的路径名,不需要任何其他信息就可以定位它所表示的文件,例如:F:\\project\\Java\\java-03-IO\\java2.txt
  • 相对路径:必须使用取自其他路径名的信息进行解释。例如:java-03-IO\\java3.txt

删除目录时的注意事项:

  • 如果一个目录中有内容(目录,文件),不能直接删除,应该先删除目录中的内容,最后才能删除目录。

实例:

public class FileTest3 {
    public static void main(String[] args) throws IOException {
        //File f1 = new File("F:\\project\\Java\\java-03-IO\\java2.txt");
        //在当前模块目录下创建java3.txt文件
        File f2 = new File("java-03-IO\\java3.txt");
        System.out.println(f2.createNewFile());

        //删除当前模块目录下的java.txt文件
        System.out.println(f2.delete());
        System.out.println("==========");

        //在当前模块目录下创建test目录
        File f3 = new File("java-03-IO\\test2");
        System.out.println(f3.mkdir());
        System.out.println("==========");

        //删除当前模块目录下的test2目录
        System.out.println(f3.delete());

        //在当前模块创建一个目录test3,,然后再该目录下创建一个文件java.txt
        File f4 = new File("java-03-IO\\test3");
        System.out.println(f4.mkdir());
        File f5 = new File("java-03-IO\\test3\\java.txt");
        System.out.println(f5.createNewFile());

        //删除当前模块下的目录test3
        System.out.println(f5.delete());
        System.out.println(f4.delete());
    }
}

控制台输出:

1.4 File类判断和获取功能

方法名说明
public boolean isDirectory()
测试此抽象路径名表示的File是否为目录
public boolean isFile()
测试此抽象路径名表示的file是否为文件
public boolean exists()
测试此抽象路径名表示的File是否存在
public String getAbsolutePath()
返回此抽象路径名的绝对路径名字符串
public String getPath()
将此抽象路径名转换为路径名字符串
public String getName()
返回由此抽象路径名表示的文件或目录的名称
public String[] list()
返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
public File[] listFiles()
返回此抽象路径名表示的目录中的文件和目录的File对象数组

实例:

/*
      方法名	                               说明
public boolean isDirectory()	    测试此抽象路径名表示的File是否为目录
public boolean isFile()	            测试此抽象路径名表示的file是否为文件
public boolean exists()         	测试此抽象路径名表示的File是否存在
public String getAbsolutePath()	    返回此抽象路径名的绝对路径名字符串
public String getPath()	            将此抽象路径名转换为路径名字符串
public String getName()	            返回由此抽象路径名表示的文件或目录的名称
public String[] list()	            返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
public File[] listFiles()	        返回此抽象路径名表示的目录中的文件和目录的File对象数组
*/
public class FileTest4 {
    public static void main(String[] args) {
        //public boolean isDirectory()	    测试此抽象路径名表示的File是否为目录
        File f1 = new File("F:\\project\\Java\\java-03-IO");
        System.out.println(f1.isDirectory());
        System.out.println("========");

        //public boolean isFile()	            测试此抽象路径名表示的file是否为文件
        File f2 = new File("F:\\project\\Java\\java-03-IO\\java.txt");
        System.out.println(f1.isFile());
        System.out.println("========");

        //public boolean exists()         	测试此抽象路径名表示的File是否存在
        System.out.println(f1.exists());
        System.out.println(f2.exists());
        System.out.println("========");

        //public String getAbsolutePath()	    返回此抽象路径名的绝对路径名字符串
        System.out.println(f1.getAbsolutePath());
        System.out.println(f2.getAbsolutePath());
        System.out.println("========");

        //public String getPath()	            将此抽象路径名转换为路径名字符串
        System.out.println(f1.getPath());
        System.out.println(f2.getPath());
        System.out.println("========");

        //public String getName()	            返回由此抽象路径名表示的文件或目录的名称
        System.out.println(f1.getName());
        System.out.println(f2.getName());
        System.out.println("========");

        //public String[] list()	            返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
        String[] strArray = f1.list();
        for (String str :
                strArray) {
            System.out.println(str);
        }
        System.out.println("========");

        //public File[] listFiles()	        返回此抽象路径名表示的目录中的文件和目录的File对象数组
        File[] files = f1.listFiles();
        for (File f :
                files) {
            System.out.println(f);
        }
    }
}

控制台输出:

2.字节流

2.1 IO流概述和分类

IO流概述:

  • IO:输入/输出(Input/Output)
  • 流:是一中抽象概念,是对数据传输的总称。也就是说数据在设备间的传输成为流,流的本质是数据传输
  • IO流就是用来处理设备间数据传输问题的
  • 常见的应用:文件复制,文件上传,文件下载

IO流分类:

按照数据的流向

  • 输入流:读数据
  • 输出流:写数据

按照数据类型来分

  • 字节流:字节输入流,字节输出流
  • 字符流:字符输入流,字符输出流

一般来说,我们说IO流是按照数据类型来分的

  • 如果数据通过记事本打开,我们还可以读懂里面的内容,我们就用字符流
  • 否则使用字节流。如果不知道使用哪种类型的流,就使用字节流

2.2 字节流写数据

字节流抽象基类

  • InputStream:这个抽象类是表示字节输入流的所有类的超类
  • OutputStream:这个抽象类是表示字节输出流的所有类的超类
  • 子类名特点:子类名称都是以其父亲名作为子类名的后缀

FileOutputSteam:文件输出流用于将输入写入File

  • FileOutputSteam(String name):创建文件输出流以指定的名称写入文件

使用字节输出流写数据的步骤:

  • 创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
  • 调用字节输出流对象的写数据方法
  • 释放资源(close)

实例:

/*
FileOutputSteam:文件输出流用于将输入写入File
FileOutputSteam(String name):创建文件输出流以指定的名称写入文件
*/
public class FileOutputSteamTest {
    public static void main(String[] args) throws IOException {
        //创建字节输出流对象
        //FileOutputSteam:文件输出流用于将输入写入File
        FileOutputStream fos = new FileOutputStream("java-03-IO\\fos.txt");
        /*
        * 做了三件事情
        *   1.调用系统功能创建了文件
        *   2.创建了字节输出流对象
        *   3.让字节输出流对象指向创建好的文件
        * */


        //public void write(int b):将制定的字节写入此文件输出流
        fos.write(97);
        
        //最后都要释放资源   public void close()
        fos.close();
    }
}

控制台输出:

?2.3 字节流写数据的3种方式

方法名说明
public void write(int b)

将指定的字节写入此文件输出流

一次写一个字节数据

public void write(byte b[])

将b.length字节从指定的字节数组写入此文件输出流,一次写一个字节数组数据

public void write(byte b[], int off, int len)
将len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流,一次写一个字节数组的部分数据

实例:

/*
     方法名	                                                说明
public void write(int b)	                    将指定的字节写入此文件输出流一次写一个字节数据
public void write(byte b[])	                    将b.length字节从指定的字节数组写入此文件输出流,一次写一个字节数组数据
public void write(byte b[], int off, int len)	将len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流,一次写一个字节数组的部分数据
* */
public class FileOutputStreamTest2 {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("java-03-IO\\fos2.txt");
        //FileOutputStream fos = new FileOutputStream(new File("java-03-IO\\fos2.txt"));

        //public void write(int b)
        fos.write(90);
        fos.write(91);
        fos.write(92);
        fos.write(93);

        //public void write(byte b[])
        byte[] bytes = {94,95,96,97};
        fos.write(bytes);
        byte[] bytes1 = " [][]".getBytes();
        fos.write(bytes1);

        //public void write(byte b[], int off, int len)
        byte[] bytes2 = " {[1!@#$%^&]".getBytes();
        fos.write(bytes2,0,bytes2.length);
    }
}

控制台输出:

2.4 字节流写数据的两个小问题

字节流写数据实现换行呢?

  • 写完数据后,加换行符\n

字节流写数据如何实现追加写入呢?

  • public FileOutputStream(File file, boolean append)
  • 创建文件输出流以指定的名称写入文件如果第二个参数为true,则字节将写入文件的末尾而不是开头

实例:

/*
* 字节流写数据实现换行呢?
    window:\r\n
    linux:\n
    mac:\r

字节流写数据如何实现追加写入呢?
 public FileOutputStream(File file, boolean append)
    创建文件输出流以指定的名称写入文件
    如果第二个参数为true,则字节将写入文件的末尾而不是开头
* ?*/
public class FileOutputStreamTest3 {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("java-03-IO\\fos3.txt",true);

        //写数据,实现换行
        for (int i = 0; i < 10; i++) {
            fos.write("java".getBytes());
            fos.write("\n".getBytes());
        }

        fos.close();
    }
}

控制台输出:

2.5 字节流写输入加异常处理

?finally:在异常处理时提供finally块来执行所有清除操作,比如说IO流中的释放资源

实例:

public class FileOutputStreamTest4 {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("java-03-IO\\fos4.txt");
            //fos = new FileOutputStream("X:java-03-IO\\fos4.txt");
            fos.write("java".getBytes());

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

控制台输出:

?2.6 字节流读数据(一次读一个字节数据)

FileInputStream:从文件系统中的文件获取输入字节

  • FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名

使用字节输入流读数据的步骤:

  1. 创建字节输入流对象
  2. 调用字节输入流对象的读数据方法
  3. 释放资源

需求:把文件fos.txt中的内容读取出来,在控制台输出

fos.txt文件中的内容为:

古巨基
博士
与复古一幅一幅一幅一幅付一半
iuhuhiuhiu
!#$$%%$%%$


465r56456

实例:

public class FileInputStreamTest {
    public static void main(String[] args) throws IOException {
        //创建字节流输入对象
        FileInputStream fis = new FileInputStream("java-03-IO\\fos.txt");

        //调用字节输入流对象的读数据方法
        //public int read():  从该输入流读取一个字节的数据

        /*//第一次读取数据
        int read = fis.read();
        System.out.println(read);
        System.out.println((char) read);

        //第二次读取数据
        int read2 = fis.read();
        System.out.println(read2);
        System.out.println((char) read2);*/

        /*int by = fis.read();
        while (by != -1) {
            System.out.println((char)by);
            by = fis.read();
        }*/

        //优化上面的程序
        int by;
        while ((by=fis.read()) != -1) {
            System.out.println((char)by);
        }

        //释放资源
        fis.close();
    }
}

控制台输出:

?2.7 字节流读数据(一次读一个字节数组的数据)

需求:把文件fos.txt中的内容读取出来在控制台输出

实例:

public class FileInputStreamTest2 {
    public static void main(String[] args) throws IOException {
        //创建字节流输入对象
        FileInputStream fis = new FileInputStream("java-03-IO\\fos.txt");

        /*//调用字节输入流对象的读数据方法
        //public int read(byte b[])
        byte[] bytes = new byte[5];

        //第一次读取数据
        int len = fis.read(bytes);
        System.out.println(len);
        //System.out.println(new String(bytes));
        System.out.println(new String(bytes,0,len));

        //第二次读取数据
        len = fis.read(bytes);
        System.out.println(len);
        //System.out.println(new String(bytes));
        System.out.println(new String(bytes,0,len));

        //第三次读取数据
        len = fis.read(bytes);
        System.out.println(len);
        System.out.println(new String(bytes,0,len));

        //第四次读取数据
        len = fis.read(bytes);
        System.out.println(len);
        System.out.println(new String(bytes,0,len));*/
        /*
        * hello\r\n
        * world\r\n
        *
        * 第一次:hello
        * 第二次:\r\nwor
        * 第三次:ld\r\nr      会对第二次读取到的进行替换,正好替换前苏哥
        * */


        byte[] bytes = new byte[1024];
        int len;
        while ((len=fis.read(bytes)) != -1) {
            System.out.println(new String(bytes,0,len));
        }

        //释放资源
        fis.close();
    }
}

控制台输出:

?2.8 案例:复制图片

实例:

public class CopyJpgTest {
    public static void main(String[] args) throws IOException {
        //根据数据源创建字节输入流对象
        FileInputStream fis = new FileInputStream("C:\\Users\\Administrator.LAPTOP-62FQ379R\\Desktop\\copy.png");
        //根据目的地创建字节输出流对象
        FileOutputStream fos = new FileOutputStream("java-03-IO\\copy.png");

        //读取数据,复制图片
        byte[] bytes = new byte[1024];
        int len;
        while ((len=fis.read(bytes)) != -1) {
            fos.write(bytes,0,len);
        }

        //释放资源
        fis.close();
        fos.close();

    }
}

查看有没有图片

?成功!

2.9 字节缓冲流

字节缓冲流:

  • BufferedOutputStream:该类实现缓冲输出流。通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
  • BufferedInputStream:创建BufferedInputStream将创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节

构造方法:

  • 字节缓冲输出流:public BufferedOutputStream(OutputStream out)
  • 字节缓冲输入流:public BufferedInputStream(InputStream in)

为什么构造方法需要的是字节流,而不是具体的文件或者路径呢?

  • 字节缓冲区仅仅提供缓冲区,而真正的读写数据还得依靠基本的字节流对象进行操作

实例:

/*
字节缓冲流:

BufferedOutputStream:该类实现缓冲输出流。通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
BufferedInputStream:创建BufferedInputStream将创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节

构造方法:

字节缓冲输出流:public BufferedOutputStream(OutputStream out)
字节缓冲输入流:public BufferedInputStream(InputStream in)
* */
public class BufferStreamTest {
    public static void main(String[] args) throws IOException {
        //字节缓冲输出流:BufferedOutputStream
        /*FileOutputStream fos = new FileOutputStream("java-03-IO\\fos.txt");
        BufferedOutputStream bos = new BufferedOutputStream(fos);*/
        /*BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("java-03-IO\\fos.txt"));

        //写数据
        bos.write("hello\r\n".getBytes());
        bos.write("world\r\n".getBytes());

        //释放资源
        bos.close();*/

        //字节缓冲输入流:BufferedInputStream
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("java-03-IO\\fos.txt"));

        /*//一次读取一个字节数据
        int by;
        while((by=bis.read()) != -1) {
            System.out.println((char)by);
        }*/

        //一次读取一个字节数组数据
        byte[] bytes = new byte[1024];
        int len;
        while((len = bis.read(bytes)) != -1) {
            System.out.println(new String(bytes,0,len));
        }

        //释放资源
        bis.close();

    }
}

控制台输出:

?2.10 案例:复制视频

需求:把"C:\Users\Administrator.LAPTOP-62FQ379R\Desktop\copy.mp4"复制到模块目录下的"copy.mp4"

思路:

  1. 根据数据源创建字节输入流对象
  2. 根据目的地创建字节输出流对象
  3. 读写数据,复制视频
  4. 释放资源
四种方式实现复制视频:并记录每种方式复制视频的事件
    1.基于字节流一次读写一个字节
    2.基于字节流一次读写一个字节数组
    3.基于缓冲流一次读写一个字节
    4.基于缓冲流一次读写一个字节数组

第一种方法:基于字节流一次读写一个字节

/*
需求:把"C:\Users\Administrator.LAPTOP-62FQ379R\Desktop\copy.mp4"复制到模块目录下的"copy.mp4"

思路:

根据数据源创建字节输入流对象
根据目的地创建字节输出流对象
读写数据,复制视频
释放资源

四种方式实现复制视频:并记录每种方式复制视频的事件
    1.基于字节流一次读写一个字节
    2.基于字节流一次读写一个字节数组
    3.基于缓冲流一次读写一个自己
    4.基于缓冲流一次读写一个字节数组
* */
public class CopyMp4 {
    public static void main(String[] args) throws IOException {

        long startTime = System.currentTimeMillis();

        FileInputStream fis = new FileInputStream("C:\\Users\\Administrator.LAPTOP-62FQ379R\\Desktop\\copy.mp4");
        FileOutputStream fos = new FileOutputStream("java-03-IO\\copy.mp4");
        //1.基于字节流一次读写一个字节
        int by;
        while((by = fis.read()) != -1) {
            fos.write(by);
        }

        long endTime = System.currentTimeMillis();
        System.out.println("第一种方法共耗时:" + (startTime - endTime) + "毫秒");

        fis.close();
        fos.close();
    }
}

控制台输出:

?第二种方法:基于字节流一次读写一个字节数组

public class CopyMp4Test2 {
    public static void main(String[] args) throws IOException {
        long startTime = System.currentTimeMillis();

        FileInputStream fis = new FileInputStream("C:\\Users\\Administrator.LAPTOP-62FQ379R\\Desktop\\copy.mp4");
        FileOutputStream fos = new FileOutputStream("java-03-IO\\copy.mp4");
        //2.基于字节流一次读写一个字节数组
        byte[] bytes = new byte[1024];
        int len;
        while((len = fis.read(bytes)) != -1) {
            fos.write(bytes,0,len);
        }

        long endTime = System.currentTimeMillis();
        System.out.println("第二种方法共耗时:" + (endTime - startTime) + "毫秒");

        fis.close();
        fos.close();
    }
}

控制台输出:

?第三种方法:基于缓冲流一次读写一个字节

public class CopyMp4Test3 {
    public static void main(String[] args) throws IOException {
        long startTime = System.currentTimeMillis();

        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\Administrator.LAPTOP-62FQ379R\\Desktop\\copy.mp4"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("java-03-IO\\copy.mp4"));

        //3.基于缓冲流一次读写一个字节
        int by;
        while((by = bis.read()) != -1) {
            bos.write(by);
        }

        long endTime = System.currentTimeMillis();
        System.out.println("第三种方法共耗时:" + (endTime - startTime) + "毫秒");

        bis.close();
        bos.close();
    }
}

控制台输出:

?第四种方法:基于缓冲流一次读写一个字节数组

public class CopyMp4Test4 {
    public static void main(String[] args) throws IOException {
        long startTime = System.currentTimeMillis();

        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\Administrator.LAPTOP-62FQ379R\\Desktop\\copy.mp4"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("java-03-IO\\copy.mp4"));

        //4.基于缓冲流一次读写一个字节数组
        byte[] bytes = new byte[1024];
        int len;
        while((len = bis.read(bytes)) != -1) {
            bos.write(bytes,0,len);
        }

        long endTime = System.currentTimeMillis();
        System.out.println("第四种方法共耗时:" + (endTime - startTime) + "毫秒");

        bis.close();
        bos.close();
    }
}

控制台输出:

?由结果可知,基于缓冲流一次读写一个字节数组的方式最快

3.字符流

3.1 为什么会出现字符流

由于字节流操作中文不是特别的方便,所以java就提供字符流

  • 字符流 = 字节流 + 编码表

用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼装成中文,如何识别中文的呢?

  • 汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数

3.2 编码表

基础知识:

  • 计算机中存储的信息都是用二进制数表示的,我们在屏幕上看到的英文,汉字等字符都是二进制数转换之后的结果
  • 按照某种规则,将字符存储到计算机中,成为编码。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,成为解码。
  • 按照哪种编码规则编码就必须按照此种规则进行解析

字符编码:就是一套自然语言的字符与二进制之间的对应规则

字符集:

  • 是一个系统支持的所有字符的集合,包括各国家文字,标点符号,图形符号,数字等
  • 计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码。
  • 常见的字符集有ASCII字符集,GBXXX字符集,Unicode字符集等

ASCII字符集:

  • ASCII ((American Standard Code for Information Interchange): 美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是最通用的信息交换标准,并等同于国际标准ISO/IEC 646。ASCII第一次以规范标准的类型发表是在1967年,最后一次更新则是在1986年,到目前为止共定义了128个字符。
  • ASCII 码使用指定的7 位或8 位二进制数组合来表示128 或256 种可能的字符。标准ASCII 码也叫基础ASCII码,使用7 位二进制数(剩下的1位二进制为0)来表示所有的大写和小写字母,数字0 到9、标点符号,以及在美式英语中使用的特殊控制字符

GBXXX字符集:

GB2312:

  • GB2312编码适用于汉字处理、汉字通信等系统之间的信息交换,通行于中国大陆;新加坡等地也采用此编码。中国大陆几乎所有的中文系统和国际化的软件都支持GB 2312。
  • 基本集共收入汉字6763个和非汉字图形字符682个。整个字符集分成94个区,每区有94个位。每个区位上只有一个字符,因此可用所在的区和位来对汉字进行编码,称为区位码。

GBK:

  • GBK与GB 2312—1980国家标准所对应的内码标准兼容,同时在字汇一级支持ISO/IEC10646—1和GB 13000—1的全部中、日、韩(CJK)汉字,共计20902字。

GB18030:

  • 是我国制订的以汉字为主并包含多种我国少数民族文字(如藏、蒙古、傣、彝、朝鲜、维吾尔文等)的超大型中文编码字符集强制性标准,其中收入汉字70000余个

Unicode字符集:

  • 统一码,也叫万国码、单一码(Unicode)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。
  • 有三种编码方案,UTF-8、UTF-16和UTF32。最为常见的是UTF-8
  • UTF-8(8位元,Universal Character Set/Unicode Transformation Format)是针对Unicode的一种可变长度字符编码。它可以用来表示Unicode标准中的任何字符,而且其编码中的第一个字节仍与ASCII相容,使得原来处理ASCII字符的软件无须或只进行少部分修改后,便可继续使用。因此,它逐渐成为电子邮件,网页及其他存储或传送文字的应用中,优先采用的编码。

编码规则:

  • UTF-8使用1~4字节为每个字符编码:
  • 一个US-ASCIl字符只需1字节编码(Unicode范围由U+0000~U+007F)。
  • 带有变音符号的拉丁文、希腊文、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文等字母则需要2字节编码(Unicode范围由U+0080~U+07FF)。
  • 其他语言的字符(包括中日韩文字、东南亚文字、中东文字等)包含了大部分常用字,使用3字节编码。
  • 其他极少使用的语言字符使用4字节编码。

小结:采用何种规则编码,就要采用何种规则解码!

3.3 字符串中的编码解码问题

编码:

  • byte[] getBytes():使用平台(idea)默认字符集将该String编码为一系列字节,将该结果存储到新的字符数组中
  • byte[] getBytes(String charsetName):使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中

解码:

  • String(byte[] bytes):通过使用平台(idea)的默认字符集解码指定的字节数组来构造新的String
  • String(bytes[] bytes,String charsetName):通过指定的字符集解析指定的字节数组来构造新的String

实例:

public class StringTest {
    public static void main(String[] args) throws UnsupportedEncodingException {
        String s = "周星驰";

        //默认方式编码
        byte[] bytes = s.getBytes();//[-27, -111, -88, -26, -104, -97, -23, -87, -80]
        System.out.println(Arrays.toString(bytes));

        //指定方式编码:utf-8
        byte[] bytes1 = s.getBytes("utf-8");
        System.out.println(Arrays.toString(bytes1));

        //指定方式编码:gbk
        byte[] bytes2 = s.getBytes("gbk");
        System.out.println(Arrays.toString(bytes2));

        //默认方式解码
        String ss = new String(bytes);
        System.out.println(ss);

        //指定字符集解码
        String ss2 = new String(bytes2,"GBK");
        System.out.println(ss2);

    }
}

控制台输出:

3.4 字符流中的编码解码问题

字符流抽象基类

  • Reader:字符输入流的抽象类
  • Writer:字符输出流的抽象类

字符流中和编码解码问题相关的两个类:

  • InputStreamReader
  • OutputStreamWriter

实例:

public class ConversionStreamTest {
    public static void main(String[] args) throws IOException {
        //public OutputStreamWriter(OutputStream out)
        //public OutputStreamWriter(OutputStream out, String charsetName)
//        FileOutputStream fos = new FileOutputStream("java-03-IO\\fos.txt");
//        OutputStreamWriter osw = new OutputStreamWriter(fos);
//        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("java-03-IO\\fos.txt"));
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("java-03-IO\\fos.txt"),"gbk");
        osw.write("周星驰x");

        osw.close();

        //public InputStreamReader(InputStream in)
        //public InputStreamReader(InputStream in, String charsetName)
        InputStreamReader isr = new InputStreamReader(new FileInputStream("java-03-IO\\fos.txt"),"gbk");

        //一次读取一个字符数据
        int ch;
        while ((ch = isr.read()) != -1) {
            System.out.println((char) ch);
        }

        isr.close();
    }
}

控制台输出:

3.5 字符流写数据的五种方式

方法名说明
public void write(int c)
写入一个字符
public void write(char cbuf[])
写入一个字符数组
public void write(char cbuf[], int off, int len)
写入字符数组的一部分
public void write(String str)
写入一个字符串
public void write(String str, int off, int len)
写入一个字符串的一部分

方法名说明
flush()刷新流,还可以继续写数据
close()关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据

实例:

/*
     方法名	                                               说明
public void write(int c)	                            写入一个字符
public void write(char cbuf[])	                        写入一个字符数组
public void write(char cbuf[], int off, int len)	    写入字符数组的一部分
public void write(String str)	                        写入一个字符串
public void write(String str, int off, int len)	        写入一个字符串的一部分
*/
public class OutputStreamWriterTest {
    public static void main(String[] args) throws IOException {
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("java-03-IO\\fos.txt"));

        //public void write(int c):写入一个字符
//        osw.write(97);
//        osw.flush();


        //public void write(char cbuf[]):写入一个字符数组
        char[] chs = {'粥','星','吃','或','和'};
//        osw.write(chs);

        //public void write(char cbuf[], int off, int len):写入字符数组的一部分
//        osw.write(chs,0,chs.length);

        //public void write(String str)	                        写入一个字符串
//        osw.write("abc周星驰");

//        osw.write("abc周星驰",0,"abc周星驰".length());
//        osw.write("abc周星驰",1,2);


        osw.close();
    }
}

控制台输出:

?3.6 字符流读数据的两种方式

方法名说明
int read()一次读一个字符数据
int read(char[] read)一次读一个字符数组数据

实例:

/*
方法名	                        说明
int read()	                一次读一个字符数据
int read(char[] read)	    一次读一个字符数组数据
*/
public class InputStreamReaderTest {
    public static void main(String[] args) throws IOException {
        InputStreamReader isr = new InputStreamReader(new FileInputStream("java-03-IO\\fos.txt"));

        //int read():一次读一个字符数据
//        int ch;
//        while ((ch = isr.read()) != -1) {
//            System.out.print((char)ch);
//        }

        //int read(char[] read):一次读一个字符数组数据
        char[] chars = new char[1024];
        int len;
        while ((len = isr.read(chars)) != -1) {
            System.out.println(new String(chars,0,len));
        }

        //释放资源
        isr.close();
    }
}

控制台输出:

3.7 案例:复制java文件

需求:把模块目录下的"OutputStreamWriterTest.java"复制到模块目录下的"copy.java"

分析

  • 转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化书写,转换流提供了对应的子类
  • FileReader:用于读取字符文件的便捷类:FileReader(String fileName)? ?
  • FileWriter:用于写入字符文件的边界类(FileWriter(String fileName)?

数据源和目的地的分析

数据源:?OutputStreamWriterTest.java---读数据---Reader---InputStreamReader---FileReader

目的地:copy.java---写数据---Writer---OutputStreamWriter---FileWriter

思路:????????

  1. 根据数据源创建字符输入流对象
  2. 根据目的地创建字符输出流对象
  3. 读写数据,复制文件
  4. 释放资源

实例:

/*
根据数据源创建字符输入流对象
根据目的地创建字符输出流对象
读写数据,复制文件
释放资源
* */
public class CopyJavaTest {
    public static void main(String[] args) throws IOException {
        //根据数据源创建字符输入流对象
        FileReader fr = new FileReader("java-03-IO\\OutputStreamWriterTest.java");
        //根据目的地创建字符输出流对象
        FileWriter fw = new FileWriter("java-03-IO\\copy.java");

        //读写数据,复制文件
//        int ch;
//        while ((ch = fr.read()) != -1) {
//            fw.write(ch);
//        }

        char[] chars = new char[1024];
        int len;
        while ((len = fr.read(chars)) != -1) {
            fw.write(chars,0,len);
        }

        //释放资源
        fw.close();
        fr.close();
    }
}

控制台输出:

3.8 字符缓冲流

字符缓冲流:

  • BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接收默认大小。默认值足够大,可用于大多数用途
  • BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。默认值足够大,可用于大多数用途

构造方法:

BufferedWriter(Writer out)

BufferedReader(Reader in)

实例:

public class BufferedStreamTest {
    public static void main(String[] args) throws IOException {
//        FileWriter fw = new FileWriter("java-03-IO\\fos.txt");
        BufferedWriter bw = new BufferedWriter(fw);
//
//        BufferedWriter bw = new BufferedWriter(new FileWriter("java-03-IO\\fos.txt"));
//        bw.write("hello\n");
//        bw.write("world");
//        bw.close();

        BufferedReader br = new BufferedReader(new FileReader("java-03-IO\\fos.txt"));

        //一次读一个字符数据
//        int ch;
//        while ((ch = br.read()) != -1) {
//            System.out.print((char)ch);
//        }

        //一次读取一个字符数组数据
        char[] chars = new char[1024];
        int len;
        while ((len = br.read(chars)) != -1) {
            System.out.println(new String(chars,0,len));
        }
        
        br.close();
    }
}

控制台输出:

3.9 案例:复制java文件(字节缓冲流改进版)

需求:把模块目录下的"OutputStreamWriterTest.java"复制到模块目录下的"copy.java"

思路:

  1. 根据数据源创建字符缓冲输入流对象
  2. 根据目的地创建字符缓冲流输出对象
  3. 读写数据,复制文件
  4. 释放资源

实例:

public class CopyJavaTest {
    public static void main(String[] args) throws IOException {
        //根据数据源创建字符缓冲输入流对象
        BufferedReader br = new BufferedReader(new FileReader("java-03-IO\\OutputStreamWriterTest.java"));
        //根据目的地创建字符缓冲流输出对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("java-03-IO\\copy.java"));

        //读写数据,复制文件
//        int ch;
//        while ((ch = br.read()) != -1) {
//            bw.write(ch);
//        }

        //一次读写一个字符数组的数据
        char[] chars = new char[1024];
        int len;
        while ((len = br.read(chars)) != -1) {
            bw.write(chars,0,len);
        }

        //释放资源
        br.close();
        bw.close();

    }
}

控制台输出:

3.10 字符缓冲流特有功能

BufferedWriter:

  • void newLine():写一行行分隔符,行分隔符字符串由系统属性定义

BufferedReader:

  • public String readLine():读一行文字。结果包含行的内容的字符串,不包括任何行终止字符,如果流的结尾已经到达,则为null

实例:

public class BufferedStreamTest2 {
    public static void main(String[] args) throws IOException {
//        BufferedWriter bw = new BufferedWriter(new FileWriter("java-03-IO\\fos.txt"));
//
//        for (int i = 0; i < 10; i++) {
//            bw.write("hello" + i);
            bw.write("\r\n");
//            bw.newLine();
//            bw.flush();
//        }
//        bw.close();

        //创建字符缓冲输入流
        BufferedReader br = new BufferedReader(new FileReader("java-03-IO\\fos.txt"));

//        String s = br.readLine();
//        System.out.println(s);
//        s = br.readLine();
//        System.out.println(s);

        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }

        br.close();
    }
}

控制台输出:

3.11 IO流小结

4.特殊操作流

4.1 标准输入输出流

System类中有两个静态的成员变量:

  • public static final InputStream in:标准输入流。通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源
  • public static final PrintStream out:标准输出流。通常该流对应于显示输出或由主机环境或用户指定的另一个输出目标

自己实现键盘录入数据:

  • BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

写起来太麻烦,java就提供了一个类实现键盘录入

  • Scanner sc = new Scanner(System.in);

实例:

public class SystemInTest {
    public static void main(String[] args) throws IOException {
//        InputStream in = System.in;
//
//        int by;
//        while ((by = in.read()) != -1) {
//            System.out.println((char)by);
//        }
//
//        //如何把字节流转换成字符流?
//        InputStreamReader isr = new InputStreamReader(in);
//        //使用字符流能不能欧一次读取一行数据呢?
//        //但是一次读取一行数据的方法是字符缓冲输入流的特有方法
//        BufferedReader br = new BufferedReader(isr);

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("请输入一个字符串:");
        String line = br.readLine();
        System.out.println("你输出的字符串是:" + line);

        System.out.println("请输入一个整数:");
        int i = Integer.parseInt(br.readLine());
        System.out.println("你输入的整数是:" + i);

        //自己实现键盘录入数据太麻烦了,所以java提供了一个类供我们使用
        Scanner sc = new Scanner(System.in);
    }
}

控制台输出:

?

输出语句的本质:是一个标准的输出流

  • PrintStream out = System.out;
  • PrintStream类特有的方法,System.out都可以使用

实例:

public class SystemOutTest {
    public static void main(String[] args) {
        PrintStream out = System.out;
//        out.print("hello");
//        out.print(100);

        //System.out的本质是一个字节输出流
        System.out.println("hello");
        System.out.println(100);
    }
}

控制台输出:

?4.2 打印流

打印流分类:

  • 字节打印流:PrintStream
  • 字符打印流:PrintWriter

打印流的特点:

  • 只负责输出数据,不负责读取数据
  • 有自己的特有方法

字节打印流

  • PrintStream(String fileName):使用指定的文件名创建新的打印流
  • 使用继承父类的方法写数据,查看的时候会转码;使用自己的特有方法写数据,查看的数据原样输出

实例:

public class PrintStreamTest {
    public static void main(String[] args) throws FileNotFoundException {
        PrintStream ps = new PrintStream("java-03-IO\\fos.txt");

        //写数据
        //字节输出流的方法
        ps.write(98);

        //使用特有方法写数据
        ps.print(97);
        //释放资源
        ps.close();
    }
}

控制台输出:

?

字符打印流PrintWriter的构造方法:

方法名说明
PrintWriter(String fileName)使用指定的文件名创建一个新的PrintWriter,而不需要自动执行刷新
PrintWriter(Writer out,boolean autoFlush)

创建一个新的PrintWriter

  • out:字符输出流
  • autoFlush:一个布尔值,如果为真,则println,frintf,或format方法将刷新输出缓冲区

实例:

public class PrintWriterTest {
    public static void main(String[] args) throws IOException {
//        PrintWriter pw = new PrintWriter("java-03-IO\\fos.txt");
//
        pw.write("hello");
        pw.write("\r\n");
        pw.flush();
        pw.write("world");
        pw.flush();
//
//        pw.println("hello");
//        pw.flush();
//        pw.println("world");
//        pw.flush();
//
//        pw.close();

        PrintWriter pw = new PrintWriter(new FileWriter("java-03-IO\\fos.txt"), true);
        pw.println("hello");
        pw.println("world");

        pw.close();

    }
}

控制台输出:

?

4.3 对象序列化流

对象序列化:就是将对象保存在磁盘中,或者在网络中传输对象

这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息字节序列写到文件之后,相当于文件中持久保存了一个对象的信息

反之,该字节序列还可以从文件中读取出来,重构对象,对它进行反序列化

要实现序列化和反序列化就要使用对象序列化流和对象反序列化流

  • 对象序列化流:ObjectOutputStream
  • 对象反序列化流:ObjectInputStream

对象序列化流:ObjectOutputStream

  • 将java对象的原始数据类型和图形写入OutputStream。可以使用ObjectInputStream读取(重构)对象。可以通过使用流的文件来实现对象的持久存储。如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象

构造方法:

  • ObjectOutputStream(OutputStream out):创建一个写入指定的OutputStream的ObjectOutputStream

序列化对象的方法:

  • void writeObject(Object obj):将指定的对象写入ObjectOutputStream

注意:

一个对象要想被序列化,该对象所属的类必须 实现Serializable接口

Serializable是一个标记接口,实现该接口,不需要重写任何方法

实例:

public class ObjectOutputStreamTest {
    public static void main(String[] args) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("java-03-IO\\fos.txt"));
        //创建对象
        Student student = new Student("周星驰",30);

        oos.writeObject(student);

        //释放资源
        oos.close();
    }
}

控制台输出:

对象反序列化流:ObjectInputStream?

  • ObjectInputStream反序列化先前使用ObjectOutputSteam编写的原始数据对象

构造方法:

  • ObjectInputStream(InputSteam in):创建从指定的InputStream读取的ObjectInputStream

反序列化对象的方法:

Object readObject():从ObjectInputStream读取一个对象

实例:

public class ObjectInputStreamTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("java-03-IO\\fos.txt"));

        Object obj = ois.readObject();

        Student s = (Student)obj;
        System.out.println(s.getName() + s.getAge());

        //释放资源
        ois.close();
    }
}

控制台输出:

4.4 Properties

Properties概述:

  • 是一个Map体系的集合类
  • Properties可以保存到流中或从流中加载

练习:Properties作为Map集合的使用????????

public class PropertiesTest {
    public static void main(String[] args) {
        //创建集合对象
        //Properties<String,String> prop = new Properties<String,String>();//错误
        Properties properties = new Properties();

        //存储元素
        properties.put("001","周星驰");
        properties.put("002","刘德华");
        properties.put("003","周润发");

        //遍历集合
        Set<Object> keySet = properties.keySet();
        for (Object key :
                keySet) {
            Object value = properties.get(key);
            System.out.println(key + "," + value);
        }
    }
}

控制台输出:

Properties作为集合的特有方法:

方法名说明
Object setProperty(String key,String value)设置集合的键和值,都是String类型,底层调用Hashtable方法put
String getProperty(String key)使用此属性列表中指定的键搜索属性
Set<String> stringPropertyNames()从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串

?实例:

public class PropertiesTest2 {
    public static void main(String[] args) {
        //创建集合对象
        Properties prop = new Properties();

        //添加元素
        prop.setProperty("001","周星驰");
        prop.setProperty("002","刘德华");
        prop.setProperty("003","周润发");

        System.out.println(prop.getProperty("001"));
        System.out.println(prop);

        Set<String> names = prop.stringPropertyNames();
        for (String key :
                names) {
            String value = prop.getProperty(key);
            System.out.println(key + "," + value);
        }
    }
}

?控制台输出:

?Properties和IO流结合的方法:

方法名说明
void load(InputStream inStream)从输入字节流读取属性列表(键和元素对)
void load(Reader reader)从输入字符流读取属性列表(键和元素对)
void store(OutputStream out,String comments)将此属性列表(键和元素对)写入此Properties表中,以适合于使用load(InputStream)方法的格式写入输出字节流
void store(Winter winter,String comments)将此属性列表(键和元素对)写入此Properties表中,以适合使用load(Reader)方法的格式写入输出字符流

实例:

public class PropertiesTest3 {
    public static void main(String[] args) throws IOException {
        //把集合中的数据保存到文件
        myStore();
        //把文件中的数据加载到集合
        myLoad();
    }

    private static void myStore() throws IOException {
        Properties prop = new Properties();

        prop.put("001","周星驰");
        prop.put("002","刘德华");
        prop.put("003","周润发");

        FileWriter fw = new FileWriter("java-03-IO\\fos.txt");
        prop.store(fw,null);
        fw.close();
    }

    private static void myLoad() throws IOException {
        Properties prop = new Properties();
        FileReader fr = new FileReader("java-03-IO\\fos.txt");
        prop.load(fr);
        fr.close();
        System.out.println(prop);
    }
}

控制台输出:

?

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-07 11:51:51  更:2021-08-07 11:53:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/10 7:35:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码