【Java的IO流之文件字符输入输出流 25】
一、FileReader:读取字符流;FileWriter:写入字符流
字符流可以读取和写入汉字和英文,字节流不能读取和写入汉字
二、FileReader流
1、常用的构造方法
FileReader(String filename) -->从给定从中读取数据的文件名的情况下创建一个新的filename
2、常用的成员方法
|-- public int read() throws IOException
读取:读取单个字符。
返回:作为整数读取的字符,范围在0~65535之间(0x00-0xffff)。如果已达到流的末尾,则返回-1
抛出:IOException - 如果发生 I/O 错误
|-- public int read(char[] cbuf) throws IOException
读取:将字符读入数组
参数:cbuf目标缓冲区
返回:读取的字符数,如果已达到流的末尾,返回-1
抛出:IOException - 如果发生 I/O 错误
|-- public abstract int read(char[] cbuf,
int off,
int len)
throws IOException
读取:将字符读入数组的某一部分
参数:cbuf目标缓冲区
off开始存储字符处的偏移量
len要读取的最多字符数
返回:读取的字符数,如果已达到流的末尾,返回-1
抛出:IOException - 如果发生 I/O 错误
package com.JavaStudy.studyFileReader0629; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; /** * @Author wufq * @Date 2020/6/29 17:43 * 读取文件字符流 * FileReader读取文件会出现乱码 */ public class FileReaderTest01 { public static void main(String[] args){ FileReader fr = null; String file = "/Users/wufq/Desktop/copy.txt"; try { fr = new FileReader(file); char[] chars = new char[512]; int temp=0; while ((temp=fr.read(chars))!=-1){ String msg = new String(chars,0,temp); System.out.println(msg); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e){ e.printStackTrace(); } finally { if (fr != null) { try { //谁先定义后关闭谁 fr.close(); } catch (IOException e) { e.printStackTrace(); } } } } } ===执行结果=== �Һ��ҵ����abc123
上面的代码发现读取文件内的中文,返回了乱码
如何解决乱码:
引入InputStreamReader类、BufferedReader类
1、InputStreamReader是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。
为了达到更高的效率,可要考虑在BufferedReader内包装InputStreamReader 例如:BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
2、BufferedReader从字符输入流中读取文本,缓冲各个字符,从而实现字符,数组和行的高效读取。
两个构造方法:BufferedReader(Reader in) 默认大小,默认值就足够大了,BufferedReader(Reader in, int sz)指定缓冲区的大小
主要构造方法:read():读取单个字符,readLine():读取一个文本行
package com.JavaStudy.studyFileReader0629; import java.io.*; /** * @Author wufq * @Date 2020/6/30 09:45 * 解决乱码 */ public class FileReaderTest02 { public static void main(String[] args){ String file = "/Users/wufq/Desktop/copy.txt"; InputStreamReader isr = null; BufferedReader bReader = null; String temp; try { //字节流转换成字符流的通道 isr = new InputStreamReader(new FileInputStream(file),"GBK"); bReader = new BufferedReader(isr); while ((temp=bReader.readLine())!=null){ System.out.print(temp); } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { if(bReader !=null){ try { bReader.close(); } catch (IOException e) { e.printStackTrace(); } } } } } ====执行结果==== 我和我的祖国abc123
三、FileWriter流:用于写入字符流
1、两个常用构造方法:
FileWriter(String fileName) :覆盖掉原先文件的内容
FileWriter(String fileName,boolean append) :不会覆盖掉原先文件的内容,会在原先文件的后面追加文本。
2、继承Writer类的方法:write
|-- public void write(char[] cbuf) throws IOException写入字符数组。
参数:
cbuf - 要写入的字符数组
抛出:
IOException - 如果发生 I/O 错误
|-- public abstract void write(char[] cbuf,int off, int len) throws IOException写入字符数组的某一部分。
参数:
cbuf - 字符数组
off - 开始写入字符处的偏移量
len - 要写入的字符数
抛出:
IOException - 如果发生 I/O 错误
|-- public void write(String str) throws IOException写入字符串。
参数:
str - 要写入的字符串
抛出:
IOException - 如果发生 I/O 错误
|-- public void write(String str,int off, int len) throws IOException写入字符串的某一部分。
参数:
str - 字符串
off - 相对初始写入字符的偏移量
len - 要写入的字符数
抛出:
IndexOutOfBoundsException - 如果 off 或 len 为负,或者 off+len 为负或大于给定字符串的长度
IOException - 如果发生 I/O 错误
package com.JavaStudy.studyFileReader0629; import java.io.FileWriter; import java.io.IOException; /** * @Author wufq * @Date 2020/6/30 14:55 * 写入字符流 */ public class FileWriterTest01 { public static void main(String[] args){ FileWriter fw = null; String file = "/Users/wufq/Desktop/paste.txt"; try { //fw = new FileWriter(file); fw= new FileWriter(file,true); //各个成员方法的作用 fw.write(5); fw.write("中国万岁"); fw.write("万岁",0,2); String msg = "中华人民共和国"; char[] chars = msg.toCharArray() ;//把字符串转换成char类型的数组 fw.write(chars); fw.write(chars,0,3); fw.flush(); } catch (IOException e) { e.printStackTrace(); } finally { if(fw !=null){ try { fw.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
上面的代码写入txt文件后,导致原文件的编码格式改变了(或者是写入的内容出现了乱码)
如何解决:
引入OutputStreamWriter和BufferedWriter
1、OutputStreamWriter:是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集
每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得到的这些字节将在缓冲区中累积。可以指定此缓冲区的大小,不过,默认的缓冲区对多数用途来说已足够大。注意,传递给 write() 方法的字符没有缓冲。
为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中,以避免频繁调用转换器。例如:
Writer out
= new BufferedWriter(new OutputStreamWriter(System.out));
代理对 是一个字符,它由两个 char 值序列表示:高 代理项的范围为 '\uD800' 到 '\uDBFF',后跟范围为 '\uDC00' 到 '\uDFFF' 的低 代理项。
2、BufferedWriter:将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入
可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
该类提供了 newLine() 方法,它使用平台自己的行分隔符概念,此概念由系统属性 line.separator 定义。并非所有平台都使用新行符 ('\n') 来终止各行。因此调用此方法来终止每个输出行要优于直接写入新行符。
package com.JavaStudy.studyFileReader0629; import java.io.*; /** * @Author wufq * @Date 2020/6/30 15:27 * 解决写入文件改变编码格式或者乱码问题 */ public class FileWriterTest02 { public static void main(String[] args){ String file = "/Users/wufq/Desktop/paste.txt"; OutputStreamWriter osw; BufferedWriter bufferW = null; try { osw = new OutputStreamWriter(new FileOutputStream(file,true),"GBK"); bufferW = new BufferedWriter(osw); String msg = "1、中国"; bufferW.write(msg); bufferW.newLine();//自动根据系统的不同选择换行符 bufferW.write(msg); bufferW.flush(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e){ e.printStackTrace(); } finally { if(bufferW!=null){ try { bufferW.close(); } catch (IOException e) { e.printStackTrace(); } } } } } ====执行结果==== 1、中国 1、中国
四、练习题
1、把A文件内的中文复制到B文件内(并且不能覆盖掉B文件内的原有数据)
package com.JavaStudy.studyFileReader0629; import java.io.*; /** * @Author wufq * @Date 2020/6/30 15:49 * 把A文件内的中文复制到B文件内(并且不能覆盖掉B文件内的原有数据) */ public class FileReadWriteTest01 { public static void main(String[] args){ String file1 = "/Users/wufq/Desktop/copy.txt"; String file2 = "/Users/wufq/Desktop/paste.txt"; InputStreamReader inputStreamReader; BufferedReader bufferedReader = null; BufferedWriter bufferedWriter = null; String temp; try { inputStreamReader = new InputStreamReader(new FileInputStream(file1),"GBK"); bufferedReader = new BufferedReader(inputStreamReader); while ((temp = bufferedReader.readLine())!=null) { bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file2, true), "GBK")); bufferedWriter.write(temp); bufferedWriter.newLine(); bufferedWriter.flush(); } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch(IOException e){ e.printStackTrace(); } finally{ if(bufferedReader != null&&bufferedWriter!=null){ try { bufferedWriter.close(); bufferedReader.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
2、使用BufferReader实现用户键盘的输入
package com.JavaStudy.studyFileReader0629; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.Scanner; /** * @Author wufq * @Date 2020/6/30 17:07 * BufferReader实现键盘的输出 */ public class BufferReader { public static void main(String[] args)throws Exception{ /* 利用Scanner实现 */ Scanner s = new Scanner(System.in); //执行到此处停下来等待输入 String username = s.next(); System.out.println("用户名:"+username); /* 利用BufferReader实现键盘的输出 */ BufferedReader bu = new BufferedReader(new InputStreamReader(System.in)); //执行到此处停下来等待输入 String username1 =bu.readLine(); System.out.println("用户名是:"+username1); bu.close(); } }