Java基础⑤-File类、IO流、字节缓冲流、字符流、字符缓冲流、序列化与反序列化

1、File类

1.1 File类概述和构造方法

1.2 File类创建功能

public boolean createNewFile()当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空 文件
public boolean mkdir()创建由此抽象路径名命名的目录
public boolean mkdirs()创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录
/*
    File类创建功能:
        public boolean createNewFile():当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件
            如果文件不存在,就创建文件,并返回true
            如果文件存在,就不创建文件,并返回false

        public boolean mkdir():创建由此抽象路径名命名的目录
            如果目录不存在,就创建目录,并返回true
            如果目录存在,就不创建目录,并返回false

        public boolean mkdirs():创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录
            自己补齐
 */
public class FileDemo02 {
    public static void main(String[] args) throws IOException {
        //需求1:我要在E:\\itcast目录下创建一个文件java.txt
        File f1 = new File("E:\\itcast\\java.txt");
        System.out.println(f1.createNewFile());
        System.out.println("--------");

        //需求2:我要在E:\\itcast目录下创建一个目录JavaSE
        File f2 = new File("E:\\itcast\\JavaSE");
        System.out.println(f2.mkdir());
        System.out.println("--------");

        //需求3:我要在E:\\itcast目录下创建一个多级目录JavaWEB\\HTML
        File f3 = new File("E:\\itcast\\JavaWEB\\HTML");
//        System.out.println(f3.mkdir());
        System.out.println(f3.mkdirs());
        System.out.println("--------");

        //需求4:我要在E:\\itcast目录下创建一个文件javase.txt
        File f4 = new File("E:\\itcast\\javase.txt");
//        System.out.println(f4.mkdir());	//此时创建出来的是目录
        System.out.println(f4.createNewFile());
    }
}

1.2 File类判断和获取功能

public class FileDemo04 {
    public static void main(String[] args) {
        //创建一个File对象
        File f = new File("myFile\\java.txt");

//        public boolean isDirectory():测试此抽象路径名表示的File是否为目录
//        public boolean isFile():测试此抽象路径名表示的File是否为文件
//        public boolean exists():测试此抽象路径名表示的File是否存在
        System.out.println(f.isDirectory());
        System.out.println(f.isFile());
        System.out.println(f.exists());

//        public String getAbsolutePath():返回此抽象路径名的绝对路径名字符串
//        public String getPath():将此抽象路径名转换为路径名字符串
//        public String getName():返回由此抽象路径名表示的文件或目录的名称
        System.out.println(f.getAbsolutePath());    // E:\whey\myFile\java.txt
        System.out.println(f.getPath());    // myFile\java.txt
        System.out.println(f.getName());    // java.txt
        System.out.println("--------");

//        public String[] list():返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
//        public File[] listFiles():返回此抽象路径名表示的目录中的文件和目录的File对象数组
        File f2 = new File("E:\\itcast");

        String[] strArray = f2.list();
        for(String str : strArray) { //文件和目录的名称
            System.out.println(str);
        }
        System.out.println("--------");

        File[] fileArray = f2.listFiles();
        for(File file : fileArray) {    // 绝对路径
//            System.out.println(file);
//            System.out.println(file.getName());
            if(file.isFile()) {
                System.out.println(file.getName());
            }
        }
    }
}

1.2 File类删除功能

/*
    File类删除功能:
        public boolean delete():删除由此抽象路径名表示的文件或目录
 */
public class FileDemo03 {
    public static void main(String[] args) throws IOException {
//        File f1 = new File("E:\\itcast\\java.txt");
        //需求1:在当前模块目录下创建java.txt文件
        File f1 = new File("myFile\\java.txt");
//        System.out.println(f1.createNewFile());

        //需求2:删除当前模块目录下的java.txt文件
        System.out.println(f1.delete());
        System.out.println("--------");

        //需求3:在当前模块目录下创建itcast目录
        File f2 = new File("myFile\\itcast");
//        System.out.println(f2.mkdir());

        //需求4:删除当前模块目录下的itcast目录
        System.out.println(f2.delete());
        System.out.println("--------");

        //需求5:在当前模块下创建一个目录itcast,然后在该目录下创建一个文件java.txt
        File f3 = new File("myFile\\itcast");
//        System.out.println(f3.mkdir());
        File f4 = new File("myFile\\itcast\\java.txt");
//        System.out.println(f4.createNewFile());

        //需求6:删除当前模块下的目录itcast
        System.out.println(f4.delete());
        System.out.println(f3.delete());
    }
}

2、IO流

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

IO流的使用场景:
        如果操作的是纯文本文件,优先使用字符流
        如果操作的是图片、视频、音频等二进制文件。优先使用字节流
        如果不确定文件类型优先使用字节流。字节流是万能的流

2.1 字节流数据-FileOutputStream

字节流抽象基类
        InputStream:这个抽象类是表示字节输入流的所有类的超类(父类)
        OutputStream:这个抽象类是表示字节输出流的所有类的超类
        子类名特点:子类名称都是以其父类名作为子类名的后缀
字节输出流
        FileOutputStream(String name):创建文件输出流以指定的名称写入文件

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

        创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
        调用字节输出流对象的写数据方法
        释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)

/*
    FileOutputStream:文件输出流用于将数据写入File
        FileOutputStream​(String name):创建文件输出流以指定的名称写入文件
 */
public class FileOutputStreamDemo01 {
    public static void main(String[] args) throws IOException {
        //创建字节输出流对象
        //FileOutputStream​(String name):创建文件输出流以指定的名称写入文件
        FileOutputStream fos = new FileOutputStream("myByteStream\\fos.txt");
        /*
            做了三件事情:
                A:调用系统功能创建了文件
                B:创建了字节输出流对象
                C:让字节输出流对象指向创建好的文件
         */

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

        //最后都要释放资源
        //void close​():关闭此文件输出流并释放与此流相关联的任何系统资源。
        fos.close();
    }
}

字节流写数据的三种方式【应用】write

将 len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流 一 次写一个字节数组的部分数据

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

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/*
    构造方法:
        FileOutputStream​(String name):创建文件输出流以指定的名称写入文件
        FileOutputStream​(File file):创建文件输出流以写入由指定的 File对象表示的文件

    写数据的三种方式:
        void write​(int b):将指定的字节写入此文件输出流
        一次写一个字节数据

        void write​(byte[] b):将 b.length字节从指定的字节数组写入此文件输出流
        一次写一个字节数组数据

        void write​(byte[] b, int off, int len):将 len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流
        一次写一个字节数组的部分数据
*/
public class FileOutputStreamDemo02 {
    public static void main(String[] args) throws IOException {
        //FileOutputStream​(String name):创建文件输出流以指定的名称写入文件
        FileOutputStream fos = new FileOutputStream("myByteStream\\fos.txt");

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

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

//        void write​(byte[] b):将 b.length字节从指定的字节数组写入此文件输出流
        byte[] bys = {97, 98, 99, 100, 101};
        fos.write(bys);    //文件中写入:abcde
        //byte[] getBytes​():返回字符串对应的字节数组
        byte[] bys = "abcde".getBytes();
        fos.write(bys);    //文件中写入的也是:abcde

        //void write​(byte[] b, int off, int len):将 len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流
        byte[] bys = {97, 98, 99, 100, 101};
        fos.write(bys,0,bys.length);    //文件中写入:abcde
        fos.write(bys,1,3);    //文件中写入:bcd

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

 字节流写数据如何实现换行[不同操作系统,换行符不一样]

windows\r\n
linux\n
mac\r

字节流写数据如何实现追加写入-FileOutputStream

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

package com.itheima_01;

import java.io.FileOutputStream;
import java.io.IOException;

/*
    字节流写数据的两个小问题:
        1:字节流写数据如何实现换行呢?
            window:\r\n
            linux:\n
            mac:\r

        2:字节流写数据如何实现追加写入呢?
            public FileOutputStream​(String name,boolean append)
                创建文件输出流以指定的名称写入文件。
                如果第二个参数为true ,则字节将写入文件的末尾而不是开头
 */
public class FileOutputStreamDemo03 {
    public static void main(String[] args) throws IOException {
        //创建字节输出流对象
//        FileOutputStream fos = new FileOutputStream("myByteStream\\fos.txt");
		//创建字节输出流对象、追加写入
        FileOutputStream fos = new FileOutputStream("myByteStream\\fos.txt",true);

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

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

2.2 字节流数据-FileInputStream

2.2.1 一次读一个字节数据 read()

字节输入流
        FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream ,该文件由文件系统中的路径名name命名
字节输入流读取数据的步骤
        创建字节输入流对象
        调用字节输入流对象的读数据方法
        释放资源

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

    FileInputStream:从文件系统中的文件获取输入字节
        FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名
 */
public class FileInputStreamDemo01 {
    public static void main(String[] args) throws IOException {
        //创建字节输入流对象
        //FileInputStream(String name)
        FileInputStream fis = new FileInputStream("myByteStream\\fos.txt");

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

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

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

        //再多读取两次
        by = fis.read();
        System.out.println(by);
        by = fis.read();
        System.out.println(by);

        //如果达到文件的末尾, -1
        */

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

        //优化上面的程序
        int by;
        /*
            fis.read():读数据
            by=fis.read():把读取到的数据赋值给by
            by != -1:判断读取到的数据是否是-1
         */
        while ((by=fis.read())!=-1) {
            System.out.print((char)by);
        }


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

字节流复制文本文件

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/*
    需求:
        把“E:\\itcast\\窗里窗外.txt”复制到模块目录下的“窗里窗外.txt”

        数据源:
            E:\\itcast\\窗里窗外.txt --- 读数据 --- InputStream --- FileInputStream
        目的地:
            myByteStream\\窗里窗外.txt --- 写数据 --- OutputStream --- FileOutputStream

    思路:
        1:根据数据源创建字节输入流对象
        2:根据目的地创建字节输出流对象
        3:读写数据,复制文本文件(一次读取一个字节,一次写入一个字节)
        4:释放资源
 */
public class CopyTxtDemo {
    public static void main(String[] args) throws IOException {
        //根据数据源创建字节输入流对象
        FileInputStream fis = new FileInputStream("E:\\itcast\\窗里窗外.txt");
        //根据目的地创建字节输出流对象
        FileOutputStream fos = new FileOutputStream("myByteStream\\窗里窗外.txt");

        //读写数据,复制文本文件(一次读取一个字节,一次写入一个字节)
        int by;
        while ((by=fis.read())!=-1) {
            fos.write(by);
        }

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

2.2.2 一次读一个字节数组数据

 一次读一个字节数组的方法 public int read(byte[] b):从输入流读取最多b.length个字节的数据 返回的是读入缓冲区的总字节数,也就是实际的读取字节个数

import java.io.FileInputStream;
import java.io.IOException;

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

        //调用字节输入流对象的读数据方法
        //int read​(byte[] b):从该输入流读取最多 b.length个字节的数据到一个字节数组
        /*
        byte[] bys = new byte[5];

        //第一次读取数据
        int len = fis.read(bys);
        System.out.println(len);
        //String​(byte[] bytes)
//        System.out.println(new String(bys));    //字节数组 转 字符串
        System.out.println(new String(bys,0,len));

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

        //第三次读取数据
        len = fis.read(bys);
        System.out.println(len);
        //String​(byte[] bytes, int offset, int length)
        System.out.println(new String(bys,0,len));

        //再多读取两次
        len = fis.read(bys);
        System.out.println(len);
        len = fis.read(bys);
        System.out.println(len);
        */

        /*
            hello\r\n
            world\r\n

            第一次:hello
            第二次:\r\nwor
            第三次:ld\r\nr

         */

        byte[] bys = new byte[1024]; //1024及其整数倍
        int len;
        while ((len=fis.read(bys))!=-1) {
            System.out.print(new String(bys,0,len));    //new String(bys,0,len)字节数组 转 字符串
        }

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

字节流复制图片【应用】

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/*
    需求:
        把E:\\itcast\\mn.jpg复制到模块目录下的mn.jpg

    思路:
        1:根据数据源创建字节输入流对象
        2:根据目的地创建字节输出流对象
        3:读写数据,复制图片(一次读取一个字节数组,一次写入一个字节数组)
        4:释放资源
 */
public class CopyJpgDemo {
    public static void main(String[] args) throws IOException {
        //根据数据源创建字节输入流对象
        FileInputStream fis = new FileInputStream("E:\\itcast\\mn.jpg");
        //根据目的地创建字节输出流对象
        FileOutputStream fos = new FileOutputStream("myByteStream\\mn.jpg");

        //读写数据,复制图片(一次读取一个字节数组,一次写入一个字节数组)
        byte[] bys = new byte[1024];
        int len;
        while ((len=fis.read(bys))!=-1) {
            fos.write(bys,0,len);
        }

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

3、字节缓冲流-lBufferOutputStream、 lBufferedInputStream

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

/*
	字节缓冲流:
		BufferOutputStream
		BufferInputStream
	构造方法:
		字节缓冲输出流:BufferOutputStream(OutputStream out)
		字节缓冲输入流:BufferInputStream(InputSream in)
*/

public class BufferStreamDemo{
	public static void main(String[] args)throws IOException{
		//字节缓冲输出流:BufferOutputStream(OutputStream out)
		/*
		FileOutputStream fos=new FileOutputStream("myByteStream\\bos.txt");
		BufferOutputStream bos=new BufferOutputStream(fos);
		与下一句等价*/
		BufferOutputStream bos=new BufferOutputStream(new FileOutputStream("myByteStream\\bos.txt"));
		//写数据
		bos.write("hello\r\n".getBytes());
		bos.write("world\r\n".getBytes());
		
		bos.close();
		
		//字节缓冲输入流:BufferInputStream(InputSream in)
		BufferInputStream bis=new BufferInputStream(new FileInputStream("myByteStream\\bos.txt"));
		
		//一次读取一个字节数据
		/*
		int by;
		while((by=bis.read())!=-1){
			System.out.print((char)by);
		}
		*/
		
		//一次读取一个字节数组数据
		byte[] bys=new byte[1024];
		int len;
		while((len=fis.read(bys))!=-1){
			System.out.print(new String(bys,0,len));
		}
		
		bis.close();
	}
}

字节流复制视频

/*
	需求:
	把“E:\\itcast\\字节流复制图片.avi”复制到模块目录下的字节流复制图片.avi
	
	思路:
		1 :根据数据源创建字节输入流对象
		2 :根据目的地创建字节输出流对象
		3:读写数据,复制图片(一次读取一个字节数组,一次写入一个字节数组)
		4:释放资源
	
	四种方式实现复制视频,并记录每种方式复制视频的时间
		1:基本字节流一次读写一个字节
		2:基本字节流一次读写一个字节数组
		3:字节缓冲流一次读写一个字节
		4:字节缓冲流一次读写一个字节数组
*/
public class CopyAviDemo{
	public static void main(String[] args)throws IOException{
		//记录开始时间
		long startTime=System.currentTimeMills();
		
		//复制视频
		method1();
		method2();
		method3();
		method4();
		
		//记录结束时间
		long endTime=System.currentTimeMills();
		System.out.println("共耗时:"+(endTime-startTime));
		
	}
}
//基本字节流一次读写一个字节
public static void method1()throws IOException{
	FileInputStream fis=new FileInputStream("E:\\itcast\\字节流复制图片.avi");
	FileOutputStream fos=new FileOutputStream("myByteStream\\字节流复制图片.avi");
	
	int by;
	while((by=fis.read())!=-1){
		fos.write(by);
	}
	fis.close();
	fos.close();
}

//基本字节流一次读写一个字节数组
public static void method2()throws IOException{
	FileInputStream fis=new FileInputStream("E:\\itcast\\字节流复制图片.avi");
	FileOutputStream fos=new FileOutputStream("myByteStream\\字节流复制图片.avi");
	
	byte[] bys=new byte[1024];
	int len;
	while((len=fis.read(bys))!=-1){
		fos.write(bys,0,len);
	}
	
	fis.close();
	fos.close();
}

//字节缓冲流一次读写一个字节
public static void method3()throws IOException{
	BufferInputStream bis=new BufferInputStream(new FileInputStream("E:\\itcast\\字节流复制图片.avi"));
	BufferOutputStream bos=new BufferOutputStream(new FileOutputStream("myByteStream\\字节流复制图片.avi"));
	
	int by;
	while((by=bis.read())!=-1){
		bos.write(by);
	}
	bis.close();
	bos.close();
}

//字节缓冲流一次读写一个字节数组
public static void method3()throws IOException{
	BufferInputStream bis=new BufferInputStream(new FileInputStream("E:\\itcast\\字节流复制图片.avi"));
	BufferOutputStream bos=new BufferOutputStream(new FileOutputStream("myByteStream\\字节流复制图片.avi"));
	
	byte[] bys=new byte[1024];
	int len;
	while((len=bis.read(bys))!=-1){
		bos.write(bys,0,len);
	}
	bis.close();
	bos.close();
}

 4、字符流

4.1 为什么会出现字符流【理解】

字符流的介绍
        由于字节流操作中文不是特别的方便,所以Java就提供字符流 字符流 = 字节流 + 编码表
中文的字节存储方式
        用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接成中文,如何识别是中文的呢?
                汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数.

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

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

    解码:
        String(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的 String
        String(byte[] bytes, String charsetName):通过指定的字符集解码指定的字节数组来构造新的 String
 */
public class StringDemo {
    public static void main(String[] args) throws UnsupportedEncodingException {
        //定义一个字符串
        String s = "中国";

        //byte[] getBytes():使用平台的默认字符集将该 String编码为一系列字节,将结果存储到新的字节数组中
        byte[] bys = s.getBytes(); //[-28, -72, -83, -27, -101, -67]
        //byte[] getBytes(String charsetName):使用指定的字符集将该 String编码为一系列字节,将结果存储到新的字节数组中
        byte[] bys = s.getBytes("UTF-8"); //[-28, -72, -83, -27, -101, -67]
        byte[] bys = s.getBytes("GBK"); //[-42, -48, -71, -6]
        System.out.println(Arrays.toString(bys));

        //String(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的 String
        String ss = new String(bys);
        //String(byte[] bytes, String charsetName):通过指定的字符集解码指定的字节数组来构造新的 String
        String ss = new String(bys,"UTF-8");
        String ss = new String(bys,"GBK");
        System.out.println(ss);
    }
}

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

InputStreamReader(InputStream in)使用默认字符编码创建InputStreamReader对象
InputStreamReader(InputStream in,String chatset)使用指定的字符编码创建InputStreamReader对象
OutputStreamWriter(OutputStream out)使用默认字符编码创建OutputStreamWriter对象
OutputStreamWriter(OutputStream out,String charset)使用指定的字符编码创建OutputStreamWriter对象
public class ConversionStreamDemo {
    public static void main(String[] args) throws IOException {

        /*FileOutputStream fos = new FileOutputStream("myCharStream\\osw.txt");
        OutputStreamWriter osw = new OutputStreamWriter(fos);*/
        //OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("myCharStream\\osw.txt"));
//        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("myCharStream\\osw.txt"),"UTF-8");
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("myCharStream\\osw.txt"),"GBK");
        osw.write("中国");
        osw.close();

//        InputStreamReader​(InputStream in) 创建一个使用默认字符集的InputStreamReader。
//        InputStreamReader​(InputStream in, String charsetName) 创建一个使用命名字符集的InputStreamReader。
//        InputStreamReader isr = new InputStreamReader(new FileInputStream("myCharStream\\osw.txt"));
        InputStreamReader isr = new InputStreamReader(new FileInputStream("myCharStream\\osw.txt"),"GBK");
        //一次读取一个字符数据
        int ch;
        while ((ch=isr.read())!=-1) {
            System.out.print((char)ch);
        }

        isr.close();

    }
}

 4.4 字符流数据的5种方式【应用】

public class OutputStreamWriterDemo {
    public static void main(String[] args) throws IOException {
        //OutputStreamWriter​(OutputStream out):创建一个使用默认字符编码的OutputStreamWriter
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("myCharStream\\osw.txt"));

        //void write​(int c):写一个字符
//        osw.write(97);
//        //void flush():刷新流
//        osw.flush();
//        osw.write(98);
//        osw.flush();
//        osw.write(99);

        //void write​(char[] cbuf):写入一个字符数组
        char[] chs = {'a', 'b', 'c', 'd', 'e'};
//        osw.write(chs);

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

        //void write​(String str):写一个字符串
//        osw.write("abcde");

        //void write​(String str, int off, int len):写一个字符串的一部分
//        osw.write("abcde", 0, "abcde".length());
        osw.write("abcde", 1, 3);

        //释放资源
        osw.close();
        //Exception in thread "main" java.io.IOException: Stream closed
//        osw.write(100);
    }
}

 4.5 字符流数据的2种方式

/*
    构造方法:
        InputStreamReader​(InputStream in):创建一个使用默认字符集的InputStreamReader

    读数据的2种方式:
        int read​():一次读一个字符数据
        int read​(char[] cbuf):一次读一个字符数组数据
 */
public class InputStreamReaderDemo {
    public static void main(String[] args) throws IOException {
        //InputStreamReader​(InputStream in):创建一个使用默认字符集的InputStreamReader
//        InputStreamReader isr = new InputStreamReader(new FileInputStream("myCharStream\\osw.txt"));
        InputStreamReader isr = new InputStreamReader(new FileInputStream("myCharStream\\ConversionStreamDemo.java"));

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

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


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

 4.6 字符流复制Java文件

import java.io.*;

/*
    需求:
        把模块目录下的ConversionStreamDemo.java 复制到模块目录下的 Copy.java

    思路:
        1:根据数据源创建字符输入流对象
        2:根据目的地创建字符输出流对象
        3:读写数据,复制文件
        4:释放资源
 */
public class CopyJavaDemo01 {
    public static void main(String[] args) throws IOException {
        //根据数据源创建字符输入流对象
        InputStreamReader isr = new InputStreamReader(new FileInputStream("myCharStream\\ConversionStreamDemo.java"));
        //根据目的地创建字符输出流对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("myCharStream\\Copy.java"));

        //读写数据,复制文件
        //一次读写一个字符数据
//        int ch;
//        while ((ch=isr.read())!=-1) {
//            osw.write(ch);
//        }

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

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

 改进

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/*
    需求:
        把模块目录下的ConversionStreamDemo.java 复制到模块目录下的 Copy.java

    数据源和目的地的分析
        数据源:myCharStream\\ConversionStreamDemo.java --- 读数据 --- Reader --- InputStreamReader --- FileReader
        目的地: myCharStream\\ Copy.java --- 写数据 --- Writer --- OutputStreamWriter --- FileWriter

    思路:
        1:根据数据源创建字符输入流对象
        2:根据目的地创建字符输出流对象
        3:读写数据,复制文件
        4:释放资源
 */
public class CopyJavaDemo02 {
    public static void main(String[] args) throws IOException {
        //根据数据源创建字符输入流对象
        FileReader fr = new FileReader("myCharStream\\ConversionStreamDemo.java");
        //根据目的地创建字符输出流对象
        FileWriter fw = new FileWriter("myCharStream\\Copy.java");

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

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

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

5、字符缓冲流-BufferedWriter、BufferedReader

public class BufferedStreamDemo01 {
    public static void main(String[] args) throws IOException {
        //BufferedWriter(Writer out)
        /*FileWriter fw = new FileWriter("myCharStream\\bw.txt");
        BufferedWriter bw = new BufferedWriter(fw);*/
        BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\bw.txt"));
        bw.write("hello\r\n");
        bw.write("world\r\n");
        bw.close();

        //BufferedReader(Reader in)
        BufferedReader br = new BufferedReader(new FileReader("myCharStream\\bw.txt"));

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

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

        br.close();

    }
}

 5.1 字符缓冲流复制Java文件

/*
    需求:
        把模块目录下的ConversionStreamDemo.java 复制到模块目录下的 Copy.java

    思路:
        1:根据数据源创建字符缓冲输入流对象
        2:根据目的地创建字符缓冲输出流对象
        3:读写数据,复制文件
        4:释放资源
 */
public class CopyJavaDemo01 {
    public static void main(String[] args) throws IOException {
        //根据数据源创建字符缓冲输入流对象
        BufferedReader br = new BufferedReader(new FileReader("myCharStream\\ConversionStreamDemo.java"));
        //根据目的地创建字符缓冲输出流对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\Copy.java"));

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

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

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

5.2 字符缓冲流特有功能

/*
    字符缓冲流的特有功能
        BufferedWriter:
            void newLine():写一行行分隔符,行分隔符字符串由系统属性定义

        BufferedReader:
            public String readLine():读一行文字。
                结果包含行的内容的字符串,不包括任何行终止字符,如果流的结尾已经到达,则为null
 */
public class BufferedStreamDemo02 {
    public static void main(String[] args) throws IOException {
        /*
        //创建字符缓冲输出流
        BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\bw.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("myCharStream\\bw.txt"));

        //public String readLine():读一行文字。
        /*
        //第一次读取数据
        String line = br.readLine();
        System.out.println(line);

        //第二次读取数据
        line = br.readLine();
        System.out.println(line);

        //在多读两次
        line = br.readLine();
        System.out.println(line);

        line = br.readLine();
        System.out.println(line);
        */

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

        br.close();
    }
}

 5.3 字符缓冲流特有功能复制Java文件

/*
    需求:
        把模块目录下的ConversionStreamDemo.java 复制到模块目录下的 Copy.java

    思路:
        1:根据数据源创建字符缓冲输入流对象
        2:根据目的地创建字符缓冲输出流对象
        3:读写数据,复制文件
            使用字符缓冲流特有功能实现
        4:释放资源
 */
public class CopyJavaDemo02 {
    public static void main(String[] args) throws IOException {
        //根据数据源创建字符缓冲输入流对象
        BufferedReader br = new BufferedReader(new FileReader("myCharStream\\ConversionStreamDemo.java"));
        //根据目的地创建字符缓冲输出流对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\Copy.java"));

        //读写数据,复制文件
        //使用字符缓冲流特有功能实现
        String line;
        while ((line=br.readLine())!=null) {
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

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

6、IO流小节

7、IO特殊操作流 

7.1 标准输入流-InputStream

System类中有两个静态的成员变量:
        publicstatic final InputStream in:标准输入流。通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源
        public static final PrintStream out:标准输出流。通常该流对应于显示输出或由主机环境或用户指定的另一个输出目标

/*
    public static final InputStream in:标准输入流。通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源
 */
public class SystemInDemo {
    public static void main(String[] args) throws IOException {
        //public static final InputStream in:标准输入流
//        InputStream is = System.in;

//        int by;
//        while ((by=is.read())!=-1) {
			//字节流的数据,当读中文时出现乱码,因为中文在utf-8中占3个字符
//            System.out.print((char)by);	
//        }

        //如何把字节流转换为字符流?用转换流
//        InputStreamReader isr = new InputStreamReader(is);
//        //使用字符流能不能够实现一次读取一行数据呢?可以
//        //但是,一次读取一行数据的方法是字符缓冲输入流的特有方法
//        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);
    }
}

7.2 标准输出流-PrintStream

输出语句的本质:是一个标准的输出流
        PrintStream ps = System.out;
        PrintStream类有的方法,System.out都可以使用

public class SystemOutDemo {
    public static void main(String[] args) {
        //public static final PrintStream out:标准输出流
        PrintStream ps = System.out;

        //能够方便地打印各种数据值
//        ps.print("hello");
//        ps.print(100);

//        ps.println("hello");
//        ps.println(100);

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

        System.out.println();
//        System.out.print();
    }
}

7.3 字节打印流

打印流分类
        字节打印流:PrintStream
        字符打印流:PrintWriter
打印流的特点
        只负责输出数据,不负责读取数据
        永远不会抛出IOException
        有自己的特有方法
字节打印流
        PrintStream(String fileName):使用指定的文件名创建新的打印流
        使用继承父类的方法写数据,查看的时候会转码;使用自己的特有方法写数据,查看的数据原样输出
        可以改变输出语句的目的地
        public static void setOut(PrintStream out):重新分配“标准”输出流

public class PrintStreamDemo {
    public static void main(String[] args) throws IOException {
        //PrintStream​(String fileName):使用指定的文件名创建新的打印流
        PrintStream ps = new PrintStream("myOtherStream\\ps.txt");

        //写数据
        //字节输出流有的方法
//        ps.write(97);	//写入a

        //使用特有方法写数据
//        ps.print(97);	//写入97
//        ps.println();
//        ps.print(98);
        ps.println(97);
        ps.println(98);


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

7.4 字符打印流-PrintWriter

字符打印流构造房方法:

PrintWriter(String fileName)使用指定的文件名创建一个新的PrintWriter,而不需要自动执行刷新
PrintWriter(Writer out, boolean autoFlush)创建一个新的PrintWriter out:字符输出流 autoFlush: 一个布尔值,如果为真,则println , printf ,或format方法将刷新输出缓冲区
public class PrintWriterDemo {
    public static void main(String[] args) throws IOException {
        //PrintWriter​(String fileName) :使用指定的文件名创建一个新的PrintWriter,而不需要自动执行行刷新
//        PrintWriter pw = new PrintWriter("myOtherStream\\pw.txt");

//        pw.write("hello");
//        pw.write("\r\n");
//        pw.flush();
//        pw.write("world");
//        pw.write("\r\n");
//        pw.flush();

//        pw.println("hello");
        /*
            pw.write("hello");
            pw.write("\r\n");
         */
//        pw.flush();
//        pw.println("world");
//        pw.flush();

        //PrintWriter​(Writer out, boolean autoFlush):创建一个新的PrintWriter
        PrintWriter pw = new PrintWriter(new FileWriter("myOtherStream\\pw.txt"),true);
//        PrintWriter pw = new PrintWriter(new FileWriter("myOtherStream\\pw.txt"),false);

        pw.println("hello");
        /*
            pw.write("hello");
            pw.write("\r\n");
            pw.flush();
         */
        pw.println("world");

        pw.close();
    }
}

7.5 复制Java文件打印流改进版

/*
    需求:
        把模块目录下的PrintStreamDemo.java 复制到模块目录下的 Copy.java

    思路:
        1:根据数据源创建字符输入流对象
        2:根据目的地创建字符输出流对象
        3:读写数据,复制文件
        4:释放资源
 */
public class CopyJavaDemo {
    public static void main(String[] args) throws IOException {
        /*
        //根据数据源创建字符输入流对象
        BufferedReader br = new BufferedReader(new FileReader("myOtherStream\\PrintStreamDemo.java"));
        //根据目的地创建字符输出流对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("myOtherStream\\Copy.java"));

        //读写数据,复制文件
        String line;
        while ((line=br.readLine())!=null) {
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

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

        //根据数据源创建字符输入流对象
        BufferedReader br = new BufferedReader(new FileReader("myOtherStream\\PrintStreamDemo.java"));
        //根据目的地创建字符输出流对象
        PrintWriter pw = new PrintWriter(new FileWriter("myOtherStream\\Copy.java"),true);

        //读写数据,复制文件
        String line;
        while ((line=br.readLine())!=null) {
            pw.println(line);
        }

        //释放资源
        pw.close();
        br.close();
    }
}

8、对象序列化流

public class Student implements Serializable {
    private String name;
    private int age;
    ......
}
/*
    对象序列化流
        构造方法:
            ObjectOutputStream​(OutputStream out):创建一个写入指定的OutputStream的ObjectOutputStream

        序列化对象的方法:
            void writeObject​(Object obj):将指定的对象写入ObjectOutputStream

    NotSerializableException:抛出一个实例需要一个Serializable接口。 序列化运行时或实例的类可能会抛出此异常

    类的序列化由实现java.io.Serializable接口的类启用。 不实现此接口的类将不会使任何状态序列化或反序列化
 */
public class ObjectOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        //ObjectOutputStream​(OutputStream out):创建一个写入指定的OutputStream的ObjectOutputStream
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("myOtherStream\\oos.txt"));

        //创建对象
        Student s = new Student("林青霞",30);

        //void writeObject​(Object obj):将指定的对象写入ObjectOutputStream
        oos.writeObject(s);

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

  

 9、对象反序列化流

/*
    构造方法:
        ObjectInputStream​(InputStream in):创建从指定的InputStream读取的ObjectInputStream

    反序列化对象的方法:
        Object readObject​():从ObjectInputStream读取一个对象
 */
public class ObjectInputStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //ObjectInputStream​(InputStream in):创建从指定的InputStream读取的ObjectInputStream
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("myOtherStream\\oos.txt"));

        //Object readObject​():从ObjectInputStream读取一个对象
        Object obj = ois.readObject();

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

        ois.close();
    }
}

 10、serialVersionUID&transient【应用】

public class ObjectStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
//        write();
        read();
    }

    //反序列化
    private static void read() throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("myOtherStream\\oos.txt"));
        Object obj = ois.readObject();
        Student s = (Student) obj;
        System.out.println(s.getName() + "," + s.getAge());
        ois.close();
    }

    //序列化
    private static void write() throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("myOtherStream\\oos.txt"));
        Student s = new Student("林青霞", 30);
        oos.writeObject(s);
        oos.close();
    }
}
  • 用对象序列化流序列化了一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出问题呢?
           会出问题,抛出InvalidClassException异常
  • 如果出问题了,如何解决呢?
            重新序列化;给对象所属的类加一个serialVersionUID
                                   private static final long serialVersionUID = 42L;

     
  • 如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?
            答:给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程
  • public class Student implements Serializable {
        private static final long serialVersionUID = 42L;
        private String name;
    //    private int age;
        private transient int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
    //    @Override
    //    public String toString() {
    //        return "Student{" +
    //                "name='" + name + '\'' +
    //                ", age=" + age +
    //                '}';
    //    }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值