java基础之-I/O流和File类解析

在日常的java开发中少不了文件的读取和 写入,这就涉及到文件的I/O操作,今天就来总结下文件的IO操作,顺便文件的IO操作也需要File了的帮助,所以一起总结了。

以下图片为我根据其他博客所总结的内容进行了相应的总结和IO流的类结构图,类结构图中还少了几个类

简单描述下:

IO分为字节和字符流2中方式,字节流以byte为单位,字符流以字符为单位,1个字节8byte 0·255,字节流的抽象类为inputstream和outputstream,他们无法实例化,所以需要

其子类来实现。字符流通常按2个字节来表示则为16byte,字符流的抽象类为reader和writer。

字符流通常是需要将文件读取到内存才能进行操作的,而字节流则是直接操作文件的。

 

 还是通过具体的例子来说明吧。


@Test
public void testFileReader() throws IOException {
File file = new File("D:/train/train.txt");
FileInputStream fs = new FileInputStream(file);
InputStreamReader reader = new InputStreamReader(fs,"utf8");
BufferedReader bufferedReader = new BufferedReader(reader);
System.out.println(bufferedReader.readLine());
// 关闭文件流
bufferedReader.flush();

bufferedReader.close();
reader.close();
fs.close();

}

@Test
public void testFileOut() throws IOException {
File file = new File("D:/train/train.txt");
FileOutputStream out = new FileOutputStream(file);
String str = "hello world";
out.write(str.getBytes("utf8"));
out.close();

}
 

 上面的代码包含了文件的读取和文件的写入,包含字符集设置,读取操作其实可以包含了IO中绝大多数的操作了。需要注意的是不管是字节流,还是字符流他们的read()方法返回的结果都是int类型,需要将其转换成char类型。具体的源码可以根据类的结构树去查看。

一上为简单总结了IO流,下面是File类的总结:

 File -> FileSystem -> WinNTFileSystem

操作文件其实通过操作系统的文件功能来实现的,不同的系统如windows和UNIX其实是不同的,新建的File通过getFileSystem()方法获取系统操作文件的权限,每个新建的文件都包含2个重要参数path和prefixLength

 /**
     * This abstract pathname's normalized pathname string. A normalized
     * pathname string uses the default name-separator character and does not
     * contain any duplicate or redundant separators.
     * 这个抽象路径的正常路径名称,"d:/program file/train"这种格式
     * @serial
     */
    private final String path;

 /**
     * The length of this abstract pathname's prefix, or zero if it has no
     * prefix. 抽象路径的前缀长度,不存在则为0
     */
    private final transient int prefixLength;

 

 文件系统的操作其实很多都是通过这个前缀来创建文件的。

通过看源码可以发现,File类其实有点像接口,而WinNTFileSystem类则像实现接口。

看下File的构造函数,其中通过uri的构造函数没有贴出,有需要可以自己去查阅

/**
     * Creates a new <code>File</code> instance by converting the given
     * pathname string into an abstract pathname.  If the given string is
     * the empty string, then the result is the empty abstract pathname.
     *
     * @param   pathname  A pathname string
     * @throws  NullPointerException
     *          If the <code>pathname</code> argument is <code>null</code> 最通用给构造函数,通过文件路径来创建文件
     */
    public File(String pathname) {
        if (pathname == null) {
            throw new NullPointerException();
        }
        this.path = fs.normalize(pathname);
        this.prefixLength = fs.prefixLength(this.path);
    }

 /**
     * Creates a new <code>File</code> instance from a parent pathname string
     * and a child pathname string.
     *
     * <p> If <code>parent</code> is <code>null</code> then the new
     * <code>File</code> instance is created as if by invoking the
     * single-argument <code>File</code> constructor on the given
     * <code>child</code> pathname string.
     *
     * <p> Otherwise the <code>parent</code> pathname string is taken to denote
     * a directory, and the <code>child</code> pathname string is taken to
     * denote either a directory or a file.  If the <code>child</code> pathname
     * string is absolute then it is converted into a relative pathname in a
     * system-dependent way.  If <code>parent</code> is the empty string then
     * the new <code>File</code> instance is created by converting
     * <code>child</code> into an abstract pathname and resolving the result
     * against a system-dependent default directory.  Otherwise each pathname
     * string is converted into an abstract pathname and the child abstract
     * pathname is resolved against the parent.
     * 通过父路径和子路径来创建文件
     * @param   parent  The parent pathname string
     * @param   child   The child pathname string
     * @throws  NullPointerException
     *          If <code>child</code> is <code>null</code>
     */
    public File(String parent, String child) {
        if (child == null) {
            throw new NullPointerException();
        }
        if (parent != null) {
            if (parent.equals("")) {
                this.path = fs.resolve(fs.getDefaultParent(), -->"/"
                                       fs.normalize(child));
            } else {
                this.path = fs.resolve(fs.normalize(parent),
                                       fs.normalize(child));
            }
        } else {
            this.path = fs.normalize(child);
        }
        this.prefixLength = fs.prefixLength(this.path);
    }

 /** 通过父文件和子路径来创建文件
     * Creates a new <code>File</code> instance from a parent abstract
     * pathname and a child pathname string.
     *
     * <p> If <code>parent</code> is <code>null</code> then the new
     * <code>File</code> instance is created as if by invoking the
     * single-argument <code>File</code> constructor on the given
     * <code>child</code> pathname string.
     *
     * <p> Otherwise the <code>parent</code> abstract pathname is taken to
     * denote a directory, and the <code>child</code> pathname string is taken
     * to denote either a directory or a file.  If the <code>child</code>
     * pathname string is absolute then it is converted into a relative
     * pathname in a system-dependent way.  If <code>parent</code> is the empty
     * abstract pathname then the new <code>File</code> instance is created by
     * converting <code>child</code> into an abstract pathname and resolving
     * the result against a system-dependent default directory.  Otherwise each
     * pathname string is converted into an abstract pathname and the child
     * abstract pathname is resolved against the parent.
     *
     * @param   parent  The parent abstract pathname
     * @param   child   The child pathname string
     * @throws  NullPointerException
     *          If <code>child</code> is <code>null</code>
     */
    public File(File parent, String child) {
        if (child == null) {
            throw new NullPointerException();
        }
        if (parent != null) {
            if (parent.path.equals("")) {
                this.path = fs.resolve(fs.getDefaultParent(),
                                       fs.normalize(child));
            } else {
                this.path = fs.resolve(parent.path,   --> 将父文件转换成路径,然后和子路径拼接
                                       fs.normalize(child));
            }
        } else {
            this.path = fs.normalize(child);
        }
        this.prefixLength = fs.prefixLength(this.path);
    }

 其他的一些方法如创建新文件,creatNewFile(),创建文件夹mkdir(),mkdirs()等方法,相信看下源码就能很清楚了。

 

posted @ 2019-03-23 16:51  主宰-  阅读(394)  评论(0编辑  收藏  举报