Java文件操作及输入流输出流


Java操作文件及目录

IO,即Input/Output

  • 把内存中的数据存储到持久化设备上的动作称为输出,Output操作;
  • 把持久化设备的数据读取到内存中的动作称为输入,Input操作;
  • 一般把输入和输出的动作称为IO操作,IO也分网络IO、文件IO等。

Java文件类File

  • 主要是对计算机文件和目录的操作;
  • File类表示磁盘中存在的文件和目录;
  • File类的包名是java.io,实现了SerializableComparable两大接口以便于其对象可序列化和比较;
  • File.separator目录分隔符,在不同的系统windows/Linux/Mac有差异。

常用方法:

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

public class FileTest {
    public static void main(String[] args) {

        String dir = "/Users/laobai/IdeaProjects/test_01/";
        String name = "test_01.iml";

        File file = new File(dir);
        System.out.println(File.separator);
        System.out.println("基本路径 getPath()= " + file.getPath());
        System.out.println("文件名 getName()= " + file.getName());
        System.out.println("绝对路径 getAbsolutePath= " + file.getAbsolutePath());
        System.out.println("父路径 getParent()= " + file.getParent());
        System.out.println("是否是绝对路径 isAbsolute()= " + file.isAbsolute());
        System.out.println("是否是一个目录 isDirectory()= " + file.isDirectory());
        System.out.println("是否是一个文件 isFile()= " + file.isFile());
        System.out.println("文件或目录是否存在 exists()= " + file.exists());

        System.out.println("目录中的文件和目录的名称所组成字符串数据 list()");
        String[] arr = file.list();
        for (String temp:arr) {
            System.out.println(temp);
        }

        // 创建指定目录
        File mkdirFile = new File(dir+"test");
        mkdirFile.mkdir();

        // 创建多层级目录
        File mkdirsFlie = new File(dir + "test/aa/bb/cc");
        mkdirsFlie.mkdirs();

        // 创建一个文件
        File newFile = new File(dir + "test1.txt");
        try {
            newFile.createNewFile();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        // 删除文件
        newFile.delete();
    }
}

执行结果:

/
基本路径 getPath()= /Users/laobai/IdeaProjects/test_01
文件名 getName()= test_01
绝对路径 getAbsolutePath= /Users/laobai/IdeaProjects/test_01
父路径 getParent()= /Users/laobai/IdeaProjects
是否是绝对路径 isAbsolute()= true
是否是一个目录 isDirectory()= true
是否是一个文件 isFile()= false
文件或目录是否存在 exists()= true
目录中的文件和目录的名称所组成字符串数据 list()
.DS_Store
test
out
test_01.iml
.gitignore
.idea
src

Input、Output Stream流

IO在开发中的使用场景

  • IO:Input/Output 即输入输出
    • 输入流:外界设备 –> 程序(内存)
    • 输出流:程序(内存) –> 外界设备
  • 处理数据类型分类
    • 字符流:处理字符相关,如处理文本数据(如txt文本),Reader/Writer
    • 字节流:处理字节相关,如声音或者图片等二进制,InputStream/OutputStream
  • 字符流和字节流的区别:
    • 字节流以字节(8bit)为单位,字符流以字节流为单位,根据码表映射字符,一次可能读多个字节;
    • 字节流可以处理几乎所有文件,字符流只能处理字符流类型的数据;
  • 字符流和字节流功能不同,但具有共性内容,通过不断抽象形成4个抽象类,抽象类下面有很多子类是具体的实现
    • 字符流 Reader/Writer
    • 字节流 InputStream/OutputStream

InputStream

InputStream是输入字节流的父类,它是一个抽象类,一般使用它的子类。

  • int read():从输入流中读取单个字节,返回0到255范围内的int字节值,字节数据可直接转换为int类型,如果已经到达流末尾而没有可用的字节,则返回-1;
  • int read(byte[] buf):从输入流中读取一定数量的字节,并将其存储在缓冲区数组buf中,返回实际读取的字节数;
  • long skip(long n):从输入流中跳过并丢弃n个字节的数据;
  • int available():返回这个流中有多少个字节数,可以把buf数组长度定义为这个;
  • void close() throws IOException:关闭输入流并释放与该流关联的系统资源;

常见子类

  • FileInputStream

  • 抽象类InputStream用来具体实现类的创建对象,文件字节输入流,对文件数据以字节的形式进行读取操作;

    • 常用构造函数

      // 传入所在地址
      public FileInputStream(string name) throws FileNotFoundException
        
      // 传入文件对象
      public FileInputStream(File file) throws FileNotFoundException
    import java.io.*;
    
    public class Main {
        public static void main(String[] args) throws IOException {
    
            String dir = "/Users/laobai/IdeaProjects/test_01/";
            String name = "plscript.txt";
            File file = new File(dir, name);
            InputStream inputStream = new FileInputStream(file);
    
            testRead(inputStream);
            testSkip(inputStream);
            testReadByteArr(inputStream);
        }
    
        public static void testRead(InputStream inputStream)throws IOException{
            int read = inputStream.read();
            System.out.println(read);
            System.out.println((char) read);
            inputStream.close();
        }
    
        public static void testSkip(InputStream inputStream)throws IOException{
            long skipSize = inputStream.skip(2);
    
            int read = inputStream.read();
            System.out.println(read);
            System.out.println((char) read);
            inputStream.close();
        }
    
        public static void testReadByteArr(InputStream inputStream) throws IOException{
            byte[] buf = new byte[2048];
            int length;
            while ((length = inputStream.read(buf))!=-1){
                System.out.println(new String(buf, 0, length));
            }
            inputStream.close();
        }
    }

    执行结果:

    112
    p
    99
    c
    ript.cn漂亮的脚本
    plscript.cn漂亮的脚本
    plscript.cn漂亮的脚本
    plscript.cn漂亮的脚本
    plscript.cn漂亮的脚本
  • ByteArrayInputStream 字节数组输入流

  • ObjectInputStream 对象输入流

OutputStream

OutputStream是输出字节流的父类,它是一个抽象类

  • void write(int b) 将指定的字节写入输出流
  • void write(byte[] b)throws IOExceptionb.length个字节的byte数组写入当前输出流
  • void flush() throws IOException write是写到缓冲区中,可以认为是内存中,当缓冲区满时系统会自动将缓冲区的内容写入文件,但一般还有部分可能会留在内存这个缓冲区中,所以需要调用flush清空缓冲区数据。
  • void close() throws IOException 关闭输入流并释放与该流关联的系统资源。

常用子类

  • FileOutputStream

    • 抽象类OutputStream用来具体实现类的创建对象,文件字节输出流,对文件数据以字节的形式进行输出的操作;

    • 构造函数

      // 传入输出的文件地址
      public FileOutPutStream(String name)
        
      // 传入目标输出的文件对象
      public FileOutputStream(File file)
        
      // 传入目标输出的文件对象,是否可以追加内容
      public FileOutputStream(File file, boolean append)
    package test05;
    
    import java.io.*;
    
    public class test1 {
        public static void main(String[] args) throws IOException {
    
            String dir = "/Users/laobai/IdeaProjects/test_01/";
            String name = "plscript.txt";
            String target = "tar.txt";
            File file = new File(dir, name);
            InputStream inputStream = new FileInputStream(file);
            // OutputStream outputStream = new FileOutputStream(dir+File.separator+target);
            OutputStream outputStream = new FileOutputStream(dir+File.separator+target, true);
    
            // testOut(inputStream,outputStream);
            testOutBuf(inputStream,outputStream);
        }
    
        public static void testOut(InputStream inputStream,OutputStream outputStream) throws IOException {
            int value = 0;
            while (value != -1){
                value = inputStream.read();
                outputStream.write(value);
            }
            inputStream.close();
            outputStream.close();
        }
    
        public static void testOutBuf(InputStream inputStream,OutputStream outputStream) throws IOException {
            byte [] buf = new byte[1024];
            int length;
            while ((length = inputStream.read(buf))!=-1){
                outputStream.write(buf, 0, length);
            }
            inputStream.close();
            outputStream.close();
    
        }
    }
  • ByteArrayOutputStream

  • ObjectOutputStream

缓冲Buffer输入输出字节流

什么是缓冲Buffer?它是内存空间的一部分,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分空间就叫缓冲区,缓冲区是具有一定大小的。

Java IO包中提供了两个缓冲类(高级流):BufferInputStreamBufferOutputStream

  • BufferInputStream

    • BufferInputStream缓冲字节输入流,通过预先读入一整段原始输入流数据至缓冲区,而外界对BufferInputStream的读取操作实际上是在缓冲区上进行的。如果读取的数据超过了缓冲区的访问,那么BufferInputStream负责重新从原始输入流中载入下一截数据填充缓冲区,然后外界继续通过缓冲区进行数据读取。

    • 缓冲区的实现:读取缓冲区的内容,当读取超过缓冲区的内容后进行一次磁盘IO,载入一段数据填充缓冲区,下一次对其一般情况就直接从缓冲区读取,减少了磁盘IO。

    • 缓冲区默认大小为8k, int DEFAULT_BUFFER_SIZE=8192;

    • 常用构造函数

      // 对输入流进行包装,里面默认的缓冲区是8k
      public BufferedInputStream(InputStream in);
      
      // 对输入流进行包装,指定创建并指定缓冲区大小
      public BufferedInputStream(InputStream in,int size)
    • 常用方法

      // 从输入流中读取一个字节
      public int read();
      
      // 从字节输入流中给定偏移量处开始将各字节读取到指定的byte数组中
      public int read(byte[] buf,int off, int len);
      
      // 关闭释放资源
      void close();
  • BufferOutputStream

    BufferOutputStream缓冲字节输出流

    • 常用构造函数

      // 对输出流进行包装,里面默认的缓冲区是8k
      public BufferedOutputStream(OutputStream out);
      
      // 对输出流进行包装,指定创建并指定缓冲区大小
      public BufferedOutputStream(OutputStream out,int size)
    • 常用方法

      // 向输出流中输出一个字节
      public void write(int b);
      
      // 将指定byte数组中从偏移量off开始len个字节写入缓存的输出流
      public void write(byte [] buf, int off, int len);
      
      // 刷新此缓冲的输出流,强制使所有缓冲的输出自己被写出到底层输出流中
      public void flush
        
      // 关闭释放资源
      void close();
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Arrays;

public class TestCopy {
    public static void main(String[] args) {

        try {
            FileInputStream fileInputStream = new FileInputStream("/Users/laobai/IdeaProjects/test_01/plscript1.txt");
            BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);

            FileOutputStream fileOutputStream = new FileOutputStream("/Users/laobai/IdeaProjects/test_01/backup.txt");
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);

            int size;
            byte [] buf = new byte[1024];
            while ((size = bufferedInputStream.read(buf))!=-1) {
                bufferedOutputStream.write(buf, 0, size);
            }
            // 刷新缓冲区的输出流,才可以保证数据全部输出完成
            // bufferedOutputStream.flush();

            bufferedInputStream.close();
            bufferedOutputStream.close();
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

Reader、Writer字符流

字符输入流Reader

  • Reader是输入字符流的父类,它是一个抽象类
    • int read() 一个字符一个字符的读取,只能用来操作文本,不能写图片、音频、视频等;
    • int read(char cbuf[]) 从输入字符流中读取一定数量的字符,并将其存储在缓冲区数组cbuf中,返回实际读取的字符数,如果已经到达流末尾而没有可用字节,则返回-1;
    • void close() throws IOException 关闭输入流并释放与该流关联的系统资源。
  • 常用子类
    • FileReader 用来读取字符文件的实现类

字符输出流Writer

  • Writer是输出字符流的父类,它是一个抽象类
    • public void write(int c) throws IOException 直接将int型数据作为参数的话,是不会写入数字的,而是先将数字按照ASCII码表转换为相应字符,然后写入;
    • public void write(String str) throws IOException 要想实现数字和中文的写入,必须要用String为参数的write;
    • public abstract void write(char cbuf[], int off, int len) throws IOException 将cbuf字符数组的一部分写入到流中,但能不能写len个字符取决于cbuf中是否有那么多;
    • void flush() throws IOException write是写到缓冲区中,可以任务是内存中,当缓冲区满时系统会自动将缓冲区的内容写入文件,但一般还有一部分有可能会留在内存这个缓冲区中,所以需要调用flush清空缓冲区数据;
    • void close() throws IOException 关闭输入流并释放与该流关联的系统资源。
  • 常用子类
    • FileWriter 用来写出字符文件的实现类

缓冲Buffer输入输出字符流

为了提高单个字符读写的效率,进行字符批量的读写;为了提高字符流读写效率,引入缓冲机制;

  • BufferedReader

    • BufferedReader在读取文本文件时,会先尽量从文件中读入字符数据并放满缓冲区,而之后若使用read()方法,会先从缓冲区中进行读取,如果缓冲区数据不足,才会再从文件中读取

    • 构造函数

      BufferedReader(Reader in)
      BufferedReader(Reader in ,int sz)  创建一个使用指定大小输入缓冲区的缓冲字符输入流
    • 常用API

      • boolean ready() 判断是否已经准备好被读取
      • int read() 读取单个字符
      • int read(char[] cbuf, int off, int len) 读取一部分字符到数组里面,从数组下标off处放置length长度的字符
      • String readLine() 读取一整行文本,返回一整行字符串,如果读到行尾了就返回null,返回的一行不包括换行符
      • void close() 关闭流释放资源
  • BufferedWriter

    • 写入的数据并不会先输出到目的地,而是先存储至缓冲区中。如果缓冲区中的数据满了,才会对目的进行输出

    • 构造函数

      BufferedWriter(Writer out)
      BufferedWriter(Writer out, int sz)
    • 常用API

      • void write(int c) 希尔一个字符
      • void write(char[] cbuf, int off, int len) 写入字符数组的一部分,通过off和len控制
      • void write(String s, int off, int len) 写入字符数组的一部分,通过off和len控制
      • void newLine() 写入一个换行符号
      • void flush() 清空缓冲区数据
      • void close() 关闭流并释放资源

字符流和字节流的转换

计算机存储的单位是字节,从持久设备读取到程序中是解码,从程序写到持久设备中是编码。

无论是编码还是解码,不同字符集编码名称字符需要不同的个数,因此字节流读取容易出错,比如出现乱码,因此需要一个流,把字节流读取的字节进行缓冲后,再通过字符集解码成字符返回。

InputStreamReader

将字节流转换为字符流,字节流通向字符流的桥梁,如果不指定字符集编码,则解码过程中将使用平台默认的字符编码,如:UTF-8。文本文件存储是A编码,如果以B编码进行读取可能会出现乱码。

  • 构造函数

    // 使用系统默认编码集
    public InputStreamReader(InputStream in)
      
    // 指定编码集创建对象
    public InputStreamReader(InputStream in ,String charsetName)
  • 常用API

    • int read()
    • int read(char [] cbuf, int off, int len)
    • int read(char [] cbuf)
    • void close()

OutputStreamWriter

将字符流转换位字节流,字符流通向字节流的桥梁。如果不指定字符集编码,则解码过程中将使用平台默认的字符编码,如:GBK。

  • 构造函数

    // 使用系统默认编码集
    public OutputStreamWriter(OutputStream out)
      
    // 指定编码集创建对象
    public OutputStreamWriter(OutputStream out,String charsetName)
  • 常用API

    • void write(int c)
    • void write(char [] cbuf, int off, int len)
    • void write(String s, int off, int len)
    • void newLine()
    • void close()
    • void flush()

try-with-resource

需要关闭的资源只要实现了java.lang.AutoCloseable,就可以自动被关闭。

import java.io.*;

public class TryTest {
    public static void main(String[] args) {

        try (
            FileInputStream fileInputStream = new FileInputStream("/Users/laobai/IdeaProjects/test_01/plscript.txt");
            BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);

            FileOutputStream outputStream = new FileOutputStream("/Users/laobai/IdeaProjects/test_01/backup.txt");
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);

        ){
            int size;
            byte [] buf = new byte[1024];
            while ((size = bufferedInputStream.read(buf))!=-1) {
                bufferedOutputStream.write(buf,0,size);
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

文章作者: 老百
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 老百 !
  目录