第十五章输入/输出-15.3字节流和字符流

15.3字节流和字符流

 15.3.1 InputStream和Reader

 InputStream和Reader都是抽象类,本省不能创建实例,但他们分别由一个用于读取文件输入流:FileInputStream和FileReader,他们都是节点流----会直接和指定文件关联。

package com.cdmt.collection.io;

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

public class FileInputStreamTest {

    public static void main(String[] args) throws IOException {
        //创建字节输入流
        //内存相对路径
        FileInputStream fis = new FileInputStream("./src/main/java/com/cdmt/collection/io/FileInputStreamTest.java");
        //硬盘绝对路径
//        FileInputStream fis = new FileInputStream("E:\\work\\demo\\src\\main\\java\\com\\cdmt\\collection\\io\\FileInputStreamTest.java");
        //创建一个1024长度的桶
        byte[] bbuf = new byte[1024];
        //用于保存实际读取的字节数
        int hasRead = 0;
        //使用循环来重复取水
        while ((hasRead = fis.read(bbuf))>0){
            System.out.println(new String(bbuf,0,hasRead));
        }
        //关闭文件输入流,放在finally块里更安全
        fis.close();
    }

}

结果:

第十五章输入/输出-15.3字节流和字符流_第1张图片

PS:

上面程序创建了一个长度为1024的子接数组来读取文件,实际上该java源文件的长度还不到1024子节,也就是说,程序只需要执行一次read()方法就可以读取完全内容,但是如果创建较小的字节数组,程序运行时在输出中文注释就可能出现乱码-----这是因为文件保存时采用的是GBK编码方式,在这总方式下,每个中文字符占2字节,如果read()方法读取时只读到半个中文字符将会乱码。

package com.cdmt.collection.io;

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

public class FileReaderTest {

    public static void main(String[] args) throws IOException {
        //创建字符输入流
        //内存相对路径
        FileReader fis = new FileReader("./src/main/java/com/cdmt/collection/io/FileReaderTest.java");
        //硬盘绝对路径
//        FileInputStream fis = new FileInputStream("E:\\work\\demo\\src\\main\\java\\com\\cdmt\\collection\\io\\FileInputStreamTest.java");
        //创建一个32长度的桶
        char[] bbuf = new char[32];
        //用于保存实际读取的字节数
        int hasRead = 0;
        //使用循环来重复取水
        while ((hasRead = fis.read(bbuf))>0){
            System.out.println(new String(bbuf,0,hasRead));
        }
        //关闭文件输入流,放在finally块里更安全
        fis.close();
    }

}

结果:

第十五章输入/输出-15.3字节流和字符流_第2张图片

结果:

因为32位的字符长度,所以需要循环多次调用读取才可以完成任务。

PS:InputStream和Reader还支持如下几个方法来移动记录指针

  1. void mark(int readAheadLimit):在记录指针当前位置记录一个标记(mark)
  2. boolean markSupported():判断此输入流是否支持mark()操作,即是否支持记录标记
  3. void reset():将此流的记录指针冲i性能定位到上一次记录标记(mark)的 位置
  4. long skip(long n):记录指针向前移动n个字节/字符

 15.3.2 OutputStream和Writer

 OutputStream和Writer也非常相似,都使用write方法与read方法类似使用。

package com.cdmt.collection.io;

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

public class FileOutputStreamTest {
    public static void main(String[] args) throws IOException {
        //创建字节输入流
        FileInputStream fis = new FileInputStream("./src/main/java/com/cdmt/collection/io/FileOutputStreamTest.java");
        //创建字节输出流
        FileOutputStream fos = new FileOutputStream("newFile.txt");
        byte[] bbuf = new byte[32];
        int hasRead = 0;
        //循环读取输入流中的数据
        while((hasRead = fis.read(bbuf))>0){
            //每次读取一次,即写入文件输出流,读了多少,就写多少
            fos.write(bbuf,0,hasRead);
        }
        fis.close();
        fos.close();
    }
}

结果:

第十五章输入/输出-15.3字节流和字符流_第3张图片

总结:

使用Java的IO流执行输出时,不要忘记关闭输出流,关闭输出流除可以保证流的物理资源被回收之外,可能还可以将输出流缓冲区的数据flush到物理节点里(因为在执行close()方法之前,自动执行输出流的flush()方法)。Java的很多输出流默认都提供了缓冲功能,气势没有必要刻意去记忆哪些流由缓冲功能,哪些流没有,只要正常关闭所有的输出流即可保证程序正常。

如果希望直接输出字符串内容,则使用Writer会有更好的效果:

package com.cdmt.collection.io;

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

public class FileWriterTest {
    public static void main(String[] args) throws IOException {
        FileWriter fw = new FileWriter("poem.txt");
        fw.write("江南   汉乐府");
        fw.write("江南可采莲,莲叶何田田。\r\n");
        fw.write("鱼戏莲叶间。\r\n");
        fw.write("鱼戏莲叶东,鱼戏莲叶西。\r\n");
        fw.write("鱼戏莲叶南,鱼戏莲叶北。\r\n");
        fw.close();
    }
}

结果:

第十五章输入/输出-15.3字节流和字符流_第4张图片

PS:换行符windows时\r\n,如果时UNIX/Linux/BSD平台,则使用\n换行符。

 

你可能感兴趣的:(Java基础)