1、基础概念
1.1、文件(File)
文件的读写可以说是开发中必不可少的部分,因为系统会存在大量处理设备上的数据,这里的设备指硬盘,内存,键盘录入,网络传输等。当然这里需要考虑的问题不仅仅是实现,还包括同步,读写熟读,文件类型等等都需要考虑在具体的项目中。
       Java 的标准库 java.io 提供了File类的实例对象来操作文件
1.2、流(Stream)
I/O是Input/Output的缩写, I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。
Java程序中,对于数据的输入/输出操作以“流(stream)” 的方式进行。
java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。
2、文件(File)
2.1、File类创建
| 名称 | 说明 | 
| public File(String pathname) | 根据文件路径创建对象 | 
| public File(String parent,String child) | 从父路径名字符串和子路径名字字符串创建文件对象 | 
| public File(File parent,String child) | 根据父路径对应文件对象和子路径名字字符串创建对象 | 
2.2、常用方法
public String getAbsolutePath() 获取绝对路径
public String getPath() 获取路径
public String getName() 获取名称
public String getParent() 获取上层文件目录路径。若无,返回null
public long length() 获取文件长度(即:字节数)。不能获取目录的长度。
public long lastModified() 获取最后一次的修改时间,毫秒值
public String[] list() 获取指定目录下的所有文件或者文件目录的字符串数组
public File[] listFiles() 获取指定目录下的所有文件或者文件目录的File对象数组
public boolean isDirectory() 判断是否是文件目录
public boolean isFile() 判断是否是文件
public boolean exists() 判断是否存在
public boolean canRead() 判断是否可读
public boolean canWrite() 判断是否可写
public boolean isHidden() 判断是否隐藏
2.3、实例
public class FileTest {
    public static void main(String[] args) throws IOException {
        //1、设置目录名称
        String filePath = "H:\\test";
        //2、设置文件名称
        String fileName = "test.txt";
        //添加文件目录
        File file = new File(filePath);
        //1、判断是否存在目录
        boolean exists = file.exists();
        System.out.println("路径"+filePath+"在磁盘中是否存在:"+exists);
        //2、不存在,创建目录
        if (!exists) {
            boolean b = file.mkdirs();// 在磁盘中指定路径下创建目录
            System.out.println("创建目录是否成功:"+b);
        }else {
            System.out.println("创建目录已经存在");
        }
        //3、再判断是否存在目录
        boolean exists1 = file.exists();
        System.out.println("路径"+filePath+"在磁盘中是否存在:"+exists1);
        //判断传入的抽象路径名是否是一个在磁盘中已存在的文件
        System.out.println("判断传入的抽象路径名是否是一个在磁盘中已存在的文件:"+file.isFile());// false
        //判断传入的抽象路径名是否是一个在磁盘中已存在的目录
        System.out.println("判断传入的抽象路径名是否是一个在磁盘中已存在的目录:"+file.isDirectory());// true
        System.out.println("获取绝对路径"+file.getAbsolutePath());
        System.out.println("获取路径"+file.getPath());
        System.out.println("获取名称"+file.getName());
        System.out.println("获取上层文件目录路径。若无,返回null"+file.getParent());
        System.out.println("获取文件长度(即:字节数)。不能获取目录的长度"+file.length());
        System.out.println("获取最后一次的修改时间,毫秒值"+new Date(file.lastModified()));
        System.out.println("获取指定目录下的所有文件或者文件目录的字符串数组:"+file.list());
        System.out.println("获取指定目录下的所有文件或者文件目录的File对象数组:"+file.listFiles());
        //从磁盘中删除指定文件路径下的文件或者文件目录
//        file.delete();
//        System.out.println("再次判断传入的抽象路径名(目录/普通文件)在磁盘中是否存在:"+file.exists());// false
        System.out.println("=================================================================================");
        //添加文件
        File f = new File(filePath,fileName);
        //1、判断是否存在目录
        boolean e = f.exists();
        System.out.println("路径"+filePath+"在磁盘中是否存在:"+e);
        //2、不存在,创建文件
        if (!e) {
            boolean b = f.createNewFile();
            System.out.println("创建文件是否成功:"+b);
        }else {
            System.out.println("创建文件已经存在");
        }
        //3、再判断是否存在目录
        boolean e1 = f.exists();
        System.out.println("路径"+filePath+"在磁盘中是否存在:"+e1);
        // 判断传入的抽象路径名是否是一个在磁盘中已存在的文件
        System.out.println("判断传入的抽象路径名是否是一个在磁盘中已存在的文件:"+f.isFile());// false
        // 判断传入的抽象路径名是否是一个在磁盘中已存在的目录
        System.out.println("判断传入的抽象路径名是否是一个在磁盘中已存在的目录:"+f.isDirectory());// true
        System.out.println("判断是否可读"+f.canRead());
        System.out.println("判断是否可写"+f.canWrite());
        System.out.println("判断是否隐藏"+f.isHidden());
        System.out.println("获取绝对路径"+f.getAbsolutePath());
        System.out.println("获取路径"+f.getPath());
        System.out.println("获取名称"+f.getName());
        System.out.println("获取上层文件目录路径。若无,返回null"+f.getParent());
        System.out.println("获取文件长度(即:字节数)。不能获取目录的长度"+f.length());
        System.out.println("获取最后一次的修改时间,毫秒值"+new Date(f.lastModified()));
        System.out.println("获取指定目录下的所有文件或者文件目录的字符串数组:"+f.list());
        System.out.println("获取指定目录下的所有文件或者文件目录的File对象数组:"+f.listFiles());
        // 从磁盘中删除指定文件路径下的文件或者文件目录
//        f.delete();
//        System.out.println("再次判断传入的抽象路径名(目录/普通文件)在磁盘中是否存在:"+file.exists());// false
    }
}
3、流的分类
- 按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)
- 按数据流的流向不同分为:输入流,输出流

补充:
- 按流的角色的不同分为:节点流,处理流
 节点流:直接从数据源或目的地读写数据
 处理流:不直接连接到数据源或目的地,而是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。
3.1、IO 流体系图

3.2、派生类
Java的IO流共涉及40多个类,实际上非常规则,都是从以上4个抽象基类派生的,并且子类名称都是以其父类名作为子类名后缀。
 
4、字节流
字节流分为字节输入流InputStream和字节输出流OutputStream,其中输入与输出是相对于内存而言的;输入即从文件中读出数据输入至内存;输出即从内存向文件中输出数据。
从jdk8文档中,InputStream 方法如下:

OutputStream方法如下:

从 Java 9 开始,InputStream 新增加了多个实用的方法:
readAllBytes():读取输入流中的所有字节,返回字节数组。
readNBytes(byte[] b, int off, int len):阻塞直到读取 len 个字节。
transferTo(OutputStream out):将所有字节从一个输入流传递到一个输出流。
4.1、实例
public class FileStreamTest {
    public static void main(String[] args) throws IOException {
        //写入
        FileOutputStream fileOutputStream = new FileOutputStream("H:\\test\\test.txt");
        String s = "test123";
        // 将字符串转换为byte数组
        byte[] outBytes = s.getBytes();
        fileOutputStream.write(outBytes);
        fileOutputStream.flush();
        fileOutputStream.close();
        System.out.println("=================================================================");
        //读取
        FileInputStream fileInputStream = new FileInputStream("H:\\test\\test.txt");
        //1、返回从该输入流中可以读取(或跳过)的字节数的估计值,而不会被下一次调用此输入流的方法阻塞。
        int available = fileInputStream.available();
        System.out.println("available:" + available);
        //2、跳过并丢弃来自此输入流的 2字节数据。
//        long skip = fileInputStream.skip(2);
//        System.out.println("skip:" + skip);
        //3、读取文件内容,为了减少IO,我们创建一个Byte数组作为接收缓冲区
        byte[] inBytes = new byte[available];
        int read;
        //4、从输入流读取一些字节数,并将它们存储到缓冲区 b 。
        while ((read = fileInputStream.read(inBytes)) != -1) {
            // 把byte数组转换成字符串
            System.out.print(new String(inBytes, 0, read));
        }
        if (fileInputStream != null) {
            fileInputStream.close();
        }
    }
}
5、字符流
已经有字节流了,可以读取任意文件,为什么还要有字符流呢?
- 对于字符文件,先作为字节传输,再转成字符,耗时耗力。
- 对于字符文件,转成字节之后,再转回来,如果是中文,很容易乱码。
5.1、Reader

5.2、Writer

5.3、实例
public class FileStreamTest {
    public static void main(String[] args) throws IOException {
        FileWriter fw = new FileWriter("H:\\test\\test.txt");
        String s = "少年";
        fw.write(s); // 将字符串写入文件
        // 关闭资源
        fw.close();
        FileReader fr = new FileReader("H:\\test\\test.txt");
        String str = new String();
        int b;
        // 循环读取
        while ((b = fr.read())!=-1) {
            str = str + (char)b;
        }
        System.out.println("str:"+str);
        // 关闭资源
        fr.close();
    }
}- flush :刷新缓冲区,流对象可以继续使用。
- close :先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。



















