【Java中的IO流】

IO字符输出流(FileReader)

【Java中的IO流】_第1张图片

 以内存为基准,可以把文件中的数据以字符的形式读到内存中;

【Java中的IO流】_第2张图片

public class FileReaderTest1 {
    public static void main(String[] args)  {
        try (
                // 1、创建一个文件字符输入流管道与源文件接通
                Reader fr = new FileReader("io-app2\\src\\itheima01.txt");
                ){
            // 2、一个字符一个字符的读(性能较差)
//            int c; // 记住每次读取的字符编号。
//            while ((c = fr.read()) != -1){
//                System.out.print((char) c);
//            }
            // 每次读取一个字符的形式,性能肯定是比较差的。

            // 3、每次读取多个字符。(性能是比较不错的!)
            char[] buffer = new char[3];
            int len; // 记住每次读取了多少个字符。
            while ((len = fr.read(buffer)) != -1){
                // 读取多少倒出多少
                System.out.print(new String(buffer, 0, len));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 使用文件字符输入流,有啥好处?

读取中文会读取完整的中文字符

如何读取一个字符和每次读取多个字符的方法是?返回值有什么特点?

public int read(); 一次读取一个字符,返回对应的字节

public int read(char[] buffer) 一次读取多个字符,返回本次读到的有效字节个数

 

FileWriter(字符输出流) 

构造器

说明

public FileWriter​(File file)

创建字节输出流管道与源文件对象接通

public FileWriter​(String filepath)

创建字节输出流管道与源文件路径接通

public FileWriter(File file,boolean append)

创建字节输出流管道与源文件对象接通,可追加数据

public FileWriter(String filepath,boolean append)

创建字节输出流管道与源文件路径接通,可追加数据

方法名称

说明

void write​(int c)

写一个字符

void write​(String str)

写一个字符串

void write​(String str, int off, int len)

写一个字符串的一部分

void write​(char[] cbuf)

写入一个字符数组

void write​(char[] cbuf, int off, int len)

写入字符数组的一部分

 

public class FileWriterTest2 {
    public static void main(String[] args) {
        try (
                // 0、创建一个文件字符输出流管道与目标文件接通。
                // 覆盖管道
                // Writer fw = new FileWriter("io-app2/src/itheima02out.txt");
                // 追加数据的管道
                Writer fw = new FileWriter("io-app2/src/itheima02out.txt", true);
                ){
            // 1、public void write(int c):写一个字符出去
            fw.write('a');
            fw.write(97);
            //fw.write('磊'); // 写一个字符出去
            fw.write("\r\n"); // 换行

            // 2、public void write(String c)写一个字符串出去
            fw.write("我爱你中国abc");
            fw.write("\r\n");

            // 3、public void write(String c ,int pos ,int len):写字符串的一部分出去
            fw.write("我爱你中国abc", 0, 5);
            fw.write("\r\n");

            // 4、public void write(char[] buffer):写一个字符数组出去
            char[] buffer = {'黑', '马', 'a', 'b', 'c'};
            fw.write(buffer);
            fw.write("\r\n");

            // 5、public void write(char[] buffer ,int pos ,int len):写字符数组的一部分出去
            fw.write(buffer, 0, 2);
            fw.write("\r\n");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

注意:

字符输出流写出数据后,必须刷新流,或者关闭流,写出去的数据才能生效 

方法名称

说明

public void flush() throws IOException

刷新流,就是将内存中缓存的数据立即写到文件中去生效!

public void close() throws IOException

关闭流的操作,包含了刷新!

 字节流、字符流的使用场景小结:

字节流适合做一切文件数据的拷贝(音视频,文本);

字节流不适合读取中文内容输出 字符流适合做文本文件的操作(读,写)

字节缓冲流(BufferedInputStream\BufferedOutStream)

【Java中的IO流】_第3张图片 原理:字节缓冲输入流自带了8KB缓冲池;字节缓冲输出流也自带了8KB缓冲池

构造器

说明

public BufferedInputStream​(InputStream is)

把低级的字节输入流包装成一个高级的缓冲字节输入流,从而提高读数据的性能

public BufferedOutputStream​(OutputStream os)

把低级的字节输出流包装成一个高级的缓冲字节输出流,从而提高写数据的性能

 

public class BufferedInputStreamTest1 {
    public static void main(String[] args) {
        try (
                InputStream is = new FileInputStream("io-app2/src/itheima01.txt");
                // 1、定义一个字节缓冲输入流包装原始的字节输入流
                InputStream bis = new BufferedInputStream(is);

                OutputStream os = new FileOutputStream("io-app2/src/itheima01_bak.txt");
                // 2、定义一个字节缓冲输出流包装原始的字节输出流
                OutputStream bos = new BufferedOutputStream(os);
        ){

            byte[] buffer = new byte[1024];
            int len;
            while ((len = bis.read(buffer)) != -1){
                bos.write(buffer, 0, len);
            }
            System.out.println("复制完成!!");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 缓冲流有几种?

字节缓冲输入流:BufferedInputStream

字节缓冲输出流:BufferedOutputStream

字符缓冲输入流:BufferedReader

字符缓冲输出流:BufferedWriter

字节缓冲流为什么提高了字节流读写数据的性能?

字节缓冲流自带8KB缓冲区 减少了内存和硬盘之间的交互,从而提高原始流读、写数据的性能

字符缓冲流

【Java中的IO流】_第4张图片 

 创建BufferedReader对象需要用到BufferedReader的构造方法,内部需要封装一个原始的字符输入流,我们可以传入FileReader.

方法

说明

public String readLine()

读取一行数据返回,如果没有数据可读了,会返回null

public class BufferedReaderTest2 {
    public static void main(String[] args)  {
        try (
                Reader fr = new FileReader("io-app2\\src\\itheima04.txt");
                // 创建一个字符缓冲输入流包装原始的字符输入流
                BufferedReader br = new BufferedReader(fr);
        ){
//            char[] buffer = new char[3];
//            int len;
//            while ((len = br.read(buffer)) != -1){
//                System.out.print(new String(buffer, 0, len));
//            }
//            System.out.println(br.readLine());
//            System.out.println(br.readLine());
//            System.out.println(br.readLine());
//            System.out.println(br.readLine());

            String line; // 记住每次读取的一行数据
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

字符缓冲流有几种,作用是什么?

BufferedReader​字符缓冲输入流、BufferedWriter字符缓冲输出流 字符缓冲流自带8KB缓冲 减少了内存和硬盘之间的交互,从而提高原始流读、写数据的性能

两种字符缓冲流各自新增了什么功能?

BufferedReader​ 新增了readLine(),按照一行读取 BufferedWriter​ 新增了newLine(),换行 

缓冲流的性能不一定比低级流高,其实低级流自己加一个数组,性能其实是不差。只不过缓冲流帮你加了一个相对而言大小比较合理的数组 。

转换流

 FileReader默认只能读取UTF-8编码格式的文件。如果使用FileReader读取GBK格式的文件,可能存在乱码,因为FileReader它遇到汉字默认是按照3个字节来读取的,而GBK格式的文件一个汉字是占2个字节,这样就会导致乱码。

Java给我们提供了另外两种流InputStreamReader,OutputStreamWriter,这两个流我们把它叫做转换流。它们可以将字节流转换为字符流,并且可以指定编码方案。

【Java中的IO流】_第5张图片 

InputStreamReader

InputStreamReader不能单独使用的,它内部需要封装一个InputStream的子类对象,再指定一个编码表,如果不指定编码表,默认会按照UTF-8形式进行转换。

作用:

是指定编码读。解决了不同编码读取数据,出现乱码的问题 解决思路:先获取文件的原始字节流,再将其按真实的字符集编码转成字符输入流,这样字符输入流中的字符就不乱码了

public InputStreamReader(InputStream is ,String charset)

把原始的字节输入流,按照指定字符集编码转成字符输入流(重点)

public class InputStreamReaderTest2 {
    public static void main(String[] args) {
        try (
                // 1、得到文件的原始字节流(GBK的字节流形式)
                InputStream is = new FileInputStream("io-app2/src/itheima06.txt");
                // 2、把原始的字节输入流按照指定的字符集编码转换成字符输入流
                Reader isr = new InputStreamReader(is, "GBK");
                // 3、把字符输入流包装成缓冲字符输入流
                BufferedReader br = new BufferedReader(isr);
                ){
            String line;
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }


        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

OutputStreamWriter

OutputStreamReader也是不能单独使用的,它内部需要封装一个OutputStream的子类对象,再指定一个编码表,如果不指定编码表,默认会按照UTF-8形式进行转换。

public OutputStreamWriter(OutputStream os,String charset)

可以把原始的字节输出流,按照指定编码转换成字符输出流

public class OutputStreamWriterTest3 {
    public static void main(String[] args) {
        // 指定写出去的字符编码。
        try (
                // 1、创建一个文件字节输出流
                OutputStream os = new FileOutputStream("io-app2/src/itheima07out.txt");
                // 2、把原始的字节输出流,按照指定的字符集编码转换成字符输出转换流。
                Writer osw = new OutputStreamWriter(os, "GBK");
                // 3、把字符输出流包装成缓冲字符输出流
                BufferedWriter bw = new BufferedWriter(osw);
                ){
            bw.write("我是中国人abc");
            bw.write("我爱你中国123");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

打印流(PrintStream、PrintWrite)

public PrintStream​(OutputStream/File/String)

打印流直接通向字节输出流/文件/文件路径

public PrintStream​(String fileName, Charset charset)

可以指定写出去的字符编码

public PrintStream​(OutputStream out, boolean autoFlush)

可以指定实现自动刷新

public PrintStream​(OutputStream out, boolean autoFlush, String encoding)

可以指定实现自动刷新,并可指定字符的编码

public void println(Xxx xx)

打印任意类型的数据出去

public void write(int/byte[]/byte[]一部分)

可以支持写字节数据出去

 PrintStream和PrintWriter的区别 打印数据的功能上是一模一样的:都是使用方便,性能高效(核心优势)

PrintStream继承自字节输出流OutputStream,因此支持写字节数据的方法

PrintWriter继承自字符输出流Writer,因此支持写字符数据出去

public class PrintTest1 {
    public static void main(String[] args) {
        try (
                // 1、创建一个打印流管道
//                PrintStream ps =
//                        new PrintStream("io-app2/src/itheima08.txt", Charset.forName("GBK"));
//                PrintStream ps =
//                        new PrintStream("io-app2/src/itheima08.txt");
                PrintWriter ps =
                        new PrintWriter(new FileOutputStream("io-app2/src/itheima08.txt", true));
                ){
                ps.print(97);	//文件中显示的就是:97
                ps.print('a'); //文件中显示的就是:a
                ps.println("我爱你中国abc");	//文件中显示的就是:我爱你中国abc
                ps.println(true);//文件中显示的就是:true
                ps.println(99.5);//文件中显示的就是99.5

                ps.write(97); //文件中显示a,发现和前面println方法的区别了吗?

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

重定向输出语句

System里面有一个静态变量叫out,out的数据类型就是PrintStream,它就是一个打印流,而且这个打印流的默认输出目的地是控制台,所以我们调用System.out.pirnln()就可以往控制台打印输出任意类型的数据,而且打印啥就输出啥。

而且System还提供了一个方法,可以修改底层的打印流,这样我们就可以重定向打印语句的输出目的地了, 直接上代码。

public class PrintTest2 {
    public static void main(String[] args) {
        System.out.println("老骥伏枥");
        System.out.println("志在千里");

        try ( PrintStream ps = new PrintStream("io-app2/src/itheima09.txt"); ){
            // 把系统默认的打印流对象改成自己设置的打印流
            System.setOut(ps);

            System.out.println("烈士暮年");	
            System.out.println("壮心不已");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 数据流

DataOutputStream

构造器

说明

public DataOutputStream(OutputStream out)

创建新数据输出流包装基础的字节输出流

方法

说明

public final void writeByte​(int v) throws IOException

将byte类型的数据写入基础的字节输出流

public final void writeInt​(int v) throws IOException

将int类型的数据写入基础的字节输出流

public final void writeDouble(Double v) throws IOException

将double类型的数据写入基础的字节输出流

public final void writeUTF(String str) throws IOException

将字符串数据以UTF-8编码成字节写入基础的字节输出流

public void write(int/byte[]/byte[]一部分)

支持写字节数据出去

public class DataOutputStreamTest1 {
    public static void main(String[] args) {
        try (
                // 1、创建一个数据输出流包装低级的字节输出流
                DataOutputStream dos =
                        new DataOutputStream(new FileOutputStream("io-app2/src/itheima10out.txt"));
                ){
            dos.writeInt(97);
            dos.writeDouble(99.5);
            dos.writeBoolean(true);
            dos.writeUTF("黑马程序员666!");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

 DataInputStream(数据输入流)

构造器

说明

public DataInputStream(InputStream is)

创建新数据输入流包装基础的字节输入流

方法

说明

Public final byte readByte​() throws IOException

读取字节数据返回

public final int readInt​() throws IOException

读取int类型的数据返回

public final double readDouble() throws IOException

读取double类型的数据返回

public final String readUTF() throws IOException

读取字符串数(UTF-8)据返回

public int readInt()/read(byte[])

支持读字节数据进来

public class DataInputStreamTest2 {
    public static void main(String[] args) {
        try (
                DataInputStream dis =
                        new DataInputStream(new FileInputStream("io-app2/src/itheima10out.txt"));
                ){
            int i = dis.readInt();
            System.out.println(i);

            double d = dis.readDouble();
            System.out.println(d);

            boolean b = dis.readBoolean();
            System.out.println(b);

            String rs = dis.readUTF();
            System.out.println(rs);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 序列化流

字节流是以字节为单位来读写数据、字符流是按照字符为单位来读写数据、而对象流是以对象为单位来读写数据。也就是把对象当做一个整体,可以写一个对象到文件,也可以从文件中把对象读取出来。

ObjectOutputStraem(序列化)

可以把Java对象进行序列化:把Java对象存入到文件中去

构造器

说明

public ObjectOutputStream(OutputStream out)

创建对象字节输出流,包装基础的字节输出流

方法

说明

public final void writeObject​(Object o) throws IOException

把对象写出去

 注意:对象如果要参与序列化,必须实现序列化接口(java.io.Serializable)

准备一个User类,必须让其实现Serializable接口。

// 注意:对象如果需要序列化,必须实现序列化接口。
public class User implements Serializable {
    private String loginName;
    private String userName;
    private int age;
    // transient 这个成员变量将不参与序列化。
    private transient String passWord;

    public User() {
    }

    public User(String loginName, String userName, int age, String passWord) {
        this.loginName = loginName;
        this.userName = userName;
        this.age = age;
        this.passWord = passWord;
    }

    @Override
    public String toString() {
        return "User{" +
                "loginName='" + loginName + '\'' +
                ", userName='" + userName + '\'' +
                ", age=" + age +
                ", passWord='" + passWord + '\'' +
                '}';
    }
}

 再创建ObjectOutputStream流对象,调用writeObject方法对象到文件。

public class Test1ObjectOutputStream {
    public static void main(String[] args) {
        try (
                // 2、创建一个对象字节输出流包装原始的字节 输出流。
                ObjectOutputStream oos =
                        new ObjectOutputStream(new FileOutputStream("io-app2/src/itheima11out.txt"));
                ){
            // 1、创建一个Java对象。
            User u = new User("admin", "张三", 32, "666888xyz");

            // 3、序列化对象到文件中去
            oos.writeObject(u);
            System.out.println("序列化对象成功!!");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

注意:写到文件中的对象,是不能用记事本打开看的。因为对象本身就不是文本数据,打开是乱码 

ObjectInputStream(反序列化)

构造器

说明

public ObjectInputStream(InputStream is)

创建对象字节输入流,包装基础的字节输入流

方法

说明

public final Object readObject​()

把存储在文件中的Java对象读出来

 

public class Test2ObjectInputStream {
    public static void main(String[] args) {
        try (
            // 1、创建一个对象字节输入流管道,包装 低级的字节输入流与源文件接通
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("io-app2/src/itheima11out.txt"));
        ){
            User u = (User) ois.readObject();
            System.out.println(u);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

1.对象序列化的含义是什么?调用哪个方法实现?

把对象数据通过对象字节输出流ObjectOutputStram,存入到文件中去 public void writeObject(Object obj)

2.对象反序列化的含义是什么?调用哪个方法实现?

把对象数据通过对象字节输入流ObjectInputStram,存入到文件中去 public Object readObject()

3.  序列化和反序列化时有哪些注意事项?

类要实现序列化接口 手动提供序列号 哪一个属性不想参与序列化可以用transient关键字修饰 使用循环反序列化,读取到文件末尾会抛EOFException异常 (End of file)

你可能感兴趣的:(java,servlet,开发语言)