Java之I/O操作

430 阅读9分钟

原文


Java流

数据流是 Java 进行 I/O 操作的对象,它按照不同的标准可以分为不同的类别。

  • 按照流的方向主要分为输入流和输出流两大类。
  • 数据流按照数据单位的不同分为字节流和字符流。
  • 按照功能可以划分为节点流和处理流。
  • 所有输入流类都是 InputStream 抽象类(字节输入流)和 Reader 抽象类(字符输入流)的子类
  • 在 Java 中所有输出流类都是 OutputStream 抽象类(字节输出流)和 Writer 抽象类(字符输出流)的子类

输入流InputSteam常用方法

  • int read(byte[] b,int off,int len) 从输入流读入一个 8 字节的数据,将它转换成一个 0~ 255 的整数,返回一个整数,如果遇到输入流的结尾返回 -1
  1. b可选, 保存到参数 b 指定的字节数组中
  2. off 可选,开始保存数据位置的起始下标
  3. len 可选,读取字节的位数
  • void close() 关闭数据流,当完成对数据流的操作之后需要关闭数据流
  • int available() 返回可以从数据源读取的数据流的位数。
  • skip(long n) 从输入流跳过参数 n 指定的字节数目
  • boolean markSupported()判断输入流是否可以重复读取,如果可以就返回 true
  • void mark(int readLimit)如果输入流可以被重复读取,从流的当前位置开始设置标记,readLimit 指定可以设置标记的字节数
  • void reset()使输入流重新定位到刚才被标记的位置,这样可以重新读取标记过的数据

一般我们会这样操作,首先使用 markSupported() 判断,如果可以重复读取,则使用 mark(int readLimit) 方法进行标记,标记完成之后可以使用 read() 方法读取标记范围内的字节数,最后使用 reset() 方法使输入流重新定位到标记的位置,继而完成重复读取操作

Java 中的字符是 Unicode 编码,即双字节的,而 InputerStream 是用来处理单字节的,在处理字符文本时不是很方便。这时可以使用 Java 的文本输入流 Reader 类,该类是字符输入流的抽象类,即所有字符输入流的实现都是它的子类,ReaderInputSteam用法类似

输出流 OutputStream类常用方法

  • int write (byte[] b,int off,int len) 将指定字节数组从 off 位置开始的 len 字节的内容写入输出流
  • close()关闭数据流,当完成对数据流的操作之后需要关闭数据流
  • flush()刷新输出流,强行将缓冲区的内容写入输出流

在读取或写入IO流的过程中,可能会发生错误,例如,文件不存在导致无法读取,没有写权限导致写入失败,等等,这些底层错误由Java虚拟机自动封装成IOException异常并抛出。因此,所有与IO操作相关的代码都必须正确处理IOException。

字节输入流常用类

字节输入流/输出

输入:

  • ByteArrayInputStream 类:将字节数组转换为字节输入流,从中读取字节。
  • FileInputStream 类:从文件中读取数据。
  • PipedInputStream 类:连接到一个 PipedOutputStream(管道输出流)。
  • SequenceInputStream类:将多个字节输入流串联成一个字节输入流。
  • ObjectInputStream 类:将对象反序列化。

输出:

  • ByteArrayOutputStream 类:向内存缓冲区的字节数组中写数据。
  • FileOutputStream 类:向文件中写数据。
  • PipedOutputStream 类:连接到一个 PipedlntputStream(管道输入流)。
  • ObjectOutputStream 类:将对象序列化。

字节数组输入流/输出

输入:

  • ByteArrayInputStream(byte[] buf, [int offse,int length]):创建一个字节数组输入流,其中,参数 buf 指定字节数组类型的数据源,offset 指定在数组中开始读取数据的起始下标位置,length 指定读取的元素个数。

输出:

  • ByteArrayOutputStream([int size]):创建一个字节数组输出流,输出流缓冲区的初始容量大小由参数 size 指定,初始容量大小为 32 字节。
  • intsize():返回缓冲区中的当前字节数。
  • byte[] toByteArray():以字节数组的形式返回输出流中的当前内容。

文件输入流/输出

  • FileInputStream 输入是 Java流中比较常用的一种,它表示从文件系统的某个文件中获取输入字节。通过使用 FileInputStream 可以访问文件中的一个字节、一批字节或整个文件。

  • FileOutputStream(File file | String name,[boolean append])输出 :通过打开一个到实际文件的链接来创建一个 FileInputStream,file为文件系统中的 File 对象; name 为文件系统中的路径名。append指定是否将数据添加到目标文件的内容末尾,如果为 true,则在末尾添加。默认为false

字符输入流常用类

字符输入流/输出

输入:

  • CharArrayReader 类:将字符数组转换为字符输入流,从中读取字符。
  • StringReader 类:将字符串转换为字符输入流,从中读取字符。
  • BufferedReader 类:为其他字符输入流提供读缓冲区。
  • PipedReader 类:连接到一个 PipedWriter
  • InputStreamReader 类:将字节输入流转换为字符输入流,可以指定字符编码。

输出:

  • CharArrayWriter 类:向内存缓冲区的字符数组写数据。
  • StringWriter 类:向内存缓冲区的字符串(StringBuffer)写数据。
  • BufferedWriter 类:为其他字符输出流提供写缓冲区。
  • PipedWriter 类:连接到一个 PipedReader
  • OutputStreamReader 类:将字节输出流转换为字符输出流,可以指定字符编码

字符文件输入/输出流

输入:

  • FileReader(File file | String fileName):在给定要读取数据的文件的情况下创建一个新的 FileReader 对象。其中,file 表示要从中读取数据的文件对象。fileName表示的是一个文件的完整路径

输出:

  • FileWriter(File file | String fileName, boolean append) 写入数据, filefileName 同上,append的值为true,则将字节写入文件末尾,而不是写入文件开始处

FileWriter 类的创建不依赖于文件存在与否,如果关联文件不存在,则会自动生成一个新的文件。在创建文件之前,FileWriter 将在创建对象时打开它作为输出。如果试图打开一个只读文件,将引

字符缓冲区输入/输出流

输入:

  • BufferedReader(Reader in, [int size]) 创建一个 BufferedReader 来修饰参数 in 指定的字符输入流,参数 size 则用于指定缓冲区的大小,单位为字符 可选。
  1. 该类下除了字符输入流提供缓冲区的方法以外, 还有readLine()方法获取行信息

输出:

  • BufferedWriter(Writer out,[int size])创建一个 BufferedWriter 来修饰参数 out 指定的字符输出流,参数 size 则用于指定缓冲区的大小,单位为字符。
  1. 该类下除了字符输出流提供缓冲区的方法以外, 还有newLine()方法写入一个行分隔符

File类文件操作

创建File对象

  • new File(String path):如果 path 是实际存在的路径,则该 File 对象表示的是目录;如果 path 是文件名,则该 File 对象表示的是文件。
  • new File(String path, String name):path 是路径名,name 是文件名。
  • new File(File dir, String name):dir 是路径对象,name 是文件名。

File类的常用方法

方法 说明
boolean canRead() 测试应用程序是否能从指定的文件中进行读取
boolean canWrite() 测试应用程序是否能写当前文件
boolean delete() 删除当前对象指定的文件
boolean exists() 测试当前 File 是否存在
String getAbsolutePath() 返回由该对象表示的文件的绝对路径名
String getName() 返回表示当前对象的文件名或路径名(如果是路径,则返回最后一级子路径名)
String getParent() 返回当前 File 对象所对应目录(最后一级子目录)的父目录名
boolean isAbsolute() 测试当前 File 对象表示的文件是否为一个绝对路径名。该方法消除了不同平台的差异,可以直接判断 file 对象是否为绝对路径。
在 UNIX/Linux/BSD 等系统上,如果路径名开头是一条斜线/,则表明该 File 对象对应一个绝对路径;
在 Windows 等系统上,如果路径开头是盘符,则说明它是一个绝对路径。
boolean isDirectory() 测试当前 File 对象表示的文件是否为一个路径
boolean isFile() 测试当前 File 对象表示的文件是否为一个“普通”文件
long lastModified() 返回当前 File 对象表示的文件最后修改的时间
long length() 返回当前 File 对象表示的文件长度
String[] list() 返回当前 File 对象指定的路径文件列表
String[] list(Filter) 返回当前 File 对象指定的目录中满足指定过滤器的文件列表
boolean mkdir() 创建一个目录,它的路径名由当前 File 对象指定
boolean mkdirs() 创建一个目录,它的路径名由当前 File 对象指定
boolean renameTo(File) 将当前 File 对象指定的文件更名为给定参数 File 指定的路径名

操作练习

public  static  void main(String[] args) throws Exception{
        String url = "D:/text/file";
    
        File f = new File(url);
    
        System.out.println(f.canRead()); // 文件是否可以读取
        System.out.println(f.canWrite());// 文件是否可以写入
        System.out.println(f.exists()); // 文件是否存在
        System.out.println(f.getAbsolutePath()); // 返回文件的绝对路径
        String[] fileList = f.list(); // 返回文件目录
        System.out.println(Arrays.toString(fileList));

        /**
         * 创建文件对象
         * abc.txt d的文件内容为:这是一个文件内容 Hello world
        **/
        File txt = new File(url,"abc.txt");
    
        if(txt.exists()){// 如果文件存在
    
            //创建文件输入流对象
            FileInputStream fis = new FileInputStream(txt);
    
            // 创建byte 类型的数组
            byte[] bytes = new byte[1024];
            int n = fis.read(bytes); // 返回读取的字节数
    
            // 将字节转换为字符串
            String str = new String(bytes,0,n);
            System.out.println(str);
    
       }
}

读取文件内容,并增加新内容,然后保存到另一个新文件中

import java.io.*;
import java.util.ArrayList;

public class Main {
    public static String readUrl = "D:/mxx-project/myself/java-demos/file/abc.txt"; // 读取路径
    public static String writeUrl = "D:/mxx-project/myself/java-demos/file/abcCopy.txt"; // 写入路径
    public static ArrayList<String> alist = new ArrayList<String>(); // 存储数据

    // 读取文件内容
    public static void read()  throws Exception{
        String linStr = "";
        FileReader newFe = new FileReader(readUrl);

        // 创建缓冲区对象
        BufferedReader  bfr = new BufferedReader(newFe);

        // 将读取的每行内容添加到 ArryList 集合中
        while ((linStr = bfr.readLine()) != null){
            alist.add(linStr);
        }
        newFe.close();
        bfr.close();
        System.out.println(alist);
    }
    public  void modification(String str, int i) throws Exception{
        try{
            alist.add(i-1,str); // 向arrayList集合中增加内容
            System.out.println(alist);
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    public  void write() throws Exception{
        FileWriter fw = new FileWriter(writeUrl); // 创建FileWriter对象
        BufferedWriter  bfr = new BufferedWriter(fw);

        for(String str:alist){
            bfr.write(str); // 向缓存区写入内容
            bfr.newLine(); // 向缓存区写入分割符
        }
        bfr.flush(); //刷新输出流,强行将缓冲区的内容写入输出流
        fw.close();
    }

    public static void main(String[] args) throws Exception{

        Main m = new Main();
        m.read();
        m.modification("这是新增加的内容",2);
        m.write();
    }
}