48-12 字符流

107 阅读11分钟

字符流

字节数组读取中文问题无法保证读取是完整的内容,可能读取你好a就乱码
解决方案:使用字符流中是3个字符-按照字符为单位进行读取的原理  你好a在字符流中是3个字符
java.io.Reader   close():  read(): 读取一个字符,返回对应的int数字(字符对应的int数字)
    read(char[] chs): 读取一些字符,返回对应的int数字(字符的个数)
        	参数: char[] chs: 用来存储读取到的多个字符的内容
        	返回值类型: 	int: 读取到的字符的个数 
 FileReader类: 文件字符输入流,以字符的方式读取文件内容,读进来,源文件
    	构造方法: FileReader(File/String path类型的文件路径) 
    	使用步骤:
        	1.创建文件字符输入流FileReader类的对象fr,绑定源文件
        	2.文件字符输入流FileReader类的对象fr调用read方法,以字符的方式读取文件内容
        	3.文件字符输入流FileReader类的对象fr调用close方法,关闭流,释放资源
补充: String的构造方法String(char[] chs): 把构造方法参数,按照平台默认编码表,转换成字符串
##使用Reader读取单个字符
public class Demo02Reader {
    public static void main(String[] args) throws IOException {
        //1.创建文件字符输入流FileReader类的对象fr,绑定源文件
        FileReader fr = new FileReader("day12_sw\\f1.txt");

        //2.文件字符输入流FileReader类的对象fr调用read方法,以字符的方式读取文件内容

        //定义int变量,保存每次读取到的一个字符的内容
        int ch = 0;
        //从fr关联的文件中读取一个字符,返回对应的int数字,存储到ch中
        //最后判断ch的值是否等于-1
        while((ch = fr.read())!=-1) {
            System.out.println((char)ch);
        }
        //3.文件字符输入流FileReader类的对象fr调用close方法,关闭流,释放资源
        fr.close();
    }    
}
### 使用Reader读取字符数组
public class Demo02Reader {
    public static void main(String[] args) throws IOException {
        //1.创建文件字符输入流FileReader类的对象fr,绑定源文件
        FileReader fr = new FileReader("day12_sw\\f1.txt");

        //2.文件字符输入流FileReader类的对象fr调用read方法,以字符的方式读取文件内容

        //定义int变量,保存每次读取到的字符的个数
        int len = 0;

        //定义字符数组,保存每次读取到的多个字符的内容
        char[] chs = new char[2];

        //从fr关联的文件中读取一些字符,存储到字符数组chs中,
        //返回读取到的字符的数量存储到len中
        //最后判断len的值是否等于-1
        while ((len = fr.read(chs)) != -1) {
            System.out.println(new String(chs,0,len));
        } 
        //3.文件字符输入流FileReader类的对象fr调用close方法,关闭流,释放资源
        fr.close();
    }
}

字符串的编码和解码方法

WriterFileWirter写数据到文件

String的编码和解码?
    问题1:    编码
        如何获取字符串(String)指定编码表对应的字节数组(byte[]) 
                String s = "你好";
        //获取UTF-8编码
        byte[] bs = s.getBytes(); 
      //获取GBK编码
        byte[] bs2 = s.getBytes("GBK");  
    问题2:    解码
        如何把字节数组(byte[])按照指定编码表,转换成对应的字符串(String)呢?
         //按照构造方法参数指定的编码表(GBK)解码
        String s3 = new String(bs2, "GBK");
        System.out.println(s3);
        //编码和解码的规则不统一: 乱码
        String s4 = new String(bs, "GBK");
        System.out.println(s4);	  
	你好 UTF-8编码: [-28, -67, -96, -27, -91, -67]
	你好 GBK编码: [-60, -29, -70, -61]
java.io.Writer类: 字符输出流顶层抽象父类,以字符的方式写出内容,写出去
        close(): 关闭流,释放资源
        write(int ch): 写出一个字符
        write(char[] chs): 写出一个字符数组
        write(char[] chs,int startIndex,int len): 写出一个字符数组的一部分
       参数:  char[] chs: 字符数组   int startIndex: 起始索引  int len: 写出字节的数量
       write(String str): 写出一个字符串
      write(String str,int startIndex,int len): 写出一个字符串的一部分
            参数:   String str: 字符串   
        构造方法:    FileWriter(File/String  path类型的文件路径,boolean append)  
    参数:  File/String 类型的文件路径   boolean append:
    true: 续写/追加写      false: 重新写,覆盖写,不写此参数默认就是false
    换行: 也是一个字符串  windows: \r\n   linux/unix: \n
 */      
        使用步骤:
            1.创建文件字符输出流FileWriter类的对象fw,绑定目标文件
            2.文件字符输出流FileWriter类的对象fw调用write方法,以字符的方式写出内容到文件
            3.文件字符输出流FileWriter类的对象fw调用close方法,关闭流,释放资源
    Writer写数据的5个方法
public class Demo02Writer {
    public static void main(String[] args) throws IOException {
        //1.创建文件字符输出流FileWriter类的对象fw,绑定目标文件
        FileWriter fw = new FileWriter("day12_sw\\fw.txt"true);

        //2.文件字符输出流FileWriter类的对象fw调用write方法,以字符的方式写出内容到文件
        //写出一个字符
        fw.write(65);//文件中显示A
        fw.write('a');//文件中显示a
        fw.write("好");//文件中显示好

        //写出一个字符数组
        char[] chs = {'好','好','学','习','天','天','向','上'};
        fw.write(chs);
       //写出换行符
        fw.write("\r\n");
        //写出一个字符数组的一部分: 学习天天 重新写一遍
        fw.write(chs,2,4);

        //写出一个字符串
        String s = "今天工作不努力,明天努力找工作";
        fw.write(s);

        //写出一个字符数组的一部分:  工作不努力,明天努力 重新写一遍
        fw.write(s,2,10);
        //3.文件字符输出流FileWriter类的对象fw调用close方法,关闭流,释放资源
        fw.close();
    }
}        

flush和close的区别

flush方法之后,可以继续调用write方法写出数据 
    close方法之后,不能继续调用write方法写出数据 
    记住一句话: io流对象,使用完毕,务必关闭流对象
    public class Demo04FlushVSClose {
    public static void main(String[] args) throws IOException {
        /*
        //1.字节流内部没有缓冲区,只要调用write方法,就是写出到目的地,所以不关流,也不会丢失数据
        FileOutputStream fos = new FileOutputStream("day12_sw\\fos.txt");
        fos.write("你好".getBytes());
        */
        FileWriter fw = new FileWriter("day12_sw\\fw3.txt");
        for (int i = 0; i < 2; i++) {
            fw.write("你好");
            //刷新
            //fw.flush();
            fw.write("大家好");
        }
        int a = 1;
        //死循环
        while(a == 1) {

        }
        //关闭流,释放资源
        fw.close();
        //fw.write("大家好");//错误了,流已经被关闭
    }
}

字符输出缓冲流

/* public BufferedWriter(Writer w):
			参数: Writer w 字符输出流抽象类 传递子类FileWriter对象
   特有方法: public void newLine() : 写入一个自适应平台的换行符
	使用步骤:
		1.创建Writer类的子类FileWriter对象fw,绑定目标文件
		2.创建高效字符输出流BufferedWriter对象bw,传递Writer类的子类FileWriter对象
		3.高效字符输出流BufferedWriter对象bw调用write方法,写出字符
		4.关闭流
 */
public class Demo01BufferedWriter {
    public static void main(String[] args) throws IOException {
        //1.创建Writer类的子类FileWriter对象fw,绑定目标文件
        FileWriter fw = new FileWriter("day12_xw\\bw.txt"); 
        //2.创建高效字符输出流BufferedWriter对象bw,传递Writer类的子类FileWriter对象
        BufferedWriter bw = new BufferedWriter(fw);  
        //3.高效字符输出流BufferedWriter对象bw调用write方法,写出字符
        bw.write("犯错,就得被惩罚~~"); 
        //写入使用操作系统的换行符
        bw.newLine(); 
        bw.write("犯错,不讲理由~~"); 
        //4.关闭流
        bw.close();
    }
}

字符输入缓冲流使用

         public BufferedReader(Reader r):
			参数: Reader r 字符输入流抽象类 传递子类FileReader对象
            read(): 读取一个字符  read(char[] chs):
			读取一些字符,把读取到的一些字符存入到方法参数字符数组chs中
			返回的是读取的字符的数量 
          特有方法: String readLine() : 读取一行文本 	遇到文件结束标志: 返回null
				读取到一行文本中,不包含换行符       
	使用步骤:
		1.创建Reader类的子类FileReader对象fr,绑定源文件
		2.创建高效字符输入流BufferedReader对象br,传递Reader类的子类FileReader对象
		3.高效字符输入流BufferedReader对象br调用readLine方法,读取一行字符
		4.关闭流 
public class Demo02BufferedReader {
    public static void main(String[] args) throws IOException {
        //1.创建Reader类的子类FileReader对象fr,绑定源文件
        FileReader fr = new FileReader("day12_xw\\bw.txt"); 
        //2.创建高效字符输入流BufferedReader对象br,传递Reader类的子类FileReader对象
        BufferedReader br = new BufferedReader(fr); 
        //3.高效字符输入流BufferedReader对象br调用readLine方法,读取一行字符 
        //定义String变量,用来接收每次读取到的一行字符串的内容
        String line = null;
        while((line = br.readLine())!=null){
            System.out.print(line);
        }
        //4.关闭流
        br.close(); 
    }
}
    练习: 把文本文件中的内容,以行为单位,按照每行前面的数字,从小到大排序
    步骤:
        1.创建List集合对象,泛型: String
        2.创建BufferedReader类的对象br,绑定源文件
        3.按行循环读取源文件
        4.把读取到的每行存储到List集合对象中
        5.调用Collections工具类中sort方法,对List集合对象排序(String排序规则: 按照第一个不相同的字母的ASCII码值,从小到大排序)
        6.创建BufferedWriter类的对象bw,绑定目标文件
        7.遍历List集合对象
        8.把获取到的当前行,写出到目标文件
        9.写入换行符
        10.关闭资源
 */
public class Demo03TxtSort {
    public static void main(String[] args) throws IOException {
        //1.创建List集合对象,泛型: String
        List<String> list = new ArrayList<>();

        //2.创建BufferedReader类的对象br,绑定源文件
        BufferedReader br = 
            new BufferedReader(new FileReader("day12_xw\\csb_no_sort.txt"));

        //3.按行循环读取源文件
        String line = null;
        while ((line = br.readLine()) != null) {
            //4.把读取到的每行存储到List集合对象中
            list.add(line);
        }
        //5.调用Collections工具类中sort方法,对List集合对象排序
        //(String排序规则: 按照第一个不相同的字母的ASCII码值,从小到大排序)
        //Collections.sort(list);
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.charAt(0)-o2.charAt(0);
            }
        });

        //6.创建BufferedWriter类的对象bw,绑定目标文件
        BufferedWriter bw = 
            new BufferedWriter(new FileWriter("day12_xw\\csb_sort.txt"));

        //7.遍历List集合对象
        for (String s : list) {
            //8.把获取到的当前行,写出到目标文件
            bw.write(s);
            //9.写入换行符
            bw.newLine();

        }
        //10.关闭资源
        br.close();
        bw.close();
    }
}

字符流乱码问题 原因: 文件中存储数据的编码表 和 读取文件时流对象使用的编码表不统一

/*
    java.io.InputStreamReader类: 是一个字符流,以字符的方式读取内容 
    构造方法:  InputStreamReader(InputStream in, String charsetName)
            参数:  InputStream in: 字节输入流抽象父类,传递子类FileInputStream类的对象
                String charsetName: 编码表,常用GBK和UTF-8  
    java.io.OutputStreamWriter类: 是一个字符流,以字符的方式写出内容  
        OutputStreamWriter(OutputStream out, String charsetName)
            参数:
                OutputStream out: 字节输出流抽象父类,传递子类FileOutputStream类的对象              
public class Demo03InputStreamReader {
    public static void main(String[] args) throws Exception {
        readUTF8();
    }
    //读取UTF8文件
    private static void readUTF8() throws IOException {
        //1.创建InputStream类的子类FileInputStream类的对象fis
        //2.创建InputStreamReader类的对象isr,传递fis并指定编码表
        InputStreamReader isr = new InputStreamReader(new FileInputStream("day12_xw\\utf8_1.txt"), "UTF-8");
        //3.InputStreamReader类的对象isr调用read方法,读取文件内容
        int len = 0;
        char[] chs = new char[2];
        while ((len = isr.read(chs)) != -1) {
            System.out.println(new String(chs,0,len));
        }
        //4.InputStreamReader类的对象isr调用close方法,关闭流释放资源
        isr.close();
    }  
}
public class Demo04OutputStreamWriter {
    public static void main(String[] args) throws IOException {
        writeUTF8();
        return;
    }
    //写出UTF-8内容到文件
    private static void writeUTF8() throws IOException {
        //1.创建OutputStream类的子类FileOutputStream类的对象fos
        //2.创建OutputStreamWriter类的对象osr,传递fos并指定编码表
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day12_xw\\utf8_2.txt"),"UTF-8");
        //3.创建OutputStreamWriter类的对象osr调用write方法,写出字符到文件
        osw.write("好好学习天天向上");
        //4.创建OutputStreamWriter类的对象osr调用close方法,关闭流释放资源
        osw.close();
    } 
}

##编码转换练习

GBK编码的文本文件,转换为UTF-8编码的文本文件 
 */
public class Demo05FromGBK2UTF8 {
    public static void main(String[] args) throws Exception {
        //1.创建InputStreamReader类的对象,绑定源文件,指定编码表GBK
        InputStreamReader isr = 
            new InputStreamReader(new FileInputStream("day12_xw\\csb_gbk.txt"), "GBK");
        //2.创建OutputStreamWriter类的对象,绑定目标文件,指定编码表UTF-8
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day12_xw\\csb_utf8.txt"), "UTF-8");
        //3.字符数组循环读(源文件)写(目标文件)
        int len = 0;
        char[] chs = new char[1024];
        while ((len = isr.read(chs)) != -1) {
            osw.write(chs,0,len);
        }
        //4.关闭流
        isr.close();
        osw.close();
    }
}
 能否使用字符缓冲输入输出流,实现此案例呢?  InputStream --> BufferedReader 
 是可以的因为是文本文件    
public class Demo06FromGBK2UTF8 {
    public static void main(String[] args) throws Exception {
        //1.创建InputStreamReader类的对象,绑定源文件,指定编码表GBK
        InputStreamReader isr = new InputStreamReader(new FileInputStream("day12_xw\\csb_gbk.txt"), "GBK");
        //把 InputStreamReader --> BufferedReader
        BufferedReader br = new BufferedReader(isr);
        //2.创建OutputStreamWriter类的对象,绑定目标文件,指定编码表UTF-8
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day12_xw\\csb_utf8.txt"), "UTF-8");
        //把 OutputStreamWriter --> BufferedWriter
        BufferedWriter bw = new BufferedWriter(osw);
        //3.循环按行读(源文件)写(目标文件)
        String line = null;
        while ((line = br.readLine()) != null) {
            bw.write(line);
            //写出换行
            bw.newLine();
        }
        //4.关闭流
        br.close();
        bw.close();
    }
}