前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java IO 操作基础1---普通文件的相关操作

Java IO 操作基础1---普通文件的相关操作

作者头像
指点
发布2019-01-18 15:11:38
5740
发布2019-01-18 15:11:38
举报
文章被收录于专栏:指点的专栏指点的专栏

Java 中 IO 操作是 Java 的一个重要组成部分,这里总结一下 Java 中的 IO 的基础操作。

首先, Java 中的 File 类是 IO 操作的基础,因为所有文件或者文件夹对象都可以用 File 对象来具体化表示,并且通过 File 类提供的方法来对其进行相关操作,扫一眼 File 类的常用 API 吧:

代码语言:javascript
复制
String getName() 获取该File对象指向的文件对象的名称(这里是指除去文件路径的单独的文件或者文件夹名称)

boolean canRead() 判断该File对象指向的文件是否是可读的

boolean canWrite() 判断该File对象指向的文件是否是可被写入的

boolean exists() 判断该File对象指向的文件是否存在

long length() 获取该File对象指向的文件的长度(以字节为单位,如果是文件夹,返回不定值)

String getAbsolutePath() 获取该File对象指向的文件的绝对路径

String getParent() 获取该该File对象指向的文件的父文件夹的绝对路径

boolean isDirectory() 判断该File对象指向的文件是否是一个目录

boolean isFile() 判断该该File对象指向的文件是否是一个普通文件(非文件夹)

boolean createNewFile() 创建一个新的文件,确保该File对象指向的文件的绝对路径中所有的父文件夹都存在,否则会报异常

boolean delete() 删除该File对象指向的文件,如果是文件夹,确保这个文件夹是空的

boolean mkdirs() 创建该File对象指向的文件的绝对路径中的所有不存在的文件夹,它本身作为一个文件夹被创建

boolean mkdir() 把该File对象指向的文件作为一个文件夹创建(只创建一个文件夹)

String[] list() 返回该File对象指向的文件夹的所有子文件名称数组

File[] listFiles() 返回返回该File对象指向的文件夹的所有子文件的 File 对象数组

好了,上面就是 File 对象的一些常用方法 ,通过这些方法我们可以对文件进行一些简单的操作,如果想要进行一些更复杂的操作,我们还需要借助一些文件输入流和输出流的类:

FileInputStream 和 FileOutputStream 类,这两个用来操作磁盘上的文件/文件夹,对于一些简单文件操作,我们都可以通过这两个类提供的方法完成。下面是 FileInputStream 类和 FileOutputStream 类的方法。

FileInputStream 类的方法:

这里写图片描述
这里写图片描述

其中比较常用的方法是read、close 方法, read(byte[] b) 方法是将当前文件指针中读取指定大小内容到 b 数组中,这个大小由 b 数组大小决定,读取完成后,文件指针向后移动,返回值为读取的文件内容大小(字节为单位)如果读到了文件末尾,那么返回 -1 ,对于其另外一个重载的方法:read(byte[] b, int off, int len),off 为数组的偏移量,len 是读取指定大小的内容(字节为单位),一般较少用。 close() 方法为关闭这个文件输入流。

FileOutputStream 类的方法:

这里写图片描述
这里写图片描述

和 FileInputStream 中的方法类似,这个类主要进行文件内容的写入操作,flush() 方法为强制把缓冲区的内容写入文件中,常用于带有缓冲区的输出流中。OK,下面来实践操作一下:

假设我们现在要从一个文件夹中移动一个文件到另外一个文件夹中。一般步骤是:在目标文件夹中创建一个和原文件名相同的文件 –> 使用输入输出流类进行文件读写 –> 删除原文件。

新建一个 Java 工程: Main.java:

代码语言:javascript
复制
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Main {

    /**
     * 如果给出的文件绝对路径中文件不存在,那么创建一个新的文件
     * @param filePath 文件的绝对路径
     */
    public static void createFile(String filePath) {
        File file = new File(filePath);
        if(!file.exists()) {
            System.out.println("文件不存在,创建文件");
            try {
                file.createNewFile();
            } catch (Exception e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
        }
    }

    /**
     * 移动一个文件到另一个文件夹中
     * @param fileAbslutePath 要移动的文件的绝对路径
     * @param targetDirectory 移动的文件的目标文件夹
     * @return 移动成功返回 true,否则返回 false 
     */
    public static boolean moveFile(String fileAbslutePath, String targetDirectory) {
        File file = new File(fileAbslutePath);
        File targetDir = new File(targetDirectory);
        // 判断是否符合移动条件,不符合直接返回 false 
        if(!file.exists() || !targetDir.exists() || !targetDir.isDirectory()) {
            System.out.println("文件不存在!");
            return false;
        }
        File targetFile = new File(targetDirectory, file.getName());
        if(targetFile.exists()) {
            targetFile.delete();
        }
        try {
            // 目标目录下新建一个同名文件
            targetFile.createNewFile();
            FileInputStream fis = new FileInputStream(file);
            FileOutputStream fos = new FileOutputStream(targetFile);
            byte[] b = new byte[1024];
            // 循环从文件中读取数据并且写入目标文件中,每次读写都有两次磁盘读写操作
            for(int len; (len = fis.read(b)) != -1; ) {
                fos.write(b, 0, len);
            }
            // 读写完成关闭输入输出流
            fis.close();
            fos.close();
            // 删除原来的文件
            file.delete();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }


    public static void main(String[] args) {
        File file = new File("文本.txt");
        File targetDir = new File("bin");
        createFile(file.getAbsolutePath());
//      if(moveFile(file.getAbsolutePath(), targetDir.getAbsolutePath())) {
//          System.out.println("文件移动成功");
//      }
    }

}

这里我在程序中新建了一个名字为 “文本”的 txt 类型文件,我需要把这个文本文件移动到 bin 文件夹下,请注意,这个 bin 文件夹在笔者的电脑中是存在的:

这里写图片描述
这里写图片描述

运行程序:

这里写图片描述
这里写图片描述

先是创建了一个文本文件:

这里写图片描述
这里写图片描述

下面我们把 main 方法中移动文件代码的注释去掉,再运行一次:

这里写图片描述
这里写图片描述

显示移动成功的提示,我们去 bin 文件夹中看一下:

这里写图片描述
这里写图片描述

成功完成了文件的移动!

因为这里我们移动的只是一个小的文本文件,用 FileInputStream 和 FileOutputStream 这两个类可以很完美的解决问题,但是如果当文件的大小逐渐变大的时候,我们就不得不考虑移动时间问题了。因为 FileInputStream 和 FileOutputStream 在读写的时候都是直接对磁盘进行的,而读写磁盘的速度比较慢,如果频繁的对磁盘进行读取的话就会影响到我们程序的执行时间。对于这个问题,Java 给我们提供带有缓冲区的文件输入输出流:BufferedInputStream 和 BufferedOutputStream 类,BufferedInputStream 类提供了缓冲区去储存读入的数据,BufferedOutputStream 类提供了从缓冲区中写入数据到文件中的方法,因为缓冲区是在内存中的,内存的读写速度比磁盘快得多,所以这样就间接地减少了文件操作中读写磁盘的次数,进而提高了程序的运行速度。下面通过例子来看下这两个类的用法:

这里写图片描述
这里写图片描述

这里我提供了一个 55 Mb 左右的视频在工程文件夹中,同样的我们把这个视频移动到 bin 文件夹中,修改 Main.java 的内容:

代码语言:javascript
复制
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Main {

    // 带有输出移动文件所消耗时间的方法
    public static boolean moveFileCalculateTime(String fileAbslutePath, String targetDirectory) {
        File file = new File(fileAbslutePath);
        File targetDir = new File(targetDirectory);
        // 判断是否符合移动条件,不符合直接返回 false 
        if(!file.exists() || !targetDir.exists() || !targetDir.isDirectory()) {
            System.out.println("文件不存在!");
            return false;
        }
        File targetFile = new File(targetDirectory, file.getName());
        if(targetFile.exists()) {
            targetFile.delete();
        }
        try {
            // 目标目录下新建一个同名文件
            targetFile.createNewFile();
            FileInputStream fis = new FileInputStream(file);
            FileOutputStream fos = new FileOutputStream(targetFile);
            byte[] b = new byte[1024];
            long time1 = System.currentTimeMillis();
            // 循环从文件中读取数据并且写入目标文件中
            for(int len; (len = fis.read(b)) != -1; ) {
                fos.write(b, 0, len);
            }
            System.out.println("移动文件耗费时间为:" + (System.currentTimeMillis() - time1));
            // 读写完成关闭输入输出流
            fis.close();
            fos.close();
            // 删除原来的文件
            file.delete();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

    // 采用BufferedInputStream 和 BufferedOutputStream 类来移动文件
    public static boolean moveFileByBufferedStream(String fileAbslutePath, String targetDirectory) {
        File file = new File(fileAbslutePath);
        File targetDir = new File(targetDirectory);
        // 判断是否符合移动条件,不符合直接返回 false 
        if(!file.exists() || !targetDir.exists() || !targetDir.isDirectory()) {
            System.out.println("文件不存在!");
            return false;
        }
        File targetFile = new File(targetDirectory, file.getName());
        if(targetFile.exists()) {
            targetFile.delete();
        }
        try {
            // 目标目录下新建一个同名文件
            targetFile.createNewFile();
            // 创建一个带有 2048 字节的输入缓冲流
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file), 2048);
            // 创建一个带有 2048 字节的输出缓冲流
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(targetFile), 2048);
            byte[] b = new byte[1024];
            long time1 = System.currentTimeMillis();
            // 循环从文件中读取数据并且写入目标文件中
            for(int len; (len = bis.read(b)) != -1; ) {
                bos.write(b, 0, len);
            }
            System.out.println("移动文件耗费时间为:" + (System.currentTimeMillis() - time1));
            // 读写完成关闭输入输出流
            bis.close();
            // 将缓冲区剩余的数据强制写到文件中
            bos.flush();
            bos.close();
            // 删除原来的文件
            file.delete();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }


    public static void main(String[] args) {
        File file = new File("修剪草坪的小黄人.mp4");
        File targetDir = new File("bin");
        if(moveFileCalculateTime(file.getAbsolutePath(), targetDir.getAbsolutePath())) {
            System.out.println("文件移动成功");
        }
    }

}

增加了两个方法,用于计算移动所用的时间,先是采用原来的FileInputStream 和 FileOutputStream 来进行文件的移动,我们看一下结果:

这里写图片描述
这里写图片描述

用时 3696 ms,OK,下面修改一下 main 方法中的代码:

代码语言:javascript
复制
public static void main(String[] args) {
        File file = new File("修剪草坪的小黄人.mp4");
        File targetDir = new File("bin");
        createFile(file.getAbsolutePath());
        if(moveFileByBufferedStream(file.getAbsolutePath(), targetDir.getAbsolutePath())) {
            System.out.println("文件移动成功");
        }
    }

把移动文件的方法换了一下,我们再看一下程序结果:

这里写图片描述
这里写图片描述

用时 930 ms,相当于之前的 1/4 ,可能在不同配置的机器上结果会有差异,但移动时间确实减少了。所以对于一些大型文件的移动等操作可以采用带有缓冲的类进行。

最后再试着做一个小实验,我们把一个文本文件中的内容输出到控制台上,思路基本不变:读取文件内容 –> 将读取到的数据转换成 String 类型字符串输出到控制台,这里我新建了一个文本文件:

这里写图片描述
这里写图片描述

我们要把文本中的这几个输出到控制台中,我们一般会采用 FileInputStream 类。 下面是代码:

代码语言:javascript
复制
    /**
     * 读取 filePath 所指向的文本文件的内容到控制台中
     * @param filePath 文本文件所在绝对路径
     * @return 读取成功返回 true, 否则返回 false
     */
    public static boolean readText(String filePath) {
        File file = new File(filePath);
        if(!file.exists()) {
            return false;
        }
        try {
            FileInputStream fis = new FileInputStream(file);
            byte[] b = new byte[3];
            for(int len; (len = fis.read(b)) != -1; ) {
                System.out.print(new String(b, 0, len));
            }
        } catch (Exception e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
        return true;
    }

    public static void main(String[] args) {
        File file = new File("文本.txt");
        readText(file.getAbsolutePath());
    }

这里为了方便,只复制了关键代码部分。下面看看结果:

这里写图片描述
这里写图片描述

很遗憾的是,输出的内容并不是我们想要的。这是因为 FileInputStream 和 FileOutputStream 都是采用的字节流来对文件进行读写,而汉字在文件中占用两个字节,并且我们代码中的 byte 数组的长度为 3,为奇数,所以如果还是采用字节流会出现乱现象,要解决的话我们可以将这个 byte 数组的长度改成偶数或者让它的长度大于我们要读取的文本的长度。 但是这样两种方法都不太可行,其一是因为我们现在读取的文件时有种对性的,即为我们自定义的文本,当我们读取未知的文本的时候采用字节流还是可能会出现乱码的现象,其二是如果文本很大的话,定义的 byte 数组占用的内存就会很大,很明显不现实。 对于字符,Java 提供了两个类来对它们进行读写:FileReader 和 FileWrite 类。这两个类采用字符流进行读写,所以无需担心乱码现象。下面用这两个类来完成我们刚刚的功能:

代码语言:javascript
复制
    /**
     * 读取 filePath 所指向的文本文件的内容到控制台中
     * @param filePath 文本文件所在绝对路径
     * @return 读取成功返回 true, 否则返回 false
     */
    public static boolean readText(String filePath) {
        File file = new File(filePath);
        if(!file.exists()) {
            return false;
        }
        try {
            FileReader fr = new FileReader(file);
            char[] b = new char[3];
            for(int len; (len = fr.read(b)) != -1; ) {
                System.out.print(new String(b, 0, len));
            }
        } catch (Exception e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
        return true;
    }

    public static void main(String[] args) {
        File file = new File("文本.txt");
        readText(file.getAbsolutePath());
    }

看看结果:

这里写图片描述
这里写图片描述

OK, 完成了,成功的读取了内容并且没有出现乱码现象。对于大的文本文件的读写,Java 同样提供了带有缓冲区的类来提高文本的读写速率:BufferedReader 和 BufferedWriter 类。下面是它们的部分方法:

BufferedReader:

这里写图片描述
这里写图片描述

readLine() 方法用于读取一行文本,遇到换行符结束,返回读取到的文本。

BufferedWriter:

这里写图片描述
这里写图片描述

使用 write(String str) 方法可以直接将 String 类型的字符串写入文件中,newLine() 可以向文本中写入一个换行符,一般配合 BufferReader 类的 readLine() 一起使用。

OK,对于这两个类,小伙伴们可以自行尝试一下它们的使用方法。

最后给出Demo,好像还附带了那个小黄人视频。。。

如果博客中有什么不正确的地方,还请多多指点,如果觉得我写的不错,请点个赞支持我吧。

谢谢观看。。。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年06月25日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档