zoukankan      html  css  js  c++  java
  • Java文件读写分析

    本文内容:IO流操作文件的细节分析;分析各种操作文件的方式。


    读写一个文件

    从一个示例开始分析,如何操作文件:

    
    /**
     * 向一个文件中写入数据
     * @throws IOException
     */
    private static void writeFile() throws IOException {
        File file = new File("D://tmp/a.txt");
        try (OutputStream outputStream = new FileOutputStream(file, false)) {
            outputStream.write("ABC".getBytes(StandardCharsets.UTF_8));
        }
    }
    
    /**
     * 从一个文件中读取数据
     * @throws IOException
     */
    private static void readFile() throws IOException {
        File file = new File("D://tmp/a.txt");
        try (FileInputStream inputStream = new FileInputStream(file)) {
            StringBuilder stringBuffer = new StringBuilder();
            int count;
            while ((count = inputStream.read()) != -1) {
                stringBuffer.append((char) count);
            }
            System.out.println(stringBuffer.toString());
        }
    }
    
    

    文件写入

    向一个文件写入数据时,首先新建一个文件,然后定义一个输出流,为什么数输出流?Java里的API都是面向JVM的,输入和输出也是面向jvm的,输入就是向jvm中输入,输出就是从jvm中输出;
    outputStream.write() 方法将一个字节数组写入到a.txt中,执行完该方法后文件中就有内容了。程序是如何写进去的?

     /**
     * Opens a file, with the specified name, for overwriting or appending.
     * @param name name of file to be opened
     * @param append whether the file is to be opened in append mode
     */
    private native void open0(String name, boolean append)
        throws FileNotFoundException;
    
    /**
     * Writes the specified byte to this file output stream.
     *
     * @param   b   the byte to be written.
     * @param   append   {@code true} if the write operation first
     *     advances the position to the end of file
     */
    private native void write(int b, boolean append) throws IOException;
    
    /**
     * Writes a sub array as a sequence of bytes.
     * @param b the data to be written
     * @param off the start offset in the data
     * @param len the number of bytes that are written
     * @param append {@code true} to first advance the position to the
     *     end of file
     * @exception IOException If an I/O error has occurred.
     */
    private native void writeBytes(byte b[], int off, int len, boolean append)
        throws IOException;
    
    private native void close0() throws IOException;
    

    从源码上看,文件写入需要三个步骤:1、打开一个文件,也就是获取文件的句柄;2、向文件中输出字节流;3、关闭输出流,释放资源;
    open0(String name, boolean append) 这个本地方法就是打开文件的方法,调用了操作系统的API。
    write(int b, boolean append)这个本地方法是最终的写入的方法,参数有两个:b[],append; b代表的是一个字节数组,append代表是否添加,false则会覆盖初始文件。

    文件读取

    与写入文件类似,文件读取同样也是相对与jvm,文件读取是向jvm中输入,所以是InputStream;

    private native int read0() throws IOException;
    
    /**
     * Reads a subarray as a sequence of bytes.
     * @param b the data to be written
     * @param off the start offset in the data
     * @param len the number of bytes that are written
     * @exception IOException If an I/O error has occurred.
     */
    private native int readBytes(byte b[], int off, int len) throws IOException;
    

    读取文件也是两种方法,一个字节一个字节地读,也能安装字节数组去读。步骤与文件写入类似:1、打开一个文件,也就是获取文件的句柄;2、从文件中读取字节流;3、关闭输入流,释放资源;

    细节分析

    字节数组读写的问题

    按照字节写入,是直接调用native方法获取文件句柄操作文件,并且是直接写入字节数组,但是如果是写入中文,就不一样了,UTF-8编码中汉字是3个字节,英文字母是1个字节;当然不同的编码方式还不一样。这样写入不会有问题,但是读取的时候,问题就来了,汉字是3个字节,不管是按照字节数组还是字节去读,都可能只读取了一个汉字的一半,这样读取出来的字节数组转成可视化的内容就会出现乱码。

    如果是从一个输入流到另外一个输出流,比如文件导出,就可以使用输入流读取的字节数组直接放到输出流中去。注意:读取到文件最后会返回-1,可以以此为分界点。

    private static void writeFile0() throws IOException {
        File fileA = new File("D://tmp/a.txt");
        File fileB = new File("D://tmp/b.txt");
        try (FileInputStream inputStream = new FileInputStream(fileA);
             OutputStream outputStream = new FileOutputStream(fileB)) {
            int count;
            byte[] bytes = new byte[64];
            while ((count = inputStream.read(bytes)) != -1) {
                outputStream.write(bytes, 0, count);
            }
        }
    }
    

    按照字符读取

    在Java API中提供了另外一种方式操作文件,那就是按照字符读取,也能按行读取。这种读取方式在文件和jvm中间加了一层缓冲区。

    private static void readFile1() throws IOException {
        File file = new File("D://tmp/a.txt");
        try (FileReader fileReader = new FileReader(file)) {
            BufferedReader bufferedReader = new BufferedReader(fileReader);
            int count;
            StringBuilder stringBuilder = new StringBuilder();
            while ((count = bufferedReader.read()) != -1) {
                // 还可以按行读取bufferedReader.readLine();
                stringBuilder.append((char) count);
            }
            System.out.println(stringBuilder.toString());
        }
    }
    
  • 相关阅读:
    zookeeper集群搭建2.7
    hadoop集群环境搭建
    Kettle(6.0) 参数方式连接数据库
    kettle数据同步的5中方案
    kettle 合并记录步骤中的 关键字段和 比较字段的说明
    KETTLE常见问题和优化
    Hbase与Oracle的比较
    EHCache
    hdu2014 青年歌手大奖赛_评委会打分【C++】
    hdu2013 蟠桃记【C++】
  • 原文地址:https://www.cnblogs.com/hello-daocaoren/p/11172478.html
Copyright © 2011-2022 走看看