Java27字节/字符流:IO流(内存为中心)

Posted 码农编程录

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java27字节/字符流:IO流(内存为中心)相关的知识,希望对你有一定的参考价值。


1.FileOutputStream两个构造:OIWR

8个电子元件组在一起表示字符a即一个byte,一般bit不会用就像一分钱一样不用,所以一般最小单位字节
在这里插入图片描述
jdk8前接口里方法都是抽象方法。jdk8后加入静态和默认方法,除了函数式编程很少见到接口里静态和默认方法。抽象类不能实例化,没法创建对象,没法调它的普通方法。所以在四个抽象类下面各学4个子类File…(因为java里数据用File类来表示)。
在这里插入图片描述

package com.itheima01.outputstream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
/*
*   FileOutStream的构造方法。这里的stream和lambda里stream没有一点关系
*       1. FileOutputStream(File file)
		2. FileOutputStream(String name) throws FileNotFoundException
 
		fos创建的时候需要跟一个路径进行绑定(将会写出数据)
				
		构造的特点:  1. 如果路径文件不存在,则新建
		            2. 如果路径文件存在,则覆盖(无论路径文件是否存在,创建一个新的覆盖)
		               异常处理 -> 待会详细的写一遍
		           3. 如果路径的父目录不存在, 就会抛出FileNotFoundException
		
		结论:  1. 一般使用FileOutputStream(String name)构造,快捷
		      2. 但是如果不能保证父目录是否存在,就用FileOutputStream(File file)
*/
public class Demo01 {
    public static void main(String[] args) throws FileNotFoundException {
//        FileOutputStream fos = new FileOutputStream("dir/a.txt");

		//如下解决上面父路径不存在不能创建缺点
        File file = new File("aaa/dir/a.txt"); //1. 判断file的父目录aaa/dir/是否存在        
        File parentFile = file.getParentFile(); 
        if(!parentFile.exists()){            
            parentFile.mkdirs(); //2. 如果不存在,则创建多级目录
        }
        FileOutputStream fos = new FileOutputStream(file); //必须有这一行才创建出文件
        System.out.println("创建成功");
    }
}
//两种创建文件方式
//1.
File file = new File("d:/a.txt"); //只创建File类路径实例
file.createNewFile(); //必须要执行才创建
//2.
File file = new File("d:/a.txt");
FileOutputStream outputStream =new FileOutputStream(file); //这行可以创建出一个空文件了
outputStream.write(123);
outputStream.close();
outputStream.flush();//必须刷新文件才有内容

2.OutputStream的基本方法:int4,char2,追加和换行

package com.itheima01.outputstream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/*
* 1. OutputStream 抽象类,是表示输出字节流的所有类的超类
		1. close() :关闭此输出流并释放与此流相关联的任何系统资源。
		2. write(byte[] b) :将 b.length字节从指定的字节数组写入此输出流。
		3. write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
		4. write(int b) :将指定的字节输出流
*/
public class Demo02 {
    public static void main(String[] args) throws IOException { //FileNotFoundException父类是IOException
        FileOutputStream fos = new FileOutputStream("a.txt");       
        fos.write(97); // ASCII码表,a.txt内容里多了一个a。 //1. write(int b) : 一次写一个字节
        fos.write('a'); //aa

        byte[] array = {65,66,67,68,69}; //2. write(byte[] b) : 一次写一个字节数组
        fos.write(array); //aaABCDE
        
        fos.write(array,1,3); //aaABCDEBCD (最后多了BCD 3个字母) (1是array从66即B开始)  //3.write(byte[] b, int offset, int len): 一次写一个字节数组的一部分 //offset(偏移量):从第几个开始
                
        fos.close(); //close()本身有个io编译异常,流用完要关掉, 释放资源,流横跨内存和硬盘开销大,所以要关
    }
}

Java:因为是跨平台的,无论在哪里,int都是四个字节。因为字符是用Unicode编码的,所以char是两个字节(C/C++中char始终都是一个字节)。
在这里插入图片描述
在这里插入图片描述

package com.itheima01.outputstream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
/*
    FileOutputStream(String name, boolean append) : 数据追加
        1. append = true : 往原文件追加内容,不会覆盖了
    
    换行
        1. windows : \\r\\n
        2. unix : \\n
        System.lineSeparator() : 根据不同的系统,返回不同的换行符 (跨平台)
*/
public class Demo03 {
    public static void main(String[] args) throws IOException {
//        FileOutputStream fos = new FileOutputStream("a.txt"); //会覆盖原内容
        FileOutputStream fos = new FileOutputStream("a.txt",true); //不覆盖原内容
//        fos.write(48); //尾部追加一个0

//1111111111111111111111111111111111111111111111111111111111111111111111111111
//        fos.write("\\r\\n".getBytes());  //win
        String line = System.lineSeparator();
        fos.write(line.getBytes());
        
//111111111111111111111111111111111111111111111111111111111111111111111111111
        String str = "hello,byebye!";
        byte[] bytes = str.getBytes();
        fos.write(bytes);
        fos.close();
    }
}

3.FileInputStream两个构造:一次读一个字节或字节数组

package com.itheima02.intputstream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
/*
  FileInputStream 构造 (读:硬盘流到内存),以内存为中心,如果文件不存在, 则抛出FileNotFoundException
		1. FileInputStream(File file)
		2. FileInputStream(String name)
*/
public class Demo01 {
    public static void main(String[] args) throws FileNotFoundException {
//        FileInputStream fis = new FileInputStream("a.txt"); //a.txt在FileOutputStream已创建
        FileInputStream fis = new FileInputStream(new File("a.txt"));//不会创建文件,和上行一样
        System.out.println(fis); //java.io.FileInputStream@6d6f6e28
    }
}
package com.itheima02.intputstream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
*  InputStream 抽象类是表示字节输入流的所有类的超类
		1. void close() :关闭此输入流并释放与此流相关联的任何系统资源。
		2. int read() : 从输入流读取数据的下一个字节。
		3. int read(byte[] b) : 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。
*/
public class Demo02 {
    public static void main(String[] args) throws IOException {
//        method01();

        FileInputStream fis = new FileInputStream("a.txt");         
      /*  int content = -1 ;  //=0也可以,都会被覆盖掉
        while(content != -1){
            content = fis.read();
            System.out.println(content);
        }*/
        
       int content = -1;
       while((content = fis.read()) != -1){ //这样和上面区别是,这不会多打印-1
           System.out.println(content);
        }		
        fis.close();
    }
    
//11111111111111111111111111111111111111111111111111111111111111111111111111111111
    private static void method01() throws IOException {
        FileInputStream fis = new FileInputStream("a.txt");//已存在a.txt且里面有abc        
        int content = 0 ;        
        content = fis.read();//向后移动一位,并返回当前元素(迭代器) //int read() : 一次读一个字节
        System.out.println(content);//97
        
        content = fis.read();
        System.out.println(content);//98
        
        content = fis.read();
        System.out.println(content);//99
        
        content = fis.read(); // 如果后面已经到文件的末尾,不会再移动直接返回-1
        System.out.println(content);//-1  //-1不在ascii表上,-1表示没有意义
        fis.close();
    }
}
package com.itheima02.intputstream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
/*
*   int read(byte[] b) : 一次读一个字节数组
*       1. 参数 byte[] : 用来存放字节流读取到的数据
*       2. 返回值 int : 本次读取到的字节个数
*            返回值 =  数组长度 < 文件剩余的字节数量 ? 数组长度 : 文件剩余字节数量
*       迭代器
*/
public class Demo03 {
    public static void main(String[] args) throws IOException {
//        method01();

        FileInputStream fis = new FileInputStream("a.txt");
        byte[] buffer = new byte[3];// {0,0,0}
        int length = 0;

        /*while(length != -1){												//A
           length = fis.read(buffer);
            System.out.println(length + "->" + Arrays.toString(buffer));
        }*/

        while((length = fis.read(buffer)) != -1){
//            System.out.println(length + "->" + Arrays.toString(buffer)); //B
            String str = new String(buffer, 0, length); 				   //C
            System.out.println(str);
        }
        fis.close();
    }

//111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    private static void method01() throws IOException {
        FileInputStream fis = new FileInputStream("a.txt"); //a.txt里内容:abcdefg
        byte[] buffer = new byte[3];//{0,0,0}  //System.out.println(Arrays.toString(buffer));  //[0,0,0] //Arrays工具类

        int length = -1;
        length = fis.read(buffer); //框子只有3个位置 
        System.out.println(length + "->" + Arrays.toString(buffer)); //3->[97,98,99]
        
        length = fis.read(buffer);
        System.out.println(length + "->" + Arrays.toString(buffer));// length=3,def
        
        length = fis.read(buffer);
        System.out.println(length + "->" + Arrays.toString(buffer));//length=1,gef,ef还是上面的没覆盖

        length = fis.read(buffer);
        System.out.println(length + "->" + Arrays.toString(buffer));// length=-1,gef
        fis.close();
    }
}

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

4.文件复制(重要):fis.read,fos.write

package com.itheima03.copy;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/*
*   文件复制: 先读后写
*       1. 先创建一个输入流 指向  原文件
*       2. 再创建一个输出流 指向  副本
*       一个读,另一个写
*    A. 一次读写一个字节
*    B. 一次读写一个字节数组
*/
public class CopyDemo01 {
    public static void main(String[] args) throws IOException {
//        method01(); // 1148ms
        method02();//59ms 
        
//1111111111111111111111111111111111111111111111111111111111111111111111111      
      /*  long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1024*4000; i++) {  //循环不耗时,打印耗时,打印就是IO流
        }
        long endTime = System.currentTimeMillis(); 
        System.out.println(endTime - startTime); // 2ms*/
    }

//111111111111111111111111111111111111111111111111111111111一次读写一个字节数组 (重要)
    private static void method02() throws IOException {
        long startTime = System.currentTimeMillis();
        FileInputStream fis = new FileInputStream("柳岩.jpg");
        FileOutputStream fos = new FileOutputStream("ly2.jpg");
  
        byte[] buffer = new byte[1024]; //1kb
        int length = -1;
        while((length = fis.read(buffer)) != -1){
            fos.write(buffer,0,length);
        }
        fos.close();
        fis.close();
   
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - startTime);
    }

//1111111111111111111111111111111111111111111111111111111111111一次读写一个字节
    private static void method01() throws IOException {
        long startTime = System.currentTimeMillis();
        FileInputStream fis = new FileInputStream("柳岩.jpg"); //已存在
        FileOutputStream fos = new FileOutputStream("ly.jpg");
 
        int content = -1;
        while((content = fis.read()) != -1){
            fos.write(content);
        }        
        fos.close(); 
        fis.close(); //先打开的后关闭     
                
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - startTime);
    }
}

在这里插入图片描述

5.编码表与字符流:编码解码和乱码

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
将如上"啊"改为"瞭",并放开gb2312和gbk,如下打印3F就是ascii码中63即?即解码失败。
在这里插入图片描述
在这里插入图片描述
如下:1.用文件浏览器(编码B)或IDE(编码B)打开一个文件(编码A)会乱码。
2.程序读取编码A的数据并且将转成字符串,但是使用的编码B转,也会乱码。
3.网页浏览器,服务端请求的数据的编码是A,但是浏览器展示用的编码B,也会乱码。
在这里插入图片描述
1.如下在浏览器地址栏ctrl+c再ctrl+v。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2.如下按gb2312拿字节码,用utf-8生成文字,强制编码出错。
在这里插入图片描述
在这里插入图片描述
3.如下1.txt中10个"啊",utf8中每个汉字对应3字节,所以30个字节。
在这里插入图片描述
byte数组长度刚好把一个字切开了,如果是英文文件就无所谓,因为一个英文ascii码就是一个字节。
在这里插入图片描述
在这里插入图片描述
4.如下是爬网页数据。
在这里插入图片描述
如下改进,未出现乱码。
在这里插入图片描述

package com.itheima04.chard;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/*
*   字符流 = 字节流 + 编码表【为什么有了编码表后有了动态判断能力?】
*   FileReader = FileInputStream + 编码表 (字典:碰到中文1次读3个字节)
*   
* 编码表: 计算机底层0和1 -> 字符(像素..)。字符集charset(字符编码表): 二进制和字符 相互转换的一种规则。
*      1. ASCII码表 : 128个数字(0~127,2的7次方=128)。0 000 0000 ~ 0 111 1111  (一个字节后7位占了)
*      2. ISO-8859-1 : 欧码(拉丁码)  256个。0000 0000 ~ 1111 1111  (一个字节)。Tomcat软件 默认编码表
* 
*      3. GBK (国标扩)是GB2312的扩展:
*        兼容ASCII码表即承认英文字母占一个字节, 一个汉字占两个字节(2的16次方,0 ~ 65535)。
* 
*      4. 国际 Unicode (universal code):utf-8 : 兼容ASCII表, 其次 归纳其他主流文字
*               1. 一个英文一个字节
*               2. 一个中文三个字节(如果有1000个字用GBK只有2kb的大小,用utf-8占3kb)
* 
*      总结: ASCII码表 : 0,A,a
*           GBK: windows中文简体默认(GBK)
*           UTF-8: 开发常用!!!(ideal里默认UTF-8)
*/
public class CharDemo {
    public static void main(String[] args) throws IOException {        
        FileInputStream fis = new FileInputStream("a.txt"); //字节流:一个英文一个字节 , 一个中文3个字节。如“中国人”显示9个数字    
      // FileReader fis = new FileReader("a.txt"); //字符流:一次读一个字符(英文只读1字节, 中文只读3个字节,动态判断)。如“中国人”显示3个数字
       
        int content = -1;
        while((content = fis.read()) != -1){
            System.out.println(content); //打印换行
        }
        fis.close();
    }
}

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

package com.itheima04.chard;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
//字符流: 赋值文本文件,不能复制图片。
public class CharDemo02 {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("a.txt"); //已存在
        FileWriter fw = new FileWriter("b.txt");
        
        int length = -1;
        char[] buffer = new char[1024];
        while((length = fr.read(buffer)) != -1){
            fw.write(buffer,0,length);
        }
        fw.close();
        fr.close(); //结果:b.txt和a.txt一样,原来没有b.txt这个文件
    }
}

以上是关于Java27字节/字符流:IO流(内存为中心)的主要内容,如果未能解决你的问题,请参考以下文章

IO流-----(字节流)

IO流

Java IO字符流

Java IO操作

字节流 字符流 - 12

理解Java之IO流