• 全面掌握IO(输入/输出流)


    File类:

    程序中操作文件和目录都可以使用File类来完成即不管是文件还是目录都是使用File类来操作的,File能新建,删除,重命名文件和目录,但File不能访问文件内容本身,如果需要访问文件本身,则需要使用输入/输出流,该类是位于java.io包下的

    输入与输出IO:

    输入流:只能从中读取数据,而不能向其中写入数据(由InputStream(字节流)和Reader(字符流)作为基类)

    输出流:只能向其写入数据,而不能从中读取数据(由OutputStream(字节流)和Writer(字符流)作为基类)

    java的io总共涉及40多个类,但都是从这四个抽象基类中派生出来的

     

    InputStream最重要的三个read方法:

    Reader中的read方法:

    从这两个抽象类提供的方法就可以看出其实功能基本是一样的,只是操作的数据单元不一样而已

    由于InputStream与Reader都是抽象类,是不能进行实例化的,我们只能用他们的子类来创建实例,它们分别提供了一个子类用于读取文件的输入流:FileInputStream和

    FileReader,这两个子类都是节点流(与处理流相对)-----会直接与指定的文件关联而无包装。下面代码演示FileInputStream使用read(byte[] b):

    复制代码
    package xidian.sl.io;
    
    import java.io.FileInputStream;
    import java.io.FileReader;
    
    public class InputStreamTest {
        /**
         * 使用FileInputStream读取该类本身
         * */
        public static void FileInputStreamTest() throws Exception{
            FileInputStream fis = null;
            try{
            //创建字节输入流
            fis = new FileInputStream("src/xidian/sl/io/InputStreamTest.java");
            //创建一个长度为1024的字节数组来存取
            byte[] bbuf = new byte[1024];
            //用于保存实际读取的字节数
            int hasRead = 0;
            //使用循环来进行重复读取
            while((hasRead = fis.read(bbuf))> 0){
                //取出字节,将字节数组转化为字符串输出
                System.out.println(new String(bbuf, 0 , hasRead));
            }
            }finally{
                //关闭文件输入流
                fis.close();
            }
        }
        /**
         * 使用FileReader读取该类本身
         * */
        public static void FileReaderTest() throws Exception{    
            FileReader fr = null;
            try{
            //创建字节输入流
            fr = new FileReader("src/xidian/sl/io/InputStreamTest.java");
            //创建一个长度为1024的字节数组来存取
            char[] bbuf = new char[40];
            //用于保存实际读取的字节数
            int hasRead = 0;
            //使用循环来进行重复读取
            while((hasRead = fr.read(bbuf))> 0){
                //取出字节,将字节数组转化为字符串输出
                System.out.println(new String(bbuf, 0 , hasRead));
            }
            }finally{
                //关闭文件输入流
                fr.close();
            }
        }
        public static void main(String[] args) throws Exception{
            InputStreamTest.FileInputStreamTest();
            InputStreamTest.FileReaderTest();
        }
    }
    复制代码

    可以看到这两个子类的使用方式可以说是完全一样的,不过这里要注意一个问题:字节流FileInputStream是根据字节来读取的,而一个中文是占两个字节的,如果包含很多中文的文件被字节流分多次进行读取,可能会造成乱码,因为有可能会导致刚好将一个中文分两次读取,这样就会乱码了,因此如果中文包含多的话还是使用字符流FileReader比较好

    在字节流与字符流之间选择的规律:如果需要进行输入/输出的内容是文本内容,则应该考虑使用字符流,如果需要进行输入/输出的是二进制内容,则应该考虑使用字节流,因为字节流的功能比字符流强大,计算机中所有的数据都是二进制的,而字节流可以处理所有的二进制文件;

     

    OutputStream中最重要的write方法:

    Writer中最重要的write方法:

    Writer类中多了两个对字符串的操作类,因此如果是直接输出字符串就选用Writer会比较的方便;

    与输入流一样,输出流也有两个文件操作的子类:FileOutputStream和FileWrite

    复制代码
    package xidian.sl.io;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.FileWriter;
    
    public class OutputStreamTest {
        /**
         * 使用字节流输出
         * */
        public static void FileOutputStreamTest() throws Exception{
            FileInputStream fis = null;
            FileOutputStream fos = null;
            try{
                //创建字节输入流
                fis = new FileInputStream("src/xidian/sl/io/InputStreamTest.java");
                //创建字节输出流
                fos = new FileOutputStream("src/xidian/sl/io/Output.txt");
                byte[] bt = new byte[40];
                int hasRead = 0;
                //循环从输入流中读取数据
                while((hasRead = fis.read(bt))> 0){
                    //每读取一个,即写入文件输出流,读了多少就写多少
                    fos.write(bt, 0, hasRead);
                }
                
            }catch (Exception e) {
                e.printStackTrace();
            }finally{
                /**
                 * 流在关闭时会自动执行flash,将缓冲中的数据flush到物理节点中
                 * 所以关闭时很重要的
                 * */
                if(fis != null){
                    fis.close();
                }
                if(fos != null){
                    fos.close();
                }
            }
        }
        /**
         * 使用字符流输出字符串会显得比较的方便
         * */
        public static void FileWriteTest() throws Exception{
            FileWriter fw = null;
            try{
                //创建字节输出流
                fw = new FileWriter("src/xidian/sl/io/Output.txt");
                fw.write("温州医学院
    ");
                fw.write("信息与管理专业
    ");
                fw.write("温州医学院
    ");
                fw.write("温州医学院
    ");
                fw.write("温州医学院");
            }catch (Exception e) {
                e.printStackTrace();
            }finally{
                if(fw != null){
                    fw.close();
                }
            }
        }
        public static void main(String[] args) throws Exception{
            OutputStreamTest.FileOutputStreamTest();
            OutputStreamTest.FileWriteTest();
        }
    }
    复制代码


     

    上面是节点流的基本使用,下面将了解处理流的使用,处理流会显得更加的高效

    区分节点流于处理流的方法是:只要流的构造器的参数不是一个物理节点,而是已存在的流,那这个流一定是处理流,因为所有的节点流都是直接以物理io节点作为构造器的参数、

    (如file)。

    举例:PrintStream处理流来封装FileOutputStream节点流,进行输出,由于PrintStream类的输出功能非常的强大,因此我们需要输出文本内容一般都会将输出流包装成PrintStream后输出

    复制代码
    package xidian.sl.io;
    
    import java.io.FileOutputStream;
    import java.io.PrintStream;
    
    public class PrintStreamTest {
        public static void main(String[] args){
            PrintStream ps = null;
            try{
                //创建一个节点输出流
                FileOutputStream fos = new FileOutputStream("src/xidian/sl/io/Output.txt");
                //以PrintStream处理流来包装FileOutputStream节点流
                ps = new PrintStream(fos);
                ps.println("普通字符串");
                ps.println(new PrintStreamTest());
            }catch (Exception e) {
                e.printStackTrace();
            }finally{
                ps.close();
            }
        }
    }
    复制代码

    其实我们一直使用的标准输出System.out的类型都是PrintStream:

    从上面的实例就可以看出将节点流封装成处理流很简单,只需调用处理流的构造方法来传入节点流就可以了;而且看到上面流的关闭只是关闭了处理流而未去关闭节点流,这样做是完全正确的,以后我们在关闭流的时候只需要关闭最上层的处理流即可

     

    字符流中有两个特别的流来处理字符串的:StringReader和StringWriter,

    可以看到使用时实例化只需要传入一个字符串即可:例子:

    复制代码
    package xidian.sl.io;
    
    import java.io.StringReader;
    import java.io.StringWriter;
    
    public class StringNodeTest {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            String src = "你是个神";
            StringReader sr = new StringReader(src);
            char[] chars = new char[40];
            int hasRead = 0;
            try{
                //采用循环的方式
                while((hasRead = sr.read(chars))>0){
                    System.out.println(new String(chars, 0, hasRead));
                }
            }catch (Exception e) {
                e.printStackTrace();
            }finally{
                sr.close();
            }
            //创建StringWriter
            StringWriter sw = new StringWriter(40);
            sw.write("你是一个大神");
            sw.write("你也是一个大神");
            System.out.println(sw.toString());
            
        }
    
    }
    复制代码


    io系统提供的两个转换流:InputStreamReader和OutputStreamWriter,都是将字节流转化为字符流

    在java中是使用System.in来提供键盘输入的,但这个标准输入流是InputStream类的实例:

    而前面讲到了当处理的是文本内容时,使用字符流会显得比较方便,正好键盘输入就是文本的操作,因此我们有必须将System.in转换为字符流:

    复制代码
    package xidian.sl.io;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    public class KeyinTest {
        public static void main(String[] args){
            BufferedReader br = null;
            try{
                //将System.in对象转化为Reader对象
                InputStreamReader isr = new InputStreamReader(System.in);
                //将节点流包装为处理流
                br = new BufferedReader(isr);
                String buffer = null;
                //采用循环的方式一行一行读取
                while((buffer = br.readLine()) != null){
                    System.out.print("输入的内容 = "+ buffer);
                }
            }catch (Exception e) {
                e.printStackTrace();
            }finally{
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    复制代码

    PrintStream是有强大的输出功能,而BufferReader有强大的输入(即读取),因此在操作读取文本内容时尽可能将其转化为BufferReader,可以方便的使用readLine()方法

     

     接下来最为强大的文件操作类RandomAccessFile来了,这个类既可以向文件输入数据,也可以输出数据,并且他与不同的流最大的不同就是“支持文件任意位置的访问”,即程序可以控制读取文件哪个位置的内容;

    从构造方法上可以看出,除了提供一个文件或文件名外还需要提供一个String参数mode,mode规定了RandomAccessFile类访问文件的模式:

    1. “r”:以只读的方式打开指定文件

    2. “rw”:以读取,写入方式打开指定文件,并且文件不存在会自动进行创建

    3.“rws”与“rwd”:与“rw”类似,只是要求文件内容或元数据的每个更新都同步写入底层存储设备

     

     

     

     

     

     

    希望多多交流,多多关注,共同成就梦想
  • 相关阅读:
    javaScript学习日记 1 数组
    总结css中单位px和em,rem的区别
    读书摘要
    读书摘要
    各种官方网站汇集
    js相关参考资料
    Node相关参考资料
    Angular【学习笔记】
    Node连接MySQL
    em 和 px相互转换
  • 原文地址:https://www.cnblogs.com/guoyaohua/p/8502918.html
Copyright © 2020-2023  润新知