Java基础 IO
创始人
2024-05-17 03:34:54
0

IO流

IO流

  1. 什么是IO流?
    存储和读取数据的解决方案

    I:input

    O:output

    流:像水流一样传输数据

  2. IO流的作用?

    用于读写数据(本地文件,网络)

  3. IO流按照流向可以分类哪两种流?

    输出流:程序 -> 文件

    输入流:文件 -> 程序

  4. IO流按照操作文件的类型可以分类哪两种流?

    字节流:可以操作所有类型的文件

    字符流:只能操作纯文本文件

  5. 什么是纯文本文件?

    用windows系统自带的记事本打开并且能读懂的文件

    txt文件,md文件,xml文件,lrc文件等

    (word, excel不是纯文本文件)

在这里插入图片描述在这里插入图片描述

字节流

1.字节输出流

  • 字节输出流FileOutputStream:操作本地文件的字节输出流,可以把程序中的数据写到本地文件中
    书写步骤:

    • 创建字节输出流对象
    • 写数据
    • 创建资源

    例子:写出一段文字到本地文件中。(暂时不写中文)

    public static void main(String[] args) throws IOException {/** 演示:字节输出流FileOutputStream* 实现需求:写出一段文字到本地文件中。(暂时不写中文)** 实现步骤:*       创建对象*       写出数据*       释放资源* *///1.创建对象//写出 输出流 OutputStream//本地文件    File// 注:FileOutputStream 要抛出异常IOException FileOutputStream fos = new FileOutputStream("myio\\a.txt");//2.写出数据fos.write(97); //a//3.释放资源fos.close();}
    
  • 字节输出流的细节:

    1. 创建字节输出流对象
      细节1:参数是字符串表示的路径或者是File对象都是可以的
      细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的。
      细节3:如果文件已经存在,则会清空文件
    2. 写数据
      细节:write方法的参数是整数,但是实际上写到本地文件中的是整数在ASCII上对应的字符
      如果真的要写数字,就要把每个数字位看成字符,写数字的ASCII码
      ‘9’:57
      ‘7’:55
    3. 释放资源
      每次使用完流之后都要释放资源,否则建立连接的通道不会关闭,占用内存
  • FileOutputStream写数据的3种方式:
    在这里插入图片描述(注意第三种方式的参数可能和你想的不一样,第二个参数是起始索引,第三个参数是长度)

    public static void main(String[] args) throws IOException {/*void write(int b)                       一次写一个字节数据void write(byte[] b)                    一次写一个字节数组数据void write(byte[] b, int off, int len)  一次写一个字节数组的部分数据参数一:数组参数二:起始索引  0参数三:个数      3*///1.创建对象FileOutputStream fos = new FileOutputStream("myio\\a.txt");//2.写出数据//fos.write(97); // a//fos.write(98); // bbyte[] bytes = {97, 98, 99, 100, 101};/* fos.write(bytes);*/fos.write(bytes,1,2);// b c//3.释放资源fos.close();}
    
  • 两个问题:如何换行?如何续写?

    • 换行写:
      再次写出一个换行符就可以了

            windows: \r\nLinux:    \nMac:      \r
      
      • 细节
        在windows操作系统当中,java对回车换行进行了优化。
        虽然完整的是\r\n,但是我们写其中一个\r或者\n,
        java也可以实现换行,因为java在底层会补全。
      • 建议:
        不要省略,还是写全了。
    • 续写:
      如果想要续写,打开续写开关即可
      开关位置:创建对象的第二个参数
      默认false:表示关闭续写,此时创建对象会清空文件
      手动传递true:表示打开续写,此时创建对象不会清空文件

    public static void main(String[] args) throws IOException {/*换行写:再次写出一个换行符就可以了windows: \r\nLinux:    \nMac:      \r细节:在windows操作系统当中,java对回车换行进行了优化。虽然完整的是\r\n,但是我们写其中一个\r或者\n,java也可以实现换行,因为java在底层会补全。建议:不要省略,还是写全了。续写:如果想要续写,打开续写开关即可开关位置:创建对象的第二个参数默认false:表示关闭续写,此时创建对象会清空文件手动传递true:表示打开续写,此时创建对象不会清空文件*///1.创建对象FileOutputStream fos = new FileOutputStream("myio\\a.txt",true);//2.写出数据String str = "kankelaoyezuishuai";byte[] bytes1 = str.getBytes();fos.write(bytes1);//再次写出一个换行符就可以了String wrap = "\r\n";byte[] bytes2 = wrap.getBytes();fos.write(bytes2);String str2 = "666";byte[] bytes3 = str2.getBytes();fos.write(bytes3);//3.释放资源fos.close();}
    

2.字节输入流

  • 字节输出流FileInputStream:操作本地文件的字节输入流,可以把本地文件中的数据读到程序中
    书写步骤:
    • 创建字节输出流对象
      • 细节:如果文件不存在,直接报错
    • 读数据
      • 细节1:一次读一个字节,读出来的数据是在ASCII上对应的数字,如果想显示原内容,可以用(char)强转
      • 细节2:读到文件末尾了,read方法返回-1.
    • 创建资源
      • 每次使用完流必须释放资源

例子:读文本中的数据

public static void main(String[] args) throws IOException {/** 演示:字节输入流FileInputStream* 实现需求:读取文件中的数据。(暂时不写中文)** 实现步骤:*       创建对象*       读取数据*       释放资源* *///1.创建对象FileInputStream fis = new FileInputStream("myio\\a.txt");//2.读取数据int b1 = fis.read();System.out.println((char)b1);int b2 = fis.read();System.out.println((char)b2);int b3 = fis.read();System.out.println((char)b3);int b4 = fis.read();System.out.println((char)b4);int b5 = fis.read();System.out.println((char)b5);int b6 = fis.read();System.out.println(b6);//-1//3.释放资源fis.close();}
  • FileInputStream循环读取

    public static void main(String[] args) throws IOException {/*字节输入流循环读取*///1.创建对象FileInputStream fis = new FileInputStream("myio\\a.txt");//2.循环读取int b;while ((b = fis.read()) != -1) {System.out.println((char) b);}//3.释放资源fis.close();}
    

    问题:不定义变量b可不可以?

    		/** read :表示读取数据,而且是读取一个数据就移动一次指针** */FileInputStream fis = new FileInputStream("myio\\a.txt");//2.循环读取while ((fis.read()) != -1) {System.out.println(fis.read());//98  100  -1}//3.释放资源fis.close();
    

    答:不可以。因为 read读取数据,读取一个数据就移动一次指针,因此调用两次fis.read()后指针移动了两次,不能完整输出数据

  • 文件拷贝
    细节:先打开的后关闭
    (以下代码边读边写,一个字节一个字节读写,效率太低,只能拷贝小文件)

    public static void main(String[] args) throws IOException {/**   练习:*       文件拷贝*       把D:\itheima\movie.mp4拷贝到当前模块下。**   注意:*       选择一个比较小的文件,不要太大。大文件拷贝我们下一个视频会说。****   课堂练习:*       要求统计一下拷贝时间,单位毫秒* */long start = System.currentTimeMillis();//1.创建对象FileInputStream fis = new FileInputStream("D:\\itheima\\movie.mp4");FileOutputStream fos = new FileOutputStream("myio\\copy.mp4");//2.拷贝//核心思想:边读边写int b;while((b = fis.read()) != -1){fos.write(b);}//3.释放资源//规则:先开的最后关闭fos.close();fis.close();long end = System.currentTimeMillis();System.out.println(end - start);}
    

    解决方式: public int read(byte[] buffer) 一次读一个字节数组数据,返回值是读取的字节长度
    如果读到最后不够字节数组的长度了,那么只会读取剩下的字节,返回的是剩下的字节长度。此时数组里面还存在上次读取的字节,这样最后一次就会多拷贝出来一些东西。因此用String str1 = new String(bytes,0,len1)、fos.write(bytes, 0, len)确保最后一次读取的是正确的字节数。

    public static void main(String[] args) throws IOException {/*public int read(byte[] buffer)      一次读一个字节数组数据*///1.创建对象FileInputStream fis = new FileInputStream("myio\\a.txt");//2.读取数据byte[] bytes = new byte[2];//一次读取多个字节数据,具体读多少,跟数组的长度有关//返回值:本次读取到了多少个字节数据int len1 = fis.read(bytes);System.out.println(len1);//2String str1 = new String(bytes,0,len1);System.out.println(str1);int len2 = fis.read(bytes);System.out.println(len2);//2String str2 = new String(bytes,0,len2);System.out.println(str2);int len3 = fis.read(bytes);System.out.println(len3);// 1String str3 = new String(bytes,0,len3);System.out.println(str3);// ed//3.释放资源fis.close();}
    

    拷贝大文件:

    public static void main(String[] args) throws IOException {/**   练习:*       文件拷贝*       把D:\itheima\movie.mp4 (16.8 MB) 拷贝到当前模块下。** */long start = System.currentTimeMillis();//1.创建对象FileInputStream fis = new FileInputStream("D:\\itheima\\movie.mp4");FileOutputStream fos = new FileOutputStream("myio\\copy.mp4");//2.拷贝int len;byte[] bytes = new byte[1024 * 1024 * 5];while((len = fis.read(bytes)) != -1){fos.write(bytes,0,len);}//3.释放资源fos.close();fis.close();long end = System.currentTimeMillis();System.out.println(end - start);}
    
  • IO流try…catch异常处理注意事项(了解):释放资源语句要放在finally里确保一定会被执行。
    无论try里有没有异常,finally里的代码一定会被执行,除非虚拟机停止

public static void main(String[] args) {/**    利用try...catch...finally捕获拷贝文件中代码出现的异常*///1.创建对象FileInputStream fis = null;FileOutputStream fos = null;try {fis = new FileInputStream("D:\\itheima\\movie.mp4");fos = new FileOutputStream("myio\\copy.mp4");//2.拷贝int len;byte[] bytes = new byte[1024 * 1024 * 5];while((len = fis.read(bytes)) != -1){fos.write(bytes,0,len);}} catch (IOException e) {//e.printStackTrace();} finally {//3.释放资源if(fos != null){try {fos.close();} catch (IOException e) {e.printStackTrace();}}//如果创建fis/fos的路径不存在时就不会创建字节流,这样fis和fos就还是null//如果不加以判断就会出现空指针异常的错误,所以要加个非空判断if(fis != null){try {//fis.close()也会有异常出现,所以在finally里又嵌套了一个try catch捕获异常fis.close();} catch (IOException e) {e.printStackTrace();}}}}

上述代码的简化:AutoCloseable,不需要写finally,自动释放
JDK7:实现了AutoCloseable的类才能在try()中创建对象
JDK9:JDK7不好阅读,所以把创建流对象放外面了
在这里插入图片描述

public static void main(String[] args) {/***    JDK7:IO流中捕获异常的写法**      try后面的小括号中写创建对象的代码,*          注意:只有实现了AutoCloseable接口的类,才能在小括号中创建对象。*     try(){**     }catch(){**     }** */try (FileInputStream fis = new FileInputStream("D:\\itheima\\movie.mp4");FileOutputStream fos = new FileOutputStream("myio\\copy.mp4")) {//2.拷贝int len;byte[] bytes = new byte[1024 * 1024 * 5];while ((len = fis.read(bytes)) != -1) {fos.write(bytes, 0, len);}} catch (IOException e) {e.printStackTrace();}}

字符集

计算机存储规则:任意数据都是以二进制形式存储的
字节:计算机中最小的存储单位,1字节(byte)=8比特(bit)
存储英文一个字节就够了(ASCII码只有128个)

  • ASCII码存储规则:在这里插入图片描述在这里插入图片描述

咱汉字怎么存?

1、GB2312字符集,1980年发布,1981年5月1日实施的简体中文汉字编码国家标准。收录7445个图形字符,其中包括6763个简体汉字

2、BIG5字符集:台湾地区繁体中文标准字符集,共收录13053个中文字,1984年实施。

3、GBK字符集,2000年3月17日发布,收录21003个汉字。

包含国家标准GB13000-1中的全部中日韩汉字,和BIG5编码中的所有汉字。

windows系统默认使用的就是GBK。系统显示:ANSI

4、Unicode字符集:国际标准字符集,它将世界各种语言的每个字符定义一个唯一的编码,以满足跨语言、跨平台的文本信息转换。

简体中文版Windows用GBK字符集。GBK字符集完全兼容ASCII字符集。

  • GBK存储规则:
    在这里插入图片描述
    在这里插入图片描述制定上述规则的原因:
    规则1:2个字节是2^16=65535,能容纳所有汉字。一个字节不够用,三个字节浪费,两个字节刚刚好。
    规则2:最高位是1还是0用于区分中文还是英文。
    如:下面三个字节很容易看出来是一个一个汉字和一个英文
    10111010 10111010 01100001

在这里插入图片描述

总结:
1.在计算机中,任意数据都是以二进制的形式来存储的
2.计算机中最小的存储单元是一个字节
3.ASCII字符集中,一个英文占一个字节
4.简体中文版Windows,默认使用GBK字符集
5. GBK字符集完全兼容ASCII字符集
一个英文占一个字节,二进制第一位是0
一个中文占两个字节,二进制高位字节的第一位是1

1990年,国际组织研发了Unicode编码来同一各国编码。

  • Unicode编码
    UTF-16:16个bit(2字节)存储(浪费空间)
    UTF-32:32个bit(4字节)存储(浪费空间)
    UTF-8:1~4个字节保存。不同的语言用不同字节数保存。在UTF-8编码中,英文占1个字节,中文占3个字节。中文第一个字节的首位是1,英文是0。
    在这里插入图片描述
    在这里插入图片描述
    问:1、UTF-8是一个字符集吗?
    不是,UTF-8是Unicode字符集的一种编码方式。
    2、以下Unicode字符集UTF-8编码规则,有几个中文几个英文?
    01001010 01100001 01110110 01100001 4个英文
    01001010 01001010 11100110 11001000 11100001 2个英文1个中文

乱码出现的原因:
读取数据时未读完整个汉字
编码和解码时的方式不统一

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
修复 爱普生 EPSON L4... L4151 L4153 L4156 L4158 L4163 L4165 L4166 L4168 L4...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...