1.File
在计算机中目录结构如下:
 
 而File就表示一个目录或者一个普通文件。
File表示目录:
 
 File表示普通文件:
 
 我们先来看File的构造方法:
| 构造器 | 描述 | 
|---|---|
| File(File parent, String child) | 根据父目录 + 孩子文件路径,创建一个新的 File 实例 | 
| File(String pathname) | 根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径 | 
| File(String parent, String child) | 根据父目录 + 孩子文件路径,创建一个新的 File 实例 | 
| File(URI uri) | 通过uri来创建一个File 实例 | 
但是通常都用File(String pathname)这个构造器来创建File对象,其他的构造器比较少用。
创建File实例:
public class CreateFileObject {
    public static void main(String[] args) {
        File file = new File("blog/dir/tmp.txt");
    }
}
 
File类常用的方法基本都在下面了:
| 返回类型 | 方法名 | 描述 | 
|---|---|---|
| String | getParent() | 返回 File 对象的父目录文件路径 | 
| String | getName() | 返回 FIle 对象的纯文件名称 | 
| String | getPath() | 返回 File 对象的文件路径 | 
| String | getAbsolutePath() | 返回 File 对象的绝对路径 | 
| String | getCanonicalPath() | 返回 File 对象的修饰过的绝对路径 | 
| boolean | exists() | 判断 File 对象描述的文件是否真实存在 | 
| boolean | isDirectory() | 判断 File 对象代表的文件是否是一个目录 | 
| boolean | isFile() | 判断 File 对象代表的文件是否是一个普通文件 | 
| boolean | createNewFile() | 根据 File 对象,自动创建一个空文件。成功创建后返回 true | 
| boolean | delete() | 根据 File 对象,删除该文件。成功删除后返回 true | 
| void | deleteOnExit() | 根据 File 对象,标注文件将被删除,删除动作会到JVM 运行结束时才会进行 | 
| String[] | list() | 返回 File 对象代表的目录下的所有文件名 | 
| File[] | listFiles() | 返回 File 对象代表的目录下的所有文件,以 File 对象表示 | 
| boolean | mkdir() | 创建 File 对象代表的目录 | 
| boolean | mkdirs() | 创建 File 对象代表的目录,如果必要,会创建中间目录 | 
| boolean | renameTo(File dest) | 进行文件改名 | 
| boolean | canRead() | 判断用户是否对文件有可读权限 | 
| boolean | canWrite() | 判断用户是否对文件有可写权限 | 
补充一个文件路径的小知识:
| . | 表示当前路径 | 
| .. | 表示上级目录 | 
mkdirs()、getName()、getParent()、getPath()、getAbsolutePath()、getCanonicalPath()的使用
目录结构:
 
代码:
public class MethodTest1 {
    public static void main(String[] args) throws IOException {
        File file = new File("io/src/blog/dir/./tmp");
        //创建dir目录并且会创建tmp这个目录
        file.mkdirs();
        //获取文件的名称
        String filename = file.getName();
        System.out.println("文件名->: " + filename);
        //获取父目录的相对路径
        String parent = file.getParent();
        System.out.println("父目录的相对路径->: " + parent);
        //获取相对路径
        String path = file.getPath();
        System.out.println("相对路径->: " + path);
        //获取绝对路径
        String absPath = file.getAbsolutePath();
        System.out.println("绝对路径->: " + absPath);
        //获取修饰后的绝对路径
        String absPathMod = file.getCanonicalPath();
        System.out.println("修饰后的绝对路径->: " + absPathMod);
    }
}
 
结果:
文件名->: tmp
父目录的相对路径->: io\src\blog\dir\.
相对路径->: io\src\blog\dir\.\tmp
绝对路径->: H:\gitee\IdeaProgram\JavaEE\io\src\blog\dir\.\tmp
修饰后的绝对路径->: H:\gitee\IdeaProgram\JavaEE\io\src\blog\dir\tmp
 
exists()、isFile()、isDirectory()、list()、listFiles()的使用
目录结构:
 
 代码:
public class MethodTest2 {
    public static void main(String[] args) {
        File file = new File("io/src/blog/dir/./tmp");
        //判断文件是否存在
        boolean isExists = file.exists();
        System.out.println("文件是否存在->: " + isExists);
        //判断是否为普通文件,比如xxx.txt
        boolean isFile = file.isFile();
        System.out.println("是否为普通文件->: " + isFile);
        //判断是否是一个目录
        boolean isDirctory = file.isDirectory();
        System.out.println("是否为一个目录->: " + isDirctory);
        //列出这个目录下面所有的文件,以String表示
        String[] list = file.list();
        System.out.println("tmp目录下所有的文件->: " + Arrays.toString(list));
        //列出这个目录下面所有的文件,以File对象表示
        File[] files = file.listFiles();
        System.out.println("tmp目录下所有的文件->: " + Arrays.toString(files));
    }
}
 
结果:
文件是否存在->: true
是否为普通文件->: false
是否为一个目录->: true
tmp目录下所有的文件->: [a.txt, b.txt]
tmp目录下所有的文件->: [io\src\blog\dir\.\tmp\a.txt, io\src\blog\dir\.\tmp\b.txt]
 
canRead()、canWrite()、renameTo()、delete()的使用
代码:
public class MethodTest3 {
    public static void main(String[] args) throws IOException {
        File file = new File("io/src/blog/dir/./tmp");
        //判断是否可读
        boolean canRead = file.canRead();
        System.out.println("是否可读->: " + canRead);
        //是否可写
        boolean canWrite = file.canWrite();
        System.out.println("是否可写->: " + canWrite);
        //改名为file_tmp
        file.renameTo(new File("io/src/blog/dir/./file_tmp"));
        //删除下面的一个.txt后缀文件
        File removeFile = new File("io/src/blog/dir/./file_tmp/a.txt");
        boolean ret = removeFile.delete();
        System.out.println("是否删除成功->: " + ret);
    }
}
 
结果:
是否可读->: true
是否可写->: true
是否删除成功->: true
 
2.InputStream
InputStream可以认为是输入设备和内存(Memory)之间的一个流,而且数据流向是从输入设备(input device)到内存(Memory)的。
 
我们创建了一个InputStream,就相当于创建了一个输入流对象,可以从输入设备上读数据到内存中。
InputStream官方声明:
public abstract class InputStream
extends Object
implements Closeable
 
常用的方法:
| 方法 | 描述 | 
|---|---|
| abstract int read() | 从输入流读取一个字节(byte)的数据,并返回 | 
| int read(byte[] b ) | 从输入流读取一些字节并存到b这个数组中 (读取多少个字节,取决于b数组的大小和文件中数据有多少)  | 
| int read(byte[] b, int off, int len) | 最多读取len个字节到b数组中,从指定数组下标开始 | 
| void close() | 关闭输入流,释放资源 | 
因为InputStream是抽象类,所以我们还得找这个类的子类。
 InputStream的子类比较多,这里以FileInputStream举例,即文件流,也是经常使用的一个流。
文件流的输入设备就是磁盘(disk),更具体一点就是文件(File)。
 
FileInputStream的声明:
public class FileInputStream extends InputStream
 
FileInputStream常用的构造器:
| 构造器 | 描述 | 
|---|---|
| FileInputStream(File file) | 根据File对象创建一个输入流 | 
| FileInputStream(String name) | 根据文件名创建一个输入流 | 
下面是文件中的数据:
文件:filetest.txt
abcdefghijk
 
read()方法使用:
public static void test1() {
    InputStream inputStream = null;
    try {
        //创建FileInputStream输入流对象
        inputStream = new FileInputStream("io/filetest.txt");
        //读取一个字节的数据,返回-1表示到达文件末尾
        int data = inputStream.read();
        //输出
        System.out.println("data->: " + data);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //关闭资源
        try {
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 
结果:
data->: 97
 
int read(byte[] b)方法使用
public static void test2() {
   InputStream inputStream = null;
   try {
       //创建FileInputStream输入流对象
       inputStream = new FileInputStream("io/filetest.txt");
       //读取数据到bytes数组中,返回读取到的字节数,返回-1表示到文件末尾,
       byte[] bytes = new byte[32];
       int ret = inputStream.read(bytes);
       //输出
       System.out.println(Arrays.toString(bytes));
   } catch (IOException e) {
       e.printStackTrace();
   } finally {
       //关闭资源
       try {
           inputStream.close();
       } catch (IOException e) {
           e.printStackTrace();
       }
   }
}
 
结果:
[97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
 
int read(byte[] b, int off, int len)方法使用:
public static void test3() {
    InputStream inputStream = null;
    try {
        //创建FileInputStream输入流对象
        inputStream = new FileInputStream("io/filetest.txt");
        //读取数据写到bytes数组指定的位置
        byte[] b = new byte[32];
        int ret2 = inputStream.read(b, 10, 10);
        //输出
        System.out.println(Arrays.toString(b));
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //关闭资源
        try {
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 
结果:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
 
不知道你有没有觉得上面的try…catch…finally这种写法有点繁琐,说白了就是丑😣。
 上面的写法跟下面的等价。
    public static void test() throws IOException {
        try (InputStream inputStream = new FileInputStream("io/filetest.txt")) {
            //读取一个字节的数据,返回-1表示到达文件末尾
            int data = inputStream.read();
            //输出
            System.out.println("data->: " + data);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
这种写法叫,try-with-resource可以自动帮助我们释放资源,即自动调用close()方法。
- 当发生异常时,能自动调用close()方法,帮助我们释放资源。
但是并不是所有类都能这样用,只有实现AutoCloseable或者Closeable接口的类,并且重写close()方法才能用这种语法。 
AutoCloseable和Closeable的关系:
public interface Closeable
extends AutoCloseable
 
底层释放资源伪代码如下:
AutoCloseable o = (AutoCloseable)inputStream;
o.close();
 
- 这里只是伪代码,帮助我们理解,而底层实现跟这个不一样。
 
3.OutputStream
OutputStream是从内存(Memory)到输出设备(output device)的一个流,且流向从内存到输出设备的。

官方声明:
public abstract class OutputStream
extends Object
implements Closeable, Flushable
 
常用的方法:
| 方法 | 描述 | 
|---|---|
| abstract void write(int b) | 写入低八位的数据,后24位的数据是不会写入的 | 
| void write(byte[] b) | 将b数组中的全部字节写入到文件中 | 
| void write(byte[] b, int off, int len) | 从off这个位置开始,将数组b的字节写到文件中 | 
| void close() | 关闭输出流,释放资源 | 
| void flush() | 刷新内存中的缓冲区,把缓冲区的数据写入文件中 | 
调用输出设备flush()方法执行的过程如下:
 
OutputStream也是抽象类,最常用的子类是FileOutputStream(文件输出流)。
 
FileOutputStream常用的构造器:
| 构造器 | 描述 | 
|---|---|
| FileOutputStream(File file) | 根据File对象创建一个输出流 | 
| FileOutputStream(String name) | 根据文件名创建一个输出流 | 
| FileOutputStream(File file, boolean append) | 根据File对象创建一个输出流 并且指定是否可追加  | 
| FileOutputStream(String name, boolean append) | 根据文件名创建一个输出流 并且指定是否可追加  | 
example:
public class OutputStreamTest {
    public static void main(String[] args) throws IOException {
        //文件路径
        String path = "./io/filetest.txt";
        //创建文件输出流对象
        try ( FileOutputStream fileOutputStream = new FileOutputStream(path)) {
            //调用wirite(int b)方法, 将
            fileOutputStream.write(1);
            //调用write(byte[] b)方法,将byte数组里的每个字节写入文件
            fileOutputStream.write(new byte[]{2, 3, 4});
        }
    }
}
 
文件内容:
 
 在idea中显示的内容:
 
 ascii码表:
 
-  
因为文件是二进制文件,以字节为单位,1对应了中的SOH
2对应STX,3对应ETX,4对应EOT。 -  
记事本是不会显示控制字符的,会用其他的字符代替,所以就出现了乱码。而在idea中打开就可以显示每个字节对应的字符。
 
追加的方式打开文件并写入byte数组:
public class OutputStreamTest2 {
    public static void main(String[] args) {
        appendConstructorTest();
    }
    public static void appendConstructorTest() {
        //路径
        String path = "io/filetest.txt";
        //以追加的方式打开文件输出流
        try (FileOutputStream fileOutputStream = new FileOutputStream(path, true)) {
            //把byte数组写入文件
            fileOutputStream.write(new byte[]{5, 6, 7});
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 
结果:
 
寄语
 清风拂来头发飞扬,指间跳动理想锋芒。


















