java IO流(1)

一. 文件类

java中提供了一个File类来表示一个文件或目录(文件夹),并提供了一些方法可以操作该文件

1. 文件类的常用方法

|--------------------------|----------------------------------------------|
| File(String pathname) | 构造方法,里面传一个路径名,用来表示一个文件 |
| boolean canRead() | 判断文件是否是可读文件 |
| boolean canWrite() | 判断文件是否是可写文件 |
| boolean exists() | 判断文件或目录是否存在 |
| String getAbsolutePath() | 获取文件的绝对路径 |
| String getName() | 获取文件名 |
| String getParent() | 获取文件的上级目录 |
| boolean isDirectory() | 判断是不是文件夹 |
| boolean isFile() | 判断是不是文件 |
| Long lastModified() | 返回文件最后一次的修改时间,由于返回值是Long类型,配合Date的构造方法,可观察时间 |
| Long length() | 返回文件有多少个字节 |
| boolean isHidden() | 判断文件是不是隐藏文件 |
| boolean delete() | 删除文件或文件夹,注意删除文件夹时必须保证文件夹是空的,否则删除失败 |
| boolean mkdir() | 创建单级文件夹 |
| boolean mkdirs() | 创建多级文件夹 |

2. 删除整个文件夹

java 复制代码
public class FileDemo2 {
    public static void main(String[] args) throws IOException {

        //递归删除文件夹中的文件和文件夹
        File f = new File("E:/download");
     
        DeleteFile(f);
    }


public static void DeleteFile(File files) {

        File[] file = files.listFiles();

        for (File f : file) {
            if (f.isDirectory()) {
                DeleteFile(f);
            } else {
                f.delete();//删除文件
            }
        }

        files.delete();
}

当文件夹不为空时调用delete方法删除是不成功的,要想删除文件夹,必须保证文件夹为空,即要先删除我文件夹中的文件和文件夹,这就要使用递归来删除

二. 输入输出概念

输入输出是一个相对概念,要有一定的参照物才能说清楚到底是输入还是输出,比如:我们将文件中的内容读到java程序中,对于java程序来讲是输入,但对于硬盘上的文件来讲则是输出,所以我们一般规定,把硬盘上的文件读到java程序中是输入,从java程序中写回硬盘上是输出

三. 流的分类

1.输入流和输出流

按照数据传输的方向,流可以分为输入流输出流

输入流:往程序中读叫输入流

输出流:从程序中往外写叫输出流

2. 字节流和字符流

从读取文件的单位不同分为字节流字符流

字节流:是以一个个字节为单位读取文件,可以读取任意的文件,这是因为,在计算机中任何类型的数据都是以字节存储的

字符流:是以一个个字符为单位读取文件,只能读文本文件

**注意:**在java中有InputStream和OutputStream,Reader和Writer四个抽象类,只要是以InputStream和OutPutStream结尾的都是字节流,以Reader和Writer结尾的都是字符流

3. 节点流和处理流

根据封装类型不同流分为节点流处理流

节点流:就是直接对数据进行读写操作的流,FileInputStream,FileOutputStream,FileReader等

处理流(包装流):对节点流进行封装,可以提高节点流对数据操作的效率,BufferReader等带Buffer的流

四. 读写文件

1. 用文件输入字节流和文件输出字节流读写文件

1.1 一个一个字节读文件

java 复制代码
public class StreamDemo1 {
    public static void main(String[] args) throws IOException {
        //输入,从硬盘上把文件读入到程序
        /*File file = new File("D:/demo.txt");
        FileInputStream inputStream1 = new FileInputStream(file);*/


        //文件输入字节流
        FileInputStream inputStream = new FileInputStream("E:/demo.txt");//输入管道
        //文件输出字节流
        FileOutputStream outputStream = new FileOutputStream("D:/demo.txt");//输出管道
        int b = 0;
        while((b = inputStream.read())!=-1)
        {
            outputStream.write(b);
        }
        inputStream.close();//关闭通道
        outputStream.close();
    }
}

由于上述方法每次是一个一个字节去读文件,效率非常低,所以java还提供每次读一个byte数组个字节大小,数组的长度可以自己定,但不建议太大内存装不下,也不建议太小效率低

2.1 一次读一个byte数组(高效文件读写)

java 复制代码
public class StrteamDemo2 {
    public static void main(String[] args) throws IOException {
        FileInputStream inputStream = new FileInputStream("E:/demo.txt");
        FileOutputStream outputStream = new FileOutputStream("D:/demo.txt");
        byte[] bytes = new byte[10];
        int size = 0;
        while((size = inputStream.read(bytes))!=-1)
        {
            outputStream.write(bytes,0,size);
        }
        inputStream.close();
        outputStream.close();
    }
}

注意:当写文件时调用的是write(byte b[], int off, int len),而不是write(byte b[]),调用第二个有可能会导致最后一次数组中还留有上次的元素,导致读完后的文件和原文件不同

2. 用包装流封装节点流读取文件

java 复制代码
public class StreamDemo3 {
    public static void main(String[] args) throws IOException {
        //FileInputStream 直接封装数据,称为节点流(最基础去读数据的流)
        FileInputStream inputStream = new FileInputStream("E:/demo.txt");

        //BufferedInputSteam封装的是一个节点流对象,可以提供缓冲功能,称为处理流/包装流
        //缓冲字节输入流 默认缓冲区大小是8192个字节,可以自定义缓冲区大小
        BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);

        FileOutputStream outputStream = new FileOutputStream("D:/demo.txt");
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);

        byte[] bytes = new byte[10];
        int size = 0;
        while((size = bufferedInputStream.read(bytes))!=-1){
            bufferedOutputStream.write(bytes,0,size);
        }

        //包装流一定要关闭,否则有可能导致数据停留在底层缓冲区
        //没有真正刷新缓冲区写入到文件中
        bufferedInputStream.close();
        bufferedOutputStream.close();
    }
}

2.1 BufferedInputStream和BufferedOutputStream读写文件底层

在包装流的底层也提供了一个缓冲数组默认长度是8192个字节,当我们去读文件时,如果一次读的字节个数比底层的缓冲数组少,那么他不会直接将读到的内容写入到文件中,而是先放到缓冲数组中,等到底层缓冲数组满时,才会写入到文件中,这样可以大大提高效率,这也是包装流的作用,但如果我们自己定义的byte数组比底层缓冲数组大,那么不会用到底层的缓冲数组,而是直接将读到的内容写入到文件中,下面是源码

注意:

  1. 包装流使用完毕后一定要关闭,否则有可能导致数据停留在底层缓冲区,没有真正刷新缓冲区写入到文件中,因为真正写入文件中是flushBuffer()方法中的write,而close()方法中调用了这个方法,如果仅仅只是上述源码,当我们最后一次读取数据时,如果缓冲数组没装满是不会调用flushBuffer(0方法,所以为了确保一定调用了flushBuffer(0方法,使用完必须调用close()方法来关闭包装流

2.底层缓冲数组可以自定义大小,在构造方法的第二个参数中

五. 对文件进行分割与合并

java 复制代码
/*

  写一个方法,将feige.exe文件分割为每份1MB大小的若干份(最后一份可以不满1MB),
  存储在一个temp的文件夹中(每份文件名自己定义,例如1.temp 2.temp), 
  
  然后再写一个方法,将temp文件夹中的若干份合并为一个文件fg.exe
*/
public class HomeWork4 {
    public static void main(String[] args) throws IOException {
        File file1 = new File("E:/feige.exe");
        File file2 = new File("E:/temp");
        SplitFile(file1);
        MergeFile(file2);
    }

    public static void SplitFile(File file) throws IOException {
        File file1 = new File("E:/temp");
        if(!file1.exists())
        {
            file1.mkdir();
        }
        FileInputStream inputStream = new FileInputStream(file);
        int length = (int)Math.ceil(file.length()/(1024*1024*1.0));
        int size = 0;
        byte[] bytes = new byte[1024];
        for (int i = 0; i < length; i++) {
            FileOutputStream outputStream = new FileOutputStream("E:/temp/"+(i+1)+".temp");
            for (int j = 0; j <1024; j++) {
                if((size = inputStream.read(bytes))!=-1)
                {
                    outputStream.write(bytes,0,size);
                }
            }
            outputStream.close();
        }
        inputStream.close();
    }

    public static void MergeFile(File file) throws IOException {
        File file1 = new File("E:/Merge");
        if(!file1.exists()){
            file1.mkdir();
        }
        File[] files = file.listFiles();
        int size = 0;
        byte[] bytes = new byte[1024];
        FileOutputStream outputStream = new FileOutputStream("E:/Merge/fg.exe");
        for(File file2 : files){
            FileInputStream inputStream = new FileInputStream(file2);
            while((size = inputStream.read(bytes))!=-1)
            {
                outputStream.write(bytes,0,size);
            }
            inputStream.close();
        }
        outputStream.close();
    }
}

六. 数据输入输出字节流

数据输入输出字节流即:DataInputStream和DataOutputStream,他们除了是字节流,同时也是包装流(处理流),用于对节点流进行便捷处理的流

|------------------|--------------------|---------------------------------|
| DataInputStream | readUTF() | 直接将读到的数据转为字符串形式,不用自己将字节数组转换成字符串 |
| DataOutputStream | writeUFT(String s) | 直接将数据以字符串形式写出,不用自己将字节数组转换成字符串 |

相关推荐
zaim12 小时前
计算机的错误计算(一百一十四)
java·c++·python·rust·go·c·多项式
学习使我变快乐2 小时前
C++:const成员
开发语言·c++
500了3 小时前
Kotlin基本知识
android·开发语言·kotlin
hong_zc3 小时前
算法【Java】—— 二叉树的深搜
java·算法
进击的女IT4 小时前
SpringBoot上传图片实现本地存储以及实现直接上传阿里云OSS
java·spring boot·后端
Miqiuha4 小时前
lock_guard和unique_lock学习总结
java·数据库·学习
一 乐5 小时前
学籍管理平台|在线学籍管理平台系统|基于Springboot+VUE的在线学籍管理平台系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习
不知所云,5 小时前
qt cmake自定义资源目录,手动加载资源(图片, qss文件)
开发语言·qt
数云界5 小时前
如何在 DAX 中计算多个周期的移动平均线
java·服务器·前端
安冬的码畜日常5 小时前
【玩转 JS 函数式编程_006】2.2 小试牛刀:用函数式编程(FP)实现事件只触发一次
开发语言·前端·javascript·函数式编程·tdd·fp·jasmine