编程语言
首页 > 编程语言> > 【Java学习笔记】IO流

【Java学习笔记】IO流

作者:互联网

文章目录

IO流

IO流概述和分类

IO流概述

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

IO流分类

按照数据的流向: 输入对应的是读数据,输出对应的是写数据
按照数据类型: 字节流(字节输入流,字节输出流),字符流(字符输入流,字符输出流),能读的懂的(例如用记事本打开一个txt文档)称为字符流,不能读懂的(例如用记事本打开一张图片,看到的是一堆乱码)称为字节流(如果不知道用字节流还是用字符流,默认 使用字节流)。

字节流

抽象父类:
字节输入流(InputStream)
字节输出流(OutputStream)

字节流写数据:
FileOutputStream: 文件输出流用于将数据写入File

步骤:一,创建字节流输出流对象,二,调用字节输出流对象的写数据方法,三,释放资源。

    public static void main(String[] args) throws IOException {
        //一,创建字节流输出对象 FileOutputStream(String name): 创建文件输出流以指定的名称写入文件
        //1.调用系统功能创建了文件
        //2.创建了字节输出流对象
        //3.让字节输出流对象指向创建好的文件
        FileOutputStream fos = new FileOutputStream("fos.txt");

        //二,void write(int b):将指定的字节写入此文件输出流
        fos.write(97);

        //三,释放资源
        //void close(): 关闭此文件输出流并释放与此相关联的任何系统资源
        fos.close();
    }

字节流写数据的3种方式
方法名说明
void write(int b)将指定的字节写入此文件输出流一次写一个字节数据
void write(byte[] b)将b.length字节从指定的字节数组写入此文件输出流,一次写一个字节数组数据
void write(byte[]b,int off,int len)将len字节从指定的字节数组开始,从偏移量(索引)off开始写入此文件输出流一次写一个字节数据的部分数据
    public static void main(String[] args) throws IOException {
        //构造方法1:FileOutputStream(String name): 创建文件输出流以指定的名称写入文件
        FileOutputStream fos=new FileOutputStream("fos.txt");

        //构造方法2:FileOutputStream(File file):创建文件输出流以写入由指定的File对象表示的文件
        File file=new File("fos.txt");
        FileOutputStream fos2=new FileOutputStream(file);

        //写数据的三种方式:

        //方式1:void write(int b):将指定的字节写入此文件输出流
        fos.write(97);
        fos.write(98);
        fos.write(99);
        fos.write(100);
        fos.write(101);

        //方式2:void write(byte[] b):将b.length字节从指定的字节数据写入此文件输出流
        byte[] bys={97,98,99,100,101};
        fos.write(bys);

        //方式2的简化写法(用到String类的getBytes();返回字符串对应的字节数组方法)
        String str="abcde";
        byte[] bytes = str.getBytes();
        fos.write(bytes);

        //方式3:void write(byte[]b,int off,int len):将len字节从指定的字节数组开始,从偏移量off处开始写数据
        String str2="abcde";
        byte[] bytes1 = str2.getBytes();
        fos.write(bytes1,0,bys.length);
    }

字节流写数据的两个小问题
  1. 字节流写数据如何实现换行?

    public static void main(String[] args) throws IOException {
        //问题1:字节流写数据如何实现换行呢?
        //创建字节流对象
        FileOutputStream fos = new FileOutputStream("fos.txt");

        //写数据
        for (int i = 0; i < 100; i++) {
            fos.write("hello".getBytes());
            //换行
            fos.write("\n".getBytes());
        }

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

  1. 字节流写数据如何实现追加写入呢?
    public static void main(String[] args) throws IOException {
        //问题2:如何追加写入?true追加数据
        FileOutputStream fos1 = new FileOutputStream("fos.txt", true);
        //写数据
        for (int i = 0; i < 100; i++) {
            fos1.write("hello".getBytes());
            //换行
            fos1.write("\n".getBytes());
        }

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

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

FileInputStream : 从文件系统中的文件获取输入字节
需求:把文件fos.txt中的内容读取出来在控制台输出

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

  1. 创建字节输入流对象
  2. 调用字节输入流对象的读数据方法
  3. 释放资源
    public static void main(String[] args) throws IOException {
        //1.创建字节输入流对象
        FileInputStream fis=new FileInputStream("fos.txt");

        //2.调用字节流输入流对象的读数据方法
        //int read(): 从该输入流读取一个字节的数据
        int by;
        while ((by=fis.read())!=-1){
            System.out.println((char) by);
        }

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

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

需求:把文件fos.txt中的内容读取出来在控制台输出
使用字节输入流读数据的步骤:

  1. 创建字节输入流对象
  2. 调用字节输入流对象的读数据方法
  3. 释放资源
    public static void main(String[] args) throws IOException {
        //1.创建字节输入流对象
        FileInputStream fis=new FileInputStream("fos.txt");

        //2.调用字节输入流对象的读数据方法
        //int read(byte[] b):从该输入流读取最多 b.length个字节的数据到一个字节数组
        byte []bys=new byte[1024];//1024及其整数倍
        int len;
        while ((len=fis.read(bys))!=-1){
            String s = new String(bys, 0, len);
            System.out.println(s);
        }
        
        //3.释放资源
        fis.close();
    }

字节缓冲流

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

构造方法:

为什么构造方法需要的是字节流,而不是具体的文件或路径呢?
字节缓冲流仅仅提供缓冲区,而真正的读写数据还得依靠基本的字节流对象进行操作

    public static void main(String[] args) throws IOException {
        //字节缓冲输出流:BufferedOutputStream(OutputStream out)
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));

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

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

    public static void main(String[] args) throws IOException {

        //字节缓冲输入流:BufferedInputStream(InputStream in)
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bos.txt"));

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

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

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


    }

字符流

为什么会出现字符流?
由于字节流操作中文不是特别方便,所以Java就提供字符流
字符流=字节流+编码表

用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因时最终底层操作会自动进行字节拼接成中文,如何识别时中文的呢?
汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数

编码表

计算机中存储的信息都是用二进制数表示的;我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果
按照某种规则,将字符存储到计算机中,称为编码。反之,将存储在计算机中的二进制数按照某种规则解析出来,称为解码。这里强调一下:按照A编码存储,必须按照A编码解析,这样才能显示正确的文本符号。否则就会导致乱码现象。

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

ASCII(American Standard Code for Information Interchange,美国信息交换标准代码):是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)。
基本的ASCII字符集,使用7位表示一个字符,共128字符。ASCII的扩展字符集使用8位表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。

GB2312:简体中文码表。一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,这样大约可以组合包括7000多个简体汉字,此外数学符号、罗马希腊的字母、日文的假名等都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码、这就是常说的“全角”字符,而原来在127号以下的那些就叫“半角”字符了。
GBK:最常用的中文码表。是在GB2312标准的基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等。
GB18030:最新的中文码表。收录汉字70244个,采用多字节编码,每个字可以由1个、2个或4个字节组成。支持中国国内少数民族的文字,同时支持繁体汉字以及日韩汉字等。

Unicode字符集:为了表示任意语言的任意字符而设计,是业界的一种标准,也称为统一码,标准万国码。它最多使用4个字节的数字来表示每个字母、符号,或者文字。有三种编码方案,UTF-8、UTF-16和UTF-32。最为常用的是UTF-8编码。
UTF-8编码可以用来表示Unicode标准中的任意字符,它是电子邮件、网页及其其他存储或传送文字应用中,优先采用的编码。互联网工程小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用一至四个字节为每个字符编码
编码规则:

  1. 128个US-ASCII字符,只需要一个字节编码
  2. 拉丁文等字符,需要二个字节编码
  3. 大部分常用字(含中文),使用三个字节编码
  4. 其他极少数使用的Unicode辅助字符,使用四个字节编码

小结:采用何种规则编码,就要采用对应规则解码,否则就会出现乱码

字符串中的编码解码问题

编码:

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

解码:

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

使用默认编码:

    public static void main(String[] args) {
        //编码
        //1.先定义一个字符串
        String s="中国";
        //2.编码 使用平台默认的字符集编码
        byte[] bytes = s.getBytes();
        System.out.println(Arrays.toString(bytes));
    }

结果如下:

[-28, -72, -83, -27, -101, -67]

使用指定编码:

    public static void main(String[] args) throws UnsupportedEncodingException {
        //编码
        //1.先定义一个字符串
        String s="中国";
        //2.编码 使用指定编码 如GBK
        byte[] bytes = s.getBytes("GBK");
        System.out.println(Arrays.toString(bytes));
    }

打印结果如下:

[-42, -48, -71, -6]

使用默认解码:


    public static void main(String[] args) throws UnsupportedEncodingException {
        //解码
        //1.先定义一个字符串
        String s="中国";
        byte[] bytes = s.getBytes();
        //2.使用默认解码
        String str=new String(bytes);
        System.out.println(str);
    }

打印结果如下:

中国

使用指定字符集解码:


    public static void main(String[] args) throws UnsupportedEncodingException {
        //解码
        //1.先定义一个字符串
        String s="中国";
        //使用GBK字符集编码
        byte[] bytes = s.getBytes("GBK");
        //2.使用GBK字符集解码
        String str=new String(bytes,"GBK");
        System.out.println(str);
    }

打印结果如下:

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

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

字符流中和编码解码问题相关的两个类:
InputStreamReader: 是从字节流到字符流的桥梁;他读取字节,并使用指定的charset将其解码为字符。它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。
OutputStreamWriter: 是从字符流到字节流的桥梁;使用指定的charset将写入的字符编码为字节。它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。

OutputStreamWriter
构造方法:

  1. OutputStreamWriter(OutputStream out):创建一个使用默认字符编码的OutputStreamWriter
  2. OutputStreamWriter(OutputStream out,String charsetName):创建一个使用命名字符集的OutputStreamWriter

使用OutputStreamWriter(OutputStream out)构造方法写数据:

    public static void main(String[] args) throws IOException {
        //1.创建字符流输出对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"));
        //2.写数据
        osw.write("中国");
        //3.关闭
        osw.close();
    }

使用OutputStreamWriter(OutputStream out,String charsetName)构造方法写数据:

    public static void main(String[] args) throws IOException {
        //1.创建字符流输出对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"),"GBK");
        //2.写数据
        osw.write("中国");
        //3.关闭
        osw.close();
    }

InputStreamReader:

  1. InputStreamReader(InputStream in); 创建一个使用默认字符集的InputStreamReader
  2. InputStreamReader(InputStream in,String charsetName); 创建一个使用命名字符集的InputStreamReager

使用InputStreamReader(InputStream in,String charsetName); 构造方法

    public static void main(String[] args) throws IOException {
        //1.创建字符流输出对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"),"GBK");
        //2.写数据
        osw.write("中国");
        //3.关闭
        osw.close();


        InputStreamReader isr=new InputStreamReader(new FileInputStream("osw.txt"),"GBK");
        //一次读取一个字符数据
        int ch;
        while ((ch=isr.read())!=-1){
            System.out.println((char)ch);
        }
        isr.close();
    }

字符流写数据的5种方式
方法名说明
void write(int c)写一个字符
void write(char[] cbuf)写一个字符数组
void write(char[] cbuf,int off, int len)写入字符数组的一部分
void write(String str)写一个字符串
void write(String str, int off, int len)写一个字符串的一部分
  1. 写入一个字符
    public static void main(String[] args) throws IOException {
        //1.创建一个默认字符编码的OutputStreamWriter对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"));
        //2.写一个字符
        osw.write(97);
        //3.刷新流(不刷新时,写入的数据还存在于缓冲区中,刷新后才写入文件)
        osw.flush();
        //4.释放资源(关闭流,会先刷新)
        osw.close();
    }
  1. 写入一个字符数组
        //1.创建一个默认字符编码的OutputStreamWriter对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"));
        //2.写入一个字符数组的数据
        char [] chs={'a','b','c','d','e'};
        //3.写入
        osw.write(chs);
        //4.关闭资源
        osw.close();
  1. 写入部分的字符数组
        //1.创建一个默认字符编码的OutputStreamWriter对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"));
        //2.写入一个字符数组的数据
        char [] chs={'a','b','c','d','e'};
        //3.写入一部分(从索引1往后写3个)
        osw.write(chs,1,3);
        //4.关闭资源
        osw.close();

  1. 写一个字符串
        //1.创建一个默认字符编码的OutputStreamWriter对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"));
        //3.写入一个字符串
        osw.write("abcde");
        //4.关闭资源
        osw.close();
  1. 写入字符串的一部分
        //1.创建一个默认字符编码的OutputStreamWriter对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"));
        //2.写入一个字符串(从索引1往后写3个)
        osw.write("abcde",0,3);
        //3.释放资源
        osw.close();
字符流读数据的2种方式
方法名说明
int read()一次读一个字符数据
int read(char [] cbuf)一次读一个字符数组数据

一次读一个字符数据:

        //1.创建一个默认字符集对象
        InputStreamReader isr=new InputStreamReader(new FileInputStream("osw.txt"));
        //2.读数据
        int ch;
        while ((ch=isr.read())!=-1){
            System.out.println((char)ch);
        }
        //3.释放资源
        isr.close();

一次读一个字符数组数据:

        //1.创建一个默认字符集对象
        InputStreamReader isr=new InputStreamReader(new FileInputStream("osw.txt"));
        //2.读数据
        char[] chs=new char[1024];
        int len;
        while ((len=isr.read(chs))!=-1){
            System.out.println(new String(chs,0,len));
        }
        //3.释放资源
        isr.close();

标签:字符,Java,String,编码,笔记,osw,IO,new,字节
来源: https://blog.csdn.net/dondurma/article/details/112210099