zoukankan      html  css  js  c++  java
  • IO

    IO的特点及相关问题

    l IO流用来处理设备之间的数据传输

    设备:硬盘,内存,键盘录入

    l Java对数据的操作是通过流的方式

    l Java用于操作流的对象都在IO包中

    l 流按操作数据分为两种:字节流与字符流。

    l 流按流向分为:输入流,输出流。

    1、输入流和输出流的流向的理解?

    流就是处理数据的一种方式或者一种手段,或者理解为一种数据流。

    从硬盘已有的数据读取出来放内存里面的这个过程就是输入流。

    外部--------->内存 输入流   

    把内存中的数据存储到硬盘中的这个过程就是输出流。

    内存--------->外部 输出流  

    简单理解就是:以内存为中心。

    2、什么时候使用流对象?

    操作设备上的数据或操作文件的时候可以使用。

    二、字符流

    字符流的抽象基类:Reader &Writer

    1、字符流的理解,由来和作用?

    由于很多国家的文字融入进来,比如说中文在编码表中默认占2个字节。(UTF-8中是3个字节)而为了按照文字的单位来处理,所以出现了字符流。

    由来:后期编码表的不断出现,识别某一文字的码表不唯一。比如中文,GBK&unicode都可以识别,就出现了编码问题,为了处理文字数据,就需要通过早期的字节流+编码表结合完成。

    作用:为了更便于操作文字数据。

    结论:只要是处理纯文本数据,就要优先考虑使用字符流,除此之外都是用字节流。

    2IO分类

    按照功能进行分类---------->读和写

     

     

     

     

    IO体系中的子类名称后缀大部分都是父类名称,而前缀都是体现子类功能的名字

    Reader

    InputStreamReader

           FileReader

    专门用于处理文件的

    字符读取流对象

    Writer

    OutputStreamWriter

             FileWriter

    专门用于处理文件的

    字符写入流对象

    3、字符流继承体系图

    4Reader中的常见方法

    ü int read()读取一个字符。返回的是读到的那个字符(0-65535),如果读到流的末尾,返回-1

    ü int read(char[ ]):将读到的字符存入指定的数组中,返回的是读到的字符个数,也就是往数组里装元素的个数,如果读到流的末尾,返回-1

    ü close( )读取字符用的是windows系统的功能,就希望使用完毕后,进行资源的释放。

    5Writer中的常见方法

    ü void write(ch)将一个字符写入到流中。

    ü void write(char[ ])将一个字符数组写入到流中。

    ü void write(String)将一个字符串写入到流中。

    ü void flush()刷新流,将流中的数据刷新到目的地中,流还存在

    ü void close()关闭资源,在关闭前会先调用flush(),刷新流中的数据去目的地,然后关闭流

    6FileWriter

    该类没有特有的方法,只有自己的构造方法。

    特点:

    l 用于处理文本文件;

    l 该类中有默认的编码表;

    l 该类中有临时缓冲。

    构造方法:在写入流对象初始化时,必须有一个存储数据的目的地。

    FileWriter(String filename):该构造函数做了什么事情呢?

    A:调用系统资源;

    B:在指定位置创建一个文件,如果该文件已经存在,将会被覆盖。

    FileWriter(String filename,boolean true)该构造函数如果传入的boolean类型值为true时,会在指定文件末尾处进行数据的续写

    换行:private static final String LINE_SEPARATOR = System.getProperties("line.separator");

      fr.writer("xi"+LINE_SEPARATOR+"xi");

    7FileReader

    用于读取文本文件的流对象,用于关联文本文件。

    构造函数:在读取流对象初始化的时候,必须要指定一个被读取的文件,如果该文件不存在会发生FileNotFindException

    FileReader  fr = new  FileReader(String filename)

    基本的读写操作方式

    因为数据通常都以文件的形式存在,所以就要找到IO体系中可以用于操作文件的流对象,通过名称可以更容易获取该对象。

    8、将文本数据存储到一个文件中。

    import java.io.FileWriter;

    import java.io.IOException;

    public class Demo1 {

    public static void main(String[] args) throws IOException {

    FileWriter fw = new FileWriter("E:\1.txt");

    fw.write("abcd");

    fw.flush();//数据刷到目的地了,流还可以继续使用

    fw.write("mn");

    fw.close();//数据也刷到目的地了,但是流不能再被使用

    }

    }

    文件中写入的数据:abcdmn意外收获:异常包也得导入。

    对于读取或者写入流对象的构造函数,以及读写方法,还有刷新关闭功能都会抛出IOException或其子类。

    所以要进行处理,要么抛出throws,要么try……catch处理。

    9、完整的异常处理方式。

    import java.io.FileWriter;

    import java.io.IOException;

    public class Demo2 {

    public static void main(String[] args) {

    FileWriter fw = null;//定义为全局,关闭的时候也要使用

    try {

    fw = new FileWriter("E:\1.txt");

    fw.write("abcd");

    fw.flush();

    fw.write("mn");

    } catch (IOException e) {

    e.printStackTrace();

    } finally {

    if (fw != null) {//防止空指针异常----->运行时异常要做健壮性判断

    try {

    fw.close();

    } catch (IOException e) {

    throw new RuntimeException("关闭异常");

    }

    }

    }

    }

    }

    小细节:当指定绝对路径时,定义目录分隔符有两种方式:

    1,反斜线,但是一定要写两个。new FileWriter("c:\1.txt");

    2,斜线,一个即可。new FileWriter("c:/1.txt");

    10、读取字符流对象的两种方式

    读取一个已有的文本文件,将文本数据打印出来。

    方式一:一次读取一个字符

    import java.io.FileReader;

    import java.io.IOException;

    public class Demo3 {

    public static void main(String[] args) {

    FileReader fr =null;

    try {

    //1,创建一个文件读取流对象,和指定名称的文件相关联,要保证该文件是已经存在的。如果不存在,会发生异常。FileNotFoundException

    fr = new FileReader("e:\1.txt");

    //2,定义一个变量,用于记录读到的那个字符对应的二进制数值。char在0-65535之间,不存在就-1。

    int ch=0;

    //3,用循环读取文件中的数据

    while((ch=fr.read())!=-1){

    System.out.print((char)ch);

    }

    } catch (Exception e) {

    e.printStackTrace();

    finally{

    if(fr!=null){

    try {

    fr.close();

    } catch (IOException e) {

    e.printStackTrace();

    }

    }

    }

    }

    }

    方式二:将读取的字符放入一个字符数组中<较第一种效率要高得多>

    import java.io.FileReader;

    import java.io.IOException;

    public class Demo4 {

    public static void main(String[] args) {

    FileReader fr = null;

    try {

    //1,创建一个文件读取流对象,和指定名称的文件相关联,要保证该文件是已经存在的。如果不存在,会发生异常。FileNotFoundException

    fr = new FileReader("e:\1.txt");

    //2,定义一个字符数组,用于存储读到的字符。

    char[] ch = new char[1024];//长度通常是1024的整数倍

    //3,定义一个变量,用于记录读取字符的个数,读到末尾返回-1。

    int len = 0;

    //4,把读到的字符暂时存到buf数组中,read(char[])返回的是读到字符的个数。

    while ((len = fr.read(ch)) != -1) {

    System.out.print(new String(ch, 0, len));

    }//将字符数组转换成字符串输出

    } catch (Exception e) {

    e.printStackTrace();

    } finally {

    if (fr != null) {

    try {

    fr.close();

    } catch (IOException e) {

    e.printStackTrace();

    }

    }

    }

    }

    }

    11、复制文本文件的原理

    首先用一个读取流对象和一个文件进行关联,然后用一个写入流对象作为目地的,为了把读取流中的文件传输到目的地流对象中,我们就提供了一个字符数组,为了关联这个数组,所以读取流对象有一个read()方法与这个字符数组进行关联,同理,写入流对象也有一个write()方法与这个字符数组进行关联,这样2个流对象就相连接了,而这个字符数组就相当于一个中转站。

     

    e盘的文件复制到i盘中

    public class CopyFileTest {

    public static void main(String[] args) {

    File startfile = new File("e:\a.txt");

    File endfile = new File("i:\hello.txt");

    copyFile(startfile, endfile);

    }

    public static void copyFile(File startfile,File endfile){

    FileReader fr = null;

    FileWriter fw = null;

    try {

    //1,创建一个字符读取流读取与源数据相关联。

    fr = new FileReader(startfile);

    //2,创建一个存储数据的目的地。

    fw = new FileWriter(endfile);

    //3,创建一个字符数组将读取流对象和写入流对象相连接。

    char[] buf = new char[1024];

    //4,每次读取的长度不一样,所以定义一个变量.

    int len = 0;

    //5,用循环读取文件中的数据

    while((len = fr.read(buf))!=-1){//判断是否读取完没

    fw.write(buf,0,len); //为了只写入有效的数据

    }

    } catch (Exception e) {

    e.printStackTrace();

    } finally {

    if(fr!=null){

    try {

    fr.close();

    } catch (Exception e2) {

    throw new RuntimeException("读取流关闭失败");

    }

    }

    if(fw!=null){

    try {

    fw.close();

    } catch (Exception e2) {

    throw new RuntimeException("写入流关闭失败");

    }

    }

    }

    }

    }

    声明:为了减少代码的书写,以后出现的异常全使用抛出!

    三、字符流缓冲区

    1、字符缓冲区的原理

    其实就是将数组进行封装。变成对象后,方便于对缓冲区的操作,提高效率。并提供了对文本便捷操作的方法。readLine( )&newLine( )。

     

    缓冲区的基本思想就是对要处理的数据进行临时存储。譬如购物车以及篮子。

    原理:减少频繁的操作,给读取流对象和写入流对象提供中转站,相对于来回跑的麻烦,利用缓冲区的容量,可以一边先存储,满了后再写入的方式,这样就提高了效率。

    BufferedWriter的特有方法:newLine():跨平台的换行符。

    BufferedReader的特有方法:readLine():一次读一行,到行标记时,将行标记之前的字符数据作为字符串返回。当读到末尾时,返回null(返回的字符是不带回车符的)

    在使用缓冲区对象时,要明确,缓冲的存在是为了增强流的功能而存在的,所以在建立缓冲区对象时,要先有流对象存在。其实缓冲内部就是在使用流对象的方法,只不过加入了数组对数据进行了临时存储,为了提高操作数据的效率

    2、代码上的体现

    A:写入缓冲区对象-------->带缓冲区的写操作,一般都要进行刷新!

    建立缓冲区对象必须把流对象作为参数传递给缓冲区的构造函数。

    BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));

    bw.write("abcd");//将数据写入缓冲区

    bw.flush();//对缓冲区的数据进行刷新,将数据刷到目的地中

    bw.close();//关闭缓冲区,其实关闭的是被包装在内部的流对象。

    B:读取缓冲区对象

    BufferedReader br = new BufferedReader(new FileReader("b.txt"));

    String line = null;

    while((line= br.readLine)!=null){

    System.out.println(line);

    }

    br.chose();

    3readLine( )方法的原理

    其实缓冲区中的该方法,用的还是与缓冲区关联的流对象的read方法,只不过,每一次读到一个字符,先不进行具体操作,而是进行临时存储。当读到回车标记时,将临时容器中的数据一次性返回。----->StringBuilder调用了buff.read()将缓冲区中的数据存储到了该容器中。

    缓冲区的read()和流对象的read()方法的区别?

    流对象:从目的地一次读取一个字符

    缓冲区:通过流对象的read([])将一批数据读取到缓冲数组,然后在数组中一次取一个字符,内存比硬盘操作要高效。

    4、自定义缓冲区MyBufferedReader

    /*

     * 模拟一个缓冲区

     * 基于已有的缓冲区思想,我们可以从源读取用read方法。

     * 我们的缓冲区,应该是一个更高效的read读取方法。

     */

    public class MyBufferedReader extends Reader{

    private Reader r;

    private char[] buf = new char[1024];

    //用于记录缓冲区数据的个数

    private int count = 0,pos = 0;

    public MyBufferedReader(Reader r){

    this.r = r;

    }

    /**

     * 一次从缓冲区中取一个

     * @return 返回一个缓冲区中的字符

     * @throws IOException

     */

    public int myRead() throws IOException {

    //1,首先判断缓冲区中是否有数据,如果没有就从源中去拿。

    if(count == 0){

    //读取一批数据到缓冲数组buf中

    count = r.read(buf);

    pos = 0;

    }

    //2,当缓冲区中没数据了且源中也没有数据时,count自减1小于0时就返回-1结束.

    if(count < 0)

    return -1;

    //3,如果以上都不满足,那么从缓冲区中写入一个字符到新的文件中。

    char ch = buf[pos];

    pos++;

    count--;

    return ch;

    }

    /**

     * 按照文本特点,提供一个特有的操作文本的方法。

     * 一次读取一行文本,只要是到行结束符之前的文本即可。

     * @return 返回读取到的一行文本

     * @throws IOException

     * 原理:就是从缓冲区中取出数据,并存储到一个临时容器中。

     * 如果取到了回车符,就将临时容器中的数据转成字符串返回。

     */

    public String myReadLine() throws IOException{

    //1,定义一个临时容器,进行临时存储

    StringBuilder sb = new StringBuilder();

    //2,定义一个变量,接收读取到的字符对应的二进制数(ASCII),0-65535

    int ch = 0;

    while((ch = myRead()) != -1){

    //3,当读取到 时,直接跳出本次循环,进行下次循环

    if(ch == ' ')

    continue;

    //4,当读取到 时,直接跳出当前循环

    if(ch == ' ')

    return sb.toString();

    //5,当都没有读取到时,就将这些数据存储到临时容器中。

    sb.append((char)ch);

    }

    //6,当临时容器中的长度不等于0时,就输出字符。

    if(sb.length() != 0)

    return sb.toString();

    return null;

    }

    @Override

    public void close() throws IOException {

    }

    @Override

    public int read(char[] arg0, int arg1, int arg2) throws IOException {

    return 0;

    }

    }

    5、通过缓冲区的形式,对文本文件进行拷贝

    public class BufferCopyTest {

    public static void main(String[] args) throws IOException {

    BufferedReader br = new BufferedReader(new FileReader("e:\a.txt"));

    BufferedWriter bw = new BufferedWriter(new FileWriter("i:\copy.txt"));

    String line = null;

    while((line = br.readLine())!=null){//高效读操作

    bw.write(line);//高效写

    bw.newLine();//换行符

    bw.flush();

    }

    bw.close();

    br.close();

    }

    }

  • 相关阅读:
    LeetCode 295. Find Median from Data Stream (堆)
    LeetCode 292. Nim Game(博弈论)
    《JavaScript 模式》读书笔记(4)— 函数2
    《JavaScript 模式》读书笔记(4)— 函数1
    《JavaScript 模式》读书笔记(3)— 字面量和构造函数3
    《JavaScript 模式》读书笔记(3)— 字面量和构造函数2
    《JavaScript 模式》读书笔记(3)— 字面量和构造函数1
    《JavaScript 模式》读书笔记(2)— 基本技巧3
    《JavaScript 模式》读书笔记(2)— 基本技巧2
    《JavaScript 模式》读书笔记(2)— 基本技巧1
  • 原文地址:https://www.cnblogs.com/itxiaok/p/IO.html
Copyright © 2011-2022 走看看