Java I/O

IO的核心组成就是五个类(FileOutputStreamInputStreamReaderWriter) 一个接口(Serializable)

File文件操作类

在Java.io包之中,File类是唯一一个与文件本身操作(创建、删除、取得信息…)有关,与文件内容无关的的程序类
File类即可以描述真实文件,也可以是个文件夹

File类使用

  • File类的两种实例化方式:
public File(String pathname) 
public File(String parent, String child) 
  • 创建新文件
public boolean createNewFile() throws IOException 
  • 判断文件是否存在
public boolean exits()
  • 删除文件
public boolean delete()

范例:编写文件的基本操作(如果文件不存在则进行创建;存在则删除)

package www.bit.FileTest;

import java.io.File;
import java.io.IOException;

public class MyFile {
    public static void main(String[] args) {
        // 定义要操作的文件路径
        // 路径分隔符:File.separator
        File file = new File("C:"+File.separator+"Users"+File.separator
                +"DELL"+File.separator+"Desktop"+File.separator+"TestIO.java");
        if (file.exists()){
            file.delete();
        }else{
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

有关目录的操作

  • 取得父路径与父File对象
public String getParent()
public File getParentFile()
  • 创建目录(无论有多少级父目录,都会一次性创建)
public boolean mkdirs()

范例:Java文件目录操作

import java.io.File;
import java.io.IOException;

public class MyFile {
    public static void main(String[] args) throws IOException{
        File file = new File("C:"+File.separator+"Users"+File.separator
                +"DELL"+File.separator+"Desktop"+File.separator+"Test"+
                File.separator+"Java IO"+File.separator+"TestIO.java");
        if (!file.getParentFile().exists()){  // 创建父目录
            file.getParentFile().mkdirs();  // 有多少级父目录就创建多少级
        }
        if (file.exists()){
            // 文件存在,进行删除 
            file.delete();
        }else {
            file.createNewFile();
        }
    }
}

文件信息

  • 判断File对象是否是文件
public boolean isFile()
  • 判断File对象是否是路径
public boolean isDirectory()
  • 取得文件大小
public long length()
  • 取得最后修改日期
public long lastModified()

范例:取得文件信息

import java.io.File;
import java.io.IOException;
import java.util.Date;

public class MyFile {
    public static void main(String[] args) throws IOException{
        File file = new File("C:"+File.separator+"Users"+File.separator
                +"DELL"+File.separator+"Desktop"+File.separator+"sifanchao.jpg");
        if (file.exists() && file.isFile()){
            System.out.println("文件大小:" + file.length()/1024 + "Kb");
            System.out.println("最后一次修改日期: " + new Date(file.lastModified()));
        }
    }
}
  • 列出一个目录的全部组成:
public File[] listFiles()

范例:列出C盘目录中的全部组成

import java.io.File;

public class MyFile {
    public static void main(String[] args){
        new Thread(()-> {
            File file = new File("C:");
            // 列出桌面目录中的全部组成
            // +File.separator+"Users"+File.separator+"DELL"+File.separator+"Desktop"
            System.out.println("遍历文件开始...");
            long start = System.currentTimeMillis();
            listAllFiles(file);
            long end = System.currentTimeMillis();
            System.out.println("遍历文件结束。共耗时:" + (end-start) + "毫秒");
        }).start();
    }
    public static void listAllFiles(File file){
        if (file.exists() && file.isFile()){
            System.out.println(file);
        }else {
            File[] files = file.listFiles();
            if (files != null){
                for (File file1 : files){
                    listAllFiles(file1);
                }
            }
        }
    }
}

IO相关处理属于阻塞式耗时操作,一般放在子线程中进行

字节流与字符流

File类不支持文件内容处理,如果要处理文件内容,必须要通过流的操作模式来完成。流分为输入流和输出流。 在java.io包中,流分为两种:字节流与字符流

  • 字节流:InputStream、OutputStream
  • 字符流:Reader、Writer
    在这里插入图片描述
    在这里插入图片描述

字节流与字符流操作的本质区别只有一个:字节流是原生的操作,而字符流是经过处理后的操作

一般使用字节流(无论是网络传输还是磁盘数据保存均以字节为单位)。
而所有磁盘中的数据必须先读取到内存后才能进行操作,内存中会帮助我们把字节变为字符。所以,只有处理中文文本时才会用到字符流。

流操作流程

无论是字节流还是字符流,操作流程几乎一样,以文件操作为例:

  1. 取得File对象
  2. 取得File对象的输入、输出流
  3. 进行数据的读取或写入
  4. 关闭流(close)

对于IO操作属于资源处理,所有的资源处理操作(IO操作、数据库操作、网络)后必须要进行关闭

字节输出流(OutputStream)

如果要想通过程序进行内容输出,则可以使用java.io.OutputStream

public abstract class OutputStream implements Closeable, Flushable

OutputStream类实现了Closeable,Flushable两个接口,这两个接口中的方法:

  1. Closeable: public void close() throws IOException;
  2. Flushable: public void flush() throws IOException;

在OutputStream类中还定义有其他方法:

  • 将指定的字节数组全部输出
public void write(byte[] b)throws IOException
  • 将部分字节数组输出
public void write(byte[] b,int offset,int len)throws IOException
  • 输出单个字节
public abstract void write(int b)throws IOException

由于OutputStream是一个抽象类,所以要想为父类实例化,就必须要使用子类。由于方法名称都由父类声明好 了,所以我们在此处只需要关心子类的构造方法。如果要进行文件的操作,可以使用FileOutputStream类来处理, 这个类的构造方法如下:

  • 文件内容覆盖
public FileOutputStream(File file) throws FileNotFoundException
  • 文件内容追加
public FileOutputStream(File file, boolean append) throws FileNotFoundException

范例:实现文件的内容输出

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class MyFile {
    public static void main(String[] args) throws Exception{
        File file = new File("C:" + File.separator + "Users" + File.separator
                + "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
        if (!file.getParentFile().exists()){  // 必须保证父目录存在
            file.getParentFile().mkdirs();  // 创建多级父目录
        }
        // OutputStream是一个抽象类,所以需要通过子类进行实例化,
        // 此时只能操作File类
        OutputStream outputStream = new FileOutputStream(file);
        // 要求输出到文件的内容
        String msg = "你好,中国!";
        outputStream.write(msg.getBytes());
        outputStream.close();
    }
}

当使用FileOutputStream进行文件内容输出时时候,只要文件的父路径存在,所有的文件会自动帮助用户创建,不在需要调用createFile()方法手工创建

这个时候程序如果重复执行,并不会出现内容追加的情况而是一直在覆盖。如果需要文件内容追加,则需要调用 FileOutputStream提供的另外一种构造方法。

范例:文件内容追加

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class MyFile {
    public static void main(String[] args) throws Exception{
        File file = new File("C:" + File.separator + "Users" + File.separator
                + "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
        if (!file.getParentFile().exists()){  
            file.getParentFile().mkdirs(); 
        }
        // true表示允许内容的追加操作
        OutputStream outputStream = new FileOutputStream(file,true);
        String msg = "我爱你\r\n";
        outputStream.write(msg.getBytes());
        outputStream.close();
    }
}

AutoCloseable自动关闭支持

从JDk1.7开始追加了一个AutoCloseable接口,这个接口的主要目的是自动进行关闭处理,但是这种处理一般不好用,因为使用自动关闭接口有一个前提,需要结合try…catch…代码块

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class MyFile {
    public static void main(String[] args) throws Exception{
        File file = new File("C:" + File.separator + "Users" + File.separator
                + "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
        if (!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        try (OutputStream outputStream = new
                FileOutputStream(file,true)){
            String msg = "改革开放40周年\r\n";
            outputStream.write(msg.getBytes());
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

字节输入流:InputStream

利用了OutputStream实现了程序输出内容到文件的处理,下面使用InputStream类在程序中读取文件内容。 InputStream类的定义如下:

public abstract class InputStream implements Closeable
  • 读取数据到字节数组b中
public int read(byte b[]) throws IOException

返回值三种情况:

  1. 返回b长度:当读取的数据大小>字节数组大小,返回字节数组大小
  2. 返回大于0但是小于b长度:当读取的数据大小<字节数组大小,返回真正读取大小
  3. 返回-1:数据读取完毕
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class MyFile {
    public static void main(String[] args) throws Exception{
        File file = new File("C:" + File.separator + "Users" + File.separator
                + "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
        if (file.exists()){
            InputStream inputStream = new FileInputStream(file);
            // 每次可以读取的大数量
            byte[] data = new byte[1024];
            // 此时的数据读取到了数组之中
            int len = inputStream.read(data);
            System.out.println(new String(data,0,len));
            inputStream.close();
        }
    }
  • 读取单个字节
public int read() throws IOException

字符输出流Writer

字符适合于处理中文数据,Writer是字符输出流的处理类,这个类的定义如下:

public abstract class Writer implements Appendable, Closeable, Flushable

OutputStream相比多了一个Appendable接口。 在Writer类里面也提供write()方法,而且该方法接收的类提供了一个直接输出字符串的方法:

public void write(String str) throws IOException

范例:通过Writer实现输出

import java.io.*;

public class MyFile {
    public static void main(String[] args) throws Exception {
        // 取得File对象
        File file = new File("C:" + File.separator + "Users" + File.separator
                + "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
        if (!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        // 取得输出流
        Writer out = new FileWriter(file);
        // 写入数据
        String msg = "你好,世界!" ;
        out.write(msg);
        // 关闭
        out.close();
    }
}

Writer类的结构与方法的使用与OutputStream非常相似,只是Writer类对于中文的支持很好并且提供了直接写入 String的方法而已。

字节的输入流Reader

Reader依然也是一个抽象类。如果要进行文件读取,同样的,使用FileReader。

在上面讲到的Writer类中提供有方法直接向目标源写入字符串,Reader类中没有方法可以直接读取字符串,只能通过字符数组来读取

import java.io.*;

public class MyFile {
    public static void main(String[] args) throws Exception {
        // 取得File对象
        File file = new File("C:" + File.separator + "Users" + File.separator
                + "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
        if (!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        // 取得输入流
        Reader reader = new FileReader(file);
        // 读入数据
        char[] data = new char[1024];
        int len = reader.read(data);
        System.out.println(len);
        System.out.println(new String(data,0,len));
        reader.close();
    }
}

字符流适合处理中文,字节流适合处理一切数据类型(对中文支持不好)

字符流VS字节流

  1. 从实际开发来讲,字节流优先考虑,只有处理中文时才会考虑使用字符流
  2. 所有字符流操作,无论是写入还是输出,数据都先保存在缓存中

如果字符流不关闭,数据就有可能保存在缓存中并没有输出到目标源。这种情况下就必须强制刷新才能够得到完整数据。

import java.io.*;

public class MyFile {
    public static void main(String[] args) throws Exception {
        // 取得File对象
        File file = new File("C:" + File.separator + "Users" + File.separator
                + "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
        if (!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        // 取得输出流
        Writer out = new FileWriter(file);
        // 写入数据
        String msg = "你好,世界!" ;
        out.write(msg);
        out.flush();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章