1、使用read()读取文本文件
FileReader用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要自己指定这些值,可以先在 FileInputStream 上构造一个 InputStreamReader。
调用读取流对象的read()方法,读取单个字符,得到的结果是字符的ascii码,下面是使用read()读取文本文件的简单例子,以及一些要点说明:
- public static void readTxtByRead(){
- Reader reader = null;
- String spr = File.separator;
- int result;
- //创建一个文件读取流对象,和指定名称的文件相关联。
- //要保证该文件是已经存在的,如果不存在,会抛出FileNotFoundException异常
- try {
- reader = new FileReader("G:" + spr + "TestFolder" + spr + "writer.txt");
- //调用读取流对象的read()方法,读取单个字符,得到的结果是字符的ascii码
- //read():一次读一个字符,并且会自动往下读,达到流的末尾,则返回-1
- while((result = reader.read()) != -1){
- P.rintln(result + " " + (char)result); //强制转换为char类型
- }
- // while(true){
- // result = reader.read();
- // if(result == -1){
- // break;
- // }
- // P.rintln(result + " " + (char)result); //强制转换为char类型
- // }
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- try {
- if(reader != null){
- reader.close();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
下面是使用read(char[] cbuf)读取文本文件的简单例子,以及一些要点说明:
- public static void readTxtByReads() throws IOException{ //使用read(char[] cbuf)读取文本文件
- Reader reader = null;
- char[] results = new char[1024]; //定义字符数组,用于存储读到的字符,一般定义长度为1024
- String spr = File.separator;
- int num = 0;
- reader = new FileReader("G:" + spr + "TestFolder" + spr + "writer.txt");
- while((num = reader.read(results)) != -1){ //read(char[])返回的是读到的字符个数
- P.rintln(new String(results, 0, num)); //以num截取有效位输出
- }
- reader.close();
- }
下面是本机测试的答案代码:
- public static void readJava() throws IOException{ //读取练习
- Reader reader = null;
- char[] results = new char[1024];
- String spr = File.separator; //通用的文件分隔符
- int num = 0;
- reader = new FileReader("G:" + spr + "Workspaces" + spr + "MyEclipse 9" + spr + "Study" +
- spr + "src" + spr + "com" + spr + "xgh" + spr + "itheima" + spr + "learn" + spr + "SystemAndOthers.java");
- while((num = reader.read(results)) != -1){
- P.rint(new String(results, 0, num));
- }
- reader.close();
- }
copy文件的原理:其实就是将源盘下的文件数据存储到目标盘的一个文件中。
例,将C盘一个文本文件复制到D盘。其步骤如下:
1:在D盘创建一个文件,用于存储C盘文件中的数据
2:定义读取流和C盘文件关联
3:通过不断的读写完成数据存储
4:关闭资源
以下为文件copy练习,以及一些要点说明:
- public static void copyFile() throws IOException{ //从C盘读一个字符,就往D盘写一个字符
- //创建目标文件
- Writer writer = new FileWriter("D:" + File.separator + "export_copy.xml");
- //与源文件关联
- Reader reader = new FileReader("C:" + File.separator + "export.xml");
- int result = 0;
- while((result = reader.read()) != -1){
- writer.append((char)result); //将获取的字符append到writer中,最终将writer写入到文件中
- // writer.write((char)result); //获取一个字符就写入一个字符,IO次数多
- }
- reader.close();
- writer.close();
- }
- public static void copyFiles(){ //使用read(char[] cs)读取源文件写入目标文件
- Writer writer = null;
- Reader reader = null;
- char[] results = new char[1024];
- int num = 0;
- try {
- writer = new FileWriter("D:" + File.separator + "export_copy.xml");
- reader = new FileReader("C:" + File.separator + "export.xml");
- while((num = reader.read(results)) != -1){
- writer.write(results, 0, num); //批量写入,可以减少磁盘IO次数
- }
- } catch (IOException e) {
- throw new RuntimeException("读写失败");
- } finally{
- if(writer != null){
- try {
- writer.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- if(reader != null){
- try {
- reader.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
缓冲区的出现提高了对数据的读写效率;流的缓冲区对应类:BufferedWriter、BufferedReader;缓冲区要结合流才可以使用;在流的基础上对流的功能进行了增强。
BufferedWriter将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。 可以指定缓冲区的大小,或者接受默认的大小。
缓冲区的出现是为了提高流的操作效率而出现的,所以在创建缓冲区之前,必须要先有流对象。缓冲技术的原理其实是这个对象封装了数组。
下面是一个BufferedWriter的简单练习,以及一些要点说明:
- public static void bufferedWriter() throws Exception{
- Writer fileWriter = null;
- BufferedWriter bufferedWriter = null;
- String spr = File.separator;
- //实例化字符写入流对象
- fileWriter = new FileWriter("G:" + spr + "TestFolder" + spr + "writer.txt");
- //为了提高字符写入流的效率,加入了缓冲区技术。
- //只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可
- bufferedWriter = new BufferedWriter(fileWriter);
- for(int i = 0; i < 5; i++){
- bufferedWriter.write("我是被缓冲流写入的");
- bufferedWriter.newLine(); //插入换行符,可以跨平台使用
- bufferedWriter.flush(); //只要用到缓冲区,就要记得刷新
- }
- //缓冲区的实质其实还是操作fileWriter对象,所以关闭缓冲区,就是关闭缓冲区的流对象,即fileWriter.close()
- bufferedWriter.close();
- }
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。 可以指定缓冲区的大小,或者可使用默认的大小。
通常,Reader 所作的每个读取请求都会导致对底层字符或字节流进行相应的读取请求。因此,建议用 BufferedReader 包装所有其 read() 操作可能开销很高的 Reader(如 FileReader 和 InputStreamReader)。
将缓冲指定文件的输入。如果没有缓冲,则每次调用 read() 或 readLine() 都会导致从文件中读取字节,并将其转换为字符后返回,而这是极其低效的。
下面是一个BufferedReader的简单练习,以及一些要点说明:
- public static void bufferedReader() throws Exception{
- Reader fileReader = null;
- BufferedReader bufferedReader = null;
- String spr = File.separator;
- String result = null;
- //实例化一个读取流对象和文件相关联
- fileReader = new FileReader("G:" + spr + "TestFolder" + spr + "writer.txt");
- //为了提高效率,加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数
- bufferedReader = new BufferedReader(fileReader);
- //该缓冲区提供了一次读一行的方法 readLine(),方便对文本文件数据的读取。
- //当返回null时,表示读到文件末尾
- while((result = bufferedReader.readLine()) != null){
- P.rintln(result);
- }
- bufferedReader.close();
- }
ReadLine()无论是读一行,或者读取多个字符,其实最终使用的还是read()方法从硬盘一个一个读取。读取数据的时候不会将任何行终止符存入到缓冲区中,因此输出时不会换行,需要主动调用newLine()换行。
下面是一个简单的通过缓冲区复制文件的例子,已经一些要点说明:
- public static void copyTextByBuf() throws Exception{
- BufferedReader bufr = null;
- BufferedWriter bufw = null;
- String spr = File.separator;
- String result = null;
- bufr = new BufferedReader(new FileReader("G:" + spr + "TestFolder" + spr + "writer.txt"));
- bufw = new BufferedWriter(new FileWriter("G:" + spr + "TestFolder" + spr + "writer_copy.txt"));
- //readLine()返回的时候只返回回车符之前的数据内容,并不返回回车符
- //因此输出的时候需要调用newLine(),以输出换行符
- while((result = bufr.readLine()) != null){
- bufw.write(result);
- bufw.newLine();
- bufw.flush();
- }
- bufw.close();
- bufr.close();
- }
- class MyBufferedReader{ //自定义一个缓冲流,等价于BufferedRrader
- private Reader fileReader;
- public MyBufferedReader(Reader fileReader){
- this.fileReader = fileReader;
- }
- public String myReaderLine() throws IOException{ //读取一行数据
- StringBuffer sb = new StringBuffer();
- int value = 0;
- while((value = fileReader.read()) != -1){
- char ch = (char)value;
- if(ch == '\r')
- continue;
- if(ch == '\n')
- return sb.toString();
- else
- sb.append(ch);
- }
- if(sb.length() != 0){
- return sb.toString();
- }
- return null;
- }
- public void close() throws IOException{ //关闭流
- fileReader.close();
- }
- }
9、装饰设计模式
装饰设计模式:当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强的功能。那么自定义的该类称为装饰类。
装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象提供更强的功能。
装饰设计模式比继承要灵活,避免了继承体系臃肿,而且降低了类与类的关系。装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。所以装饰类和被装饰类通常是都属于一个体系中的。下面是一个使用装饰模式写的MyLineNumberReader类,可以显示行号:
- class MyLineNumberReader extends MyBufferedReader{ //自建一个类,能显示行号
- // private Reader in;
- private int myLineNumber;
- public MyLineNumberReader(Reader in) {
- super(in);
- // this.in = in;
- }
- public String myReadLine() throws IOException{
- myLineNumber++;
- return super.myReaderLine();
- // StringBuffer sb = new StringBuffer();
- // char c;
- // int i;
- //
- //
- // while((i = in.read()) != -1){
- // c = (char)i;
- // if(c == '\r')
- // continue;
- // if(c == '\n')
- // return sb.toString();
- // else
- // sb.append(c);
- // }
- // if(sb.length() != 0)
- // return sb.toString();
- // return null;
- }
- public int getMyLineNumber() {
- return myLineNumber;
- }
- public void setMyLineNumber(int myLineNumber) {
- this.myLineNumber = myLineNumber;
- }
- // public void myClose() throws IOException{
- // in.close();
- // }
- }
- public static void myLineNumberReader() throws Exception{
- String spr = File.separator;
- FileReader fr = null;
- MyLineNumberReader mlnr = null;
- String line = null;
- fr = new FileReader("G:" + spr + "Workspaces" + spr + "MyEclipse 9" + spr + "Study" +
- spr + "src" + spr + "com" + spr + "xgh" + spr + "itheima" + spr + "learn" + spr + "SystemAndOthers.java");
- mlnr = new MyLineNumberReader(fr);
- while((line = mlnr.myReadLine()) != null){
- P.rintln(mlnr.getMyLineNumber() + ":" + line);
- }
- mlnr.close();
- }