• 【Java】基本I/O的学习总结


    计算机I/O

    理解IO先要知道计算机对数据的输入输出是怎么处理的,下面一张图可以大致理解:

    可以看出所谓输入是外部数据向CPU输入,而输出是CPU将数据输出到我们可见的地方,例如文件、屏幕等。而计算机通常是通过流来传递数据。

    Java I/O

    Java中的IO包中的类可以处理不同类型的流,例如:字节流(byte[])、字符流(character)、文件流、对象流等。
    java.io中的抽象类:

    • 处理字节流的抽象类:InputStream和OutputStream
    • 处理过滤流的抽象类:FilterOutputStream和FilterInputStream
    • 处理字符流的抽象类:Reader和Writer
    • 处理压缩流的抽象类:InflaterInputStream和DeflaterOutputStream
      它们之间的关系如下:

    字符流

    输入流Reader

    基本的字符输入流的类结构如下,每个类的作用从类名大致可以猜出:

    这里想强调的是出现的设计模式————装饰器模式:

    例如其中BufferedReader是对Reader接口的其他子类的一个装饰器,封装了其他Reader接口实现类,提供更方便的方法调用。
    BufferedReader的构造器如下,初始化时需要传入一个对Reader接口的实现类的对象:

    public BufferedReader(Reader in){}
    

    实例代码,读取指定路径的文件内容并输出:

    public class ReaderTest {
        public static String read(String path) throws IOException {
            //装饰器模式,BufferedReader包装了FileReader
            BufferedReader reader = new BufferedReader(new FileReader(path));
            String s;
            StringBuilder sb = new StringBuilder();
            while ((s = reader.readLine()) != null) {
                sb.append(s + "
    ");
            }
            reader.close();
            return sb.toString();
        }
    
        public static void main(String[] args) throws IOException {
            System.out.println(read("D:/test.txt"));
        }
    }
    

    可以看出BufferedReader封装了FileReader来提供更方便的文件输入功能。

    输出流Writer

    类比输出流,输出流很容易理解,类关系如下:

    同样也用到了装饰器模式,下面直接用代码来说明问题,这段代码目的是将in.txt的内容写到out.txt中:

    public class WriterTest {
        public static void main(String[] args) throws IOException{
            String inFile = "D:/in.txt";
            String outFile = "D:/out.txt";
            BufferedReader in = new BufferedReader(new StringReader(ReaderTest.read(inFile)));
            PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(outFile)));
            String s;
            int line = 1;
            while ((s = in.readLine()) != null) {
                out.println(line++ + ":" + s);
            }
            in.close();
            out.close();
            System.out.println(ReaderTest.read(outFile));
        }
    }
    

    我们可以看出BufferedReader封装了StringReader,BufferedWriter封装了FileWriter。

    字符流就说这么多吧,具体的类用的时候再去了解也不迟。

    字节流

    输入流InputStream

    InputStream是以字节流来读取文件的,如果文件是图片或二进制等格式,则不能以字符流来读,需要InputStream来读取。

    InputStream的子类关系如下图:

    值得注意的是,字节流也可以转换成字节流,利用的是InputStreamReader类,该类封装了InputStream。下面的实例代码通过两种不同的方式来读取文件内容。其中readByStream是通过字节流,而readByReader是字符流。

    public class InputStreamTest {
        public static void readByStream(String path) {
            File f = new File(path);
            try {
                InputStream in = new FileInputStream(f);
                int b;
                while ((b=in.read()) != -1) {
                    char c = (char)b;
                    System.out.printf("%c", c);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static void readByReader(String path) {
            File f = new File(path);
            try {
                InputStream in = new FileInputStream(f);
                BufferedReader reader = new BufferedReader(new InputStreamReader(in, "utf-8"));
                String string;
                StringBuilder sb = new StringBuilder();
                while ((string = reader.readLine()) != null) {
                    sb.append(string);
                }
                System.out.println(sb.toString());
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            String path = "D:/test.txt";
            readByReader(path);
            readByStream(path);
        }
    }
    

    另外,值得注意的是,如果要读取中文,建议使用字符流,因为一个汉字占两个字节,而InputStream每次只会读取一个字节,因此会乱码。而InputStreamReader有一个构造函数可以设置文件编码,如上述代码中的new InputStreamReader(in, "utf-8")指定了文件编码问utf-8,因此可以很好的解决中文乱码问题。

    输出流OutputStream

    输出流OutputStream的作用类比于Writer,也非常容易理解,即通过字节流来把数据输出到文件、磁盘等设备中。关系如下图。

    同InputStream一样,也有一个OutputStreamWriter包装了OutputStream,代码很简单我就不举例了。

    RandomAccessFile 随机存取

    上面这两大类IO,虽然结构清晰,但是多少还是复杂了点,于是乎,Java封装了一个文件随机存取类————RandomAccessFile。

    RandomAccessFile实现了两个接口,DataInput和DataOutput,因此它同时拥有读和写两个功能,方便了我们的使用。使用时需要指定打开文件的模式,可以是“r”只读,“rw”读写等。下面是实例代码:

    public class RandomAccessTest {
        public static void main(String[] args) {
            String filePath = "D:" + File.separator + "test.txt";
            File f = new File(filePath);
            try {
                RandomAccessFile write = new RandomAccessFile(f, "rw");
                String str = "abc, hello, randomAccess!";
                //把byte[]中的字节写入文件
                write.write(str.getBytes());
                System.out.println("写入文件完成...");
    
                RandomAccessFile read = new RandomAccessFile(f, "rw");
                String strRead;
                StringBuilder sb = new StringBuilder();
                while ((strRead = read.readLine()) != null) {
                    sb.append(strRead);
                }
                System.out.println("读取文件内容:" + sb.toString());
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    }
  • 相关阅读:
    PythonI/O进阶学习笔记_2.魔法函数
    FTPClient下载文件,程序假死问题
    mui搜索框在ios平台上点击多次才弹出键盘的解决方法
    用UL+Li 实现横向导航条时设定宽度
    asp.net 用cache保存对象
    QQ Tea加密解密单元 Delphi
    关于在Webservice里使用LinqToSQL遇到一对多关系的父子表中子表需要ToList输出泛型而产生循环引用错误的解决办法!
    ExtJS中从WebService获取数据保存到本地,填充GridPanel实现静态数据分页
    .net 3.5 sp1 编译器发布的网站无法在没有打SP1补丁的主机上使用
    在ashx中使用session
  • 原文地址:https://www.cnblogs.com/puyangsky/p/5785637.html
Copyright © 2020-2023  润新知