Java基础之IO系列(一)

1.本文概述

本文讲解IO系列有关字符流对象部分的内容。

字符流主要包含以下四个组成对象:

FileReader
FileWriter

BufferedReader
BufferedWriter


2.Writer部分

1.Writer概述

常用方法:

abstract void close()
关闭此流,但要先刷新它。即会在关闭前先调用flush方法。
abstract void flush()
刷新该流的缓冲。
void write(char[] cbuf)
写入字符数组。
abstract void write(char[] cbuf, int off, int len)
写入字符数组的某一部分。
void write(int c)
写入单个字符。
void write(String str)
写入字符串。
void write(String str, int off, int len)
写入字符串的某一部分。

说明:Writer是一个抽象类,无法直接实例化,因此一般使用其间接子类FileWriter。

2.FileWriter

FileWriter概述

FileWriter是用来写入字符文件的便捷类

常用构造方法:

FileWriter(File file)
根据给定的 File 对象构造一个 FileWriter 对象。
FileWriter(File file, boolean append)
根据给定的 File 对象构造一个 FileWriter 对象。如果append为true,则将数据写入文件末尾处,而不是覆盖整个文件。

说明:关于参数中的File对象部分知识将在后续博文中讲解,具体可参考:

FileWriter(String fileName)
根据给定的文件名构造一个 FileWriter 对象。
FileWriter(String fileName, boolean append)
根据给定的文件名以及指示是否附加写入数据的boolean值来构造 FileWriter 对象。如果append为true,则将数据写入文件末尾处,而不是覆盖整个文件。

说明:FileWriter的方法与Writer中的方法一致,并没有特有方法,此处不再对其方法进行列举。

向文件中写出数据

本例中用到的构造方法:

FileWriter(String fileName)
根据给定的文件名构造一个 FileWriter 对象。

说明:在表示文件路径时,分隔符需要使用双反斜杠”\”

步骤:

1.创建一个FileWriter对象,该对象初始化时必须要明确被操作的文件,并且该文件会被创建到指定目录下。若该目录下已有同名文件,则该文件将被覆盖。

2.调用write方法将字符串写入流中

3.刷新流对象中的缓冲数据,将数据写入目标文件中
说明:输出流在关闭前可以多次调用write以及flush方法

4.关闭流
说明:该方法会在关闭流前先调用flush方法刷新缓存,调用后流就被彻底关闭了。

示例代码:

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

public class FileWriterDemo {

    public static void main(String[] args) {
        try {
            //实例化字符输出流对象
            FileWriter fw=new FileWriter("G:\\test.txt");
            //向指定文件中输出数据
            fw.write("test:");
            fw.write("这是一份测试文件");
            //刷新流缓存
            fw.flush();
            //关闭流
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

程序运行结果

1.png

3.IO异常处理方式

与输入输出流相关的操作都可能抛出IOException异常,这需要我们进行一些合适的异常处理。

以下为一个标准的IOException处理示例:

示例代码:

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

public class FileWriterDemo {

    public static void main(String[] args) {
        //声明字符输出流对象并初始化
        FileWriter fw=null; 
        try {
            //实例化字符输出流对象
            fw=new FileWriter("G:\\test.txt",true);
            //向指定文件中输出数据
            fw.write("\r\ntest:这是在原有基础上添加数据!");
            //刷新流缓存
            fw.flush();             

        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            //当fw存在时才关闭流,防止空指针异常
            if(fw!=null)
                try {               
                    //关闭流
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

}

4.对已存在的文件进行续写

使用FileWriter另一个构造方法:

FileWriter(String fileName, boolean append)
根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。

说明:当append传入参数为true时,表示不覆盖已有的文件,而在已有文件的末尾续写数据。

示例代码:

    //部分代码
    public static void main(String[] args) {
        //声明字符输出流对象并初始化
        FileWriter fw=null; 
        try {
            //实例化字符输出流对象
            fw=new FileWriter("G:\\test.txt",true);
            //向指定文件中输出数据
            fw.write("\r\ntest:这是在原有基础上添加数据!");
            //刷新流缓存
            fw.flush();             

        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            //当fw存在时才关闭流,防止空指针异常
            if(fw!=null)
                try {                   
                    //关闭流
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

程序运行结果:

2.png

小技巧:如果想要实现文本换行的效果,可以使用转义字符”\n”,但为了使windows下的记事本识别换行操作,需要使用”\r\n”


3.Reader部分

1.Reader概述

常用方法:

abstract void close()
关闭该流并释放与之关联的所有资源。
int read()
读取单个字符。如果已到达流的末尾,则返回-1
int read(char[] cbuf)
将字符读入数组。如果已到达流的末尾,则返回-1
abstract int read(char[] cbuf, int off, int len)
将字符读入数组的某一部分。如果已到达流的末尾,则返回-1。off是开始位置的索引,len是要读取的最大字符数
long skip(long n)
跳过字符

int read(CharBuffer target)
试图将字符读入指定的字符缓冲区。如果已到达流的末尾,则返回-1 。
void reset()
重置该流。

说明:Reader是一个抽象类,无法直接实例化,因此一般使用其间接子类FileReader。

2.FileReader

FileReader概述

FileReader用来读取字符文件的便捷类。

构造方法:

FileReader(File file)
在给定从中读取数据的 File 的情况下创建一个新 FileReader。
FileReader(String fileName)
在给定从中读取数据的文件名的情况下创建一个新 FileReader。

说明:FileWriter的方法与Writer中的方法一致,并没有特有方法,此处不再对其方法进行列举。

第一种文本文件读取方式

通过读取单个字节的方式获得文件中的所有数据。

步骤:

1.创建一个文件读取流对象,和指定名称的文件相关联。如果文件不存在,则会抛出FileNotFoundException

2.调用读取流对象的read方法
fr.read();
说明:当read方法读取到流的末尾时,该方法返回-1。利用这一特点,可以通过while循环输出文件中的所有数据。

示例代码:

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

public class FileReaderDemo {

    public static void main(String[] args) {
        FileReader fr=null;
        try {
            //实例化指向已存在文件的输入流对象
            fr=new FileReader("G:\\test.txt");

            int ch=0;
            while((ch=fr.read())!=-1){
                //将获取到的int型数据强转为char型输出
                System.out.print((char)ch);
            }               
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally{
            if(fr!=null)
                try {
                    //关闭流
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

}

程序运行结果:

test:这是一份测试文件
test:这是在原有基础上添加数据!

第二种文本文件读取方式

通过字符数组对文件中的数据进行读取。

步骤:

1.定义一个字符数组,用于存储读到的字符
2.创建一个文件输入流对象
3.通过read(char[])方法将文件数据读入指定数组

说明:同样利用read方法读取完毕返回-1的特性,可以使用while循环读取文件中的全部数据。注意要对获取到的数组进行有效范围截取,因为在循环的最后一次数据读取中,数组不一定被填满。此外,为了保持较高的读取效率,建议将用于接受数据的字符数组大小定义为1024的整数倍。

示例代码:

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

public class FileReaderDemo {

    public static void main(String[] args) {
        FileReader fr=null;
        try {
            //实例化指向已存在文件的输入流对象
            fr=new FileReader("G:\\test.txt");

            //定义用于临时存储数据的字符数组
            char[] bufArr=new char[1024];

            //存储读取到的字节长度
            int len;
            while((len=fr.read(bufArr))!=-1){
                //将获取到的char数组转化为字符串,注意对字符数组有效区域的截取
                String endStr=new String(bufArr,0,len);
                System.out.print(endStr);
            }               
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally{
            if(fr!=null)
                try {
                    //关闭流
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

}

程序运行结果:

test:这是一份测试文件
test:这是在原有基础上添加数据!

说明:向控制台中打印数据时应该使用print方法,否则可能在错误的位置进行换行,影响输出效果

总结:以上两种方法推荐使用第二种。第二种方式由于具有字符数组作为缓冲区,相比之下读取效率更高


3.简单应用-复制文本文件

需求描述:将一个文本文件从E盘复制到D盘

复制的原理:其实就是将E盘下的文件数据读取后,输出到到D盘的指定文件中

步骤:

1.在D盘创建一个文件,用于存储E盘的文件数据
2.定义输入输出流和E盘指定文件关联
3.通过不断的读写完成数据存储
4.关闭流资源

第一种方式

示例代码:

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

public class CopyDemo {

    public static void main(String[] args) {
        FileWriter fw=null;
        FileReader fr=null;
        try {
            //实例化输入输出流
            fr=new FileReader("E:\\demo.txt");
            fw=new FileWriter("D:\\demo.txt");

            //将读取到的数据写入目标文件
            int ch=0;
            while((ch=fr.read())!=-1){
                fw.write(ch);
                //刷新流缓存
                fw.flush();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        finally{
            //关闭资源
            if(fr!=null)
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            if(fw!=null)
                try {
                    //关闭流
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }

    }

}

说明:每次读取一个字符就写入一个字符,效率较低。因此不建议使用这种方式。但如果目标文件较小倒也无所谓。

第二种方式

本例用到的方法:

int read(char[] cbuf)
将字符读入数组。如果已到达流的末尾,则返回 -1
abstract void write(char[] cbuf, int off, int len)
写入字符数组的某一部分。

示例代码:

public static void main(String[] args) {
        FileWriter fw=null;
        FileReader fr=null;
        try {
            //实例化输入输出流
            fr=new FileReader("E:\\demo.txt");
            fw=new FileWriter("D:\\demo.txt");

            //定义用于临时存储数据的字符数组
            char[] bufArr=new char[1024];

            //存储读取到的字节长度
            int len=0;
            while((len=fr.read(bufArr))!=-1){
                //将字符数组的有效范围写入目标文件
                fw.write(bufArr,0,len);
                //刷新流缓存
                fw.flush();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        finally{
            //关闭资源
            if(fr!=null)
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            if(fw!=null)
                try {
                    //关闭流
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }

    }

说明:这种方式的效率较高,推荐使用


4.缓冲字符流

1.缓冲字符流概述

  • 缓冲区的出现提高了对数据的读写效率
  • 缓冲区要结合流才可以使用
  • 缓冲流在流的基础上对流的功能进行了增强。

对应类:

BufferedWriter
BufferedReader

使用的缓冲区的时候的需要注意以下两点:

1.在使用缓冲区之前必须先有流对象,并将流对象作为参数构造一个缓冲区对象。

2.使用缓冲区时,一定要使用flush方法。另外,关闭缓冲区实际上就是关闭缓冲区中的流对象,因此在使用close对缓冲区进行关闭后,可以不必对流对象再调用close方法进行关闭。

2.BufferedWriter

BufferedWriter用于将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入.可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。

构造方法:

BufferedWriter(Writer out)
创建一个使用默认大小输出缓冲区的缓冲字符输出流。
BufferedWriter(Writer out, int sz)
创建一个使用给定大小输出缓冲区的新缓冲字符输出流。

常用方法:

void close()
关闭此流,但要先刷新它。
void flush()
刷新该流的缓冲。
void newLine()
写入一个行分隔符,即换行符。并且该操作是跨平台的。
void write(char[] cbuf)
写入字符数组。
void write(char[] cbuf, int off, int len)
写入字符数组的某一部分。
void write(int c)
写入单个字符。
void write(String str)
写入字符串。
void write(String s, int off, int len)
写入字符串的某一部分。

示例代码:

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

public class BufWriterDemo {

    public static void main(String[] args) {
        BufferedWriter bw=null;
        try {
            //通过传入FileWriter对象实例化BufferedWriter
            bw=new BufferedWriter(new FileWriter("G:\\buf_test.txt"));
            bw.write("test:这是通过缓冲流写入的数据");
            //通过缓冲流的特有方法写入换行符
            bw.newLine();
            bw.write("test:通过缓冲流的方法写入了换行符");
            //刷新流的缓存
            bw.flush();

        } catch (IOException e) {
            e.printStackTrace();
        }
        finally{
            if(bw!=null)
                try {               
                    //关闭流
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

}

程序运行结果:

3.png

3.BufferedReader

BufferedReader用于从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

构造方法:

BufferedReader(Reader in)
创建一个使用默认大小输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in, int sz)
创建一个使用指定大小输入缓冲区的缓冲字符输入流。

常用方法:

void close()
关闭该流并释放与之关联的所有资源。
int read()
读取单个字符。
int read(char[] cbuf, int off, int len)
将字符读入数组的某一部分。
String readLine()
读取一个文本行,包含该行内容的字符串,不包含任何行终止符。如果已到达流末尾,则返回 null。
long skip(long n)
跳过字符。
void reset()
将流重置到最新的标记。

示例代码:

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class BufReaderDemo {

    public static void main(String[] args) {
        BufferedReader br=null;
        try {
            通过传入FileReader对象实例化BufferedReader
            br=new BufferedReader(new FileReader("G:\\buf_test.txt"));
            String str=null;
            while((str=br.readLine())!=null){
                //注意要使用println输出获取到的数据
                System.out.println(str);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally{
            if(br!=null)
                try {
                    //关闭流
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }
}

程序运行结果:

test:这是通过缓冲流写入的数据
test:通过缓冲流的方法写入了换行符

说明:对于获取的每行数据,需要通过println输出,因为readLine()返回的字符串中不包含换行符。

4.通过缓冲区复制文本文件

需求描述: 通过缓冲区将E盘指定文件复制到D盘

通过readLine()writeLine()方法高效率读取和写出

注意:输出时使用newLine()方法写出换行符,因为readLine()返回的字符串中不包含换行符,只返回有效内容。

示例代码:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class BufCopyDemo {

    public static void main(String[] args) {
        BufferedWriter bw=null;
        BufferedReader br=null;

        try {
            //实例化输入输出缓冲流
            bw=new BufferedWriter(new FileWriter("D:\\buf_demo.txt"));
            br=new BufferedReader(new FileReader("E:\\buf_demo.txt"));

            String str=null;
            while((str=br.readLine())!=null){
                bw.write(str);
                //输出换行符
                bw.newLine();
                //刷新缓冲输出流缓存
                bw.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally{
            if(bw!=null)
                try {               
                    //关闭流
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            if(br!=null)
                try {
                    //关闭流
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }

    }
}

5.自定义一个简单的缓冲区Reader类

示例代码:

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

public class MyReader {
    private FileReader fr;//字符流,用于数据的读取

    //构造方法
    public MyReader(FileReader fr){
        this.fr=fr;
    }

    //读取整行数据的自定义方法
    public String MyReadLine() throws IOException{
        //实例化一个StringBuilder对象用来临时存储数据
        StringBuilder strBlr=new StringBuilder();

        int ch=0;       
        while((ch=fr.read())!=-1){
            //读取到换行符时执行的操作
            if(ch=='\r')
                continue;
            //读取到换行符时执行的操作
            if(ch=='\n')
                return strBlr.toString();   
            else
                strBlr.append((char)ch);
        }       
        //当读取的文件中仅有一行数据且没有换行符时,返回读取到的字符串
        if(strBlr.length()!=0)
            return strBlr.toString();       

        return null;
    }

    //关闭流的方法
    public void close() throws IOException{ 
        fr.close(); 
    }
}

注意:以上的自定义类仅实现了缓冲流的两个功能,可以利用装饰设计模式将代码优化。令该类继承Reader接口,并且通过子类实现父类中的抽象方法。优化后的代码如下。

示例代码:

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

public class MyReader {
    private FileReader fr;//字符流,用于数据的读取

    //构造方法
    public MyReader(FileReader fr){
        this.fr=fr;
    }

    //读取整行数据的自定义方法
    public String MyReadLine() throws IOException{
        //实例化一个StringBuilder对象用来临时存储数据
        StringBuilder strBlr=new StringBuilder();

        int ch=0;       
        while((ch=fr.read())!=-1){
            //读取到换行符时执行的操作
            if(ch=='\r')
                continue;
            //读取到换行符时执行的操作
            if(ch=='\n')
                return strBlr.toString();   
            else
                strBlr.append((char)ch);
        }       
        //当读取的文件中仅有一行数据且没有换行符时,返回读取到的字符串
        if(strBlr.length()!=0)
            return strBlr.toString();       

        return null;
    }

    //关闭流的方法
    public void close() throws IOException{ 
        fr.close(); 
    }
}

5.LineNumberReader

LineNumberReader是跟踪行号的缓冲字符输入流。

构造方法:

LineNumberReader(Reader in)
使用默认输入缓冲区的大小创建新的行编号 reader。
LineNumberReader(Reader in, int sz)
创建新的行编号 reader,将字符读入给定大小的缓冲区。

常用方法:

int getLineNumber()
获得当前行号。
void setLineNumber(int lineNumber)
设置当前行号。
int read()
读取单个字符。
int read(char[] cbuf, int off, int len)
将字符读入数组中的某一部分。
String readLine()
读取文本行。
long skip(long n)
跳过字符。
void reset()
将该流重新设置为最新的标记。

说明:LineNumberReader是基于Reader类,通过装饰设计模式的一个装饰类

示例代码:

    //部分代码
    public static void main(String[] args) {        
        LineNumberReader lnr=null;
        try {
            //实例化LineNumberReader对象
            lnr=new LineNumberReader(new FileReader("G:\\line_test.txt"));

            String str=null;
            while((str=lnr.readLine())!=null){
                //获取行号
                int num=lnr.getLineNumber();
                if(num==6)
                    lnr.setLineNumber(7);
                System.out.println(num+"  "+str);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally{
            if(lnr!=null)
                try {
                    lnr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

程序运行结果:

1 test:这是用于测试LineNumberReader的文件
2 LineNumberReader可以输出数据的行号
3 就像你现在看到的这样
4 么么哒
5 而且还可以设置行号
6 就像这样
8 我其实是第七行,不是第八行


相关阅读:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值