Java中的IO流

IO流的分类

按照数据类型划分:字符流和字节流

按照数据流向划分:输入流和输出流

对于纯文本数据,优先使用字符流。除此之外都使用字节流。

File类

java.io.File:不能对文件内容(流)进行读写,只能对文件和文件夹进行操作

绝对路径和相对路径

路径不区分大小写,一个反斜杠是转义字符,两个反斜杠代表一个普通的反斜杠

绝对路径:一个完整的路径,以盘符开头,例如F:\\aaa.txt
相对路径:一个简化的路径,不以盘符开头,例如\\aaa.txt\\b.txt

构造方法

File类构造方法不会给你检验这个文件或文件夹是否真实存在,因此无论该路径下是否存在文件或者目录,都不影响File对象的创建。

// 文件路径名
String path2 = "D:\\1\\2.txt";
File file2 = new File(path2);     -------------相当于D:\\1\\2.txt

// 通过父路径和子路径字符串
 String parent = "F:\\aaa";
 String child = "bbb.txt";
 File file3 = new File(parent, child);  --------相当于F:\\aaa\\bbb.txt

// 通过父级File对象和子路径字符串
File parentDir = new File("F:\\aaa");
String child = "bbb.txt";
File file4 = new File(parentDir, child); --------相当于F:\\aaa\\bbb.txt

常用方法

方法 用途
public String getAbsolutePath() 获取此File的绝对路径名字符串。
public String getPath() 获取此File转换的路径名字符串。
public String getName() 获取由此File表示的文件或目录的名称。
public long length() 获取由此File表示的文件的长度。
public boolean exists() 判断此File表示的文件或目录是否实际存在。
public boolean isDirectory() 判断此File表示的是否为目录。
public boolean isFile() 判断此File表示的是否为文件。
public boolean createNewFile() 文件不存在,创建一个新的空文件并返回true,文件存在,不创建文件并返回false
public boolean delete() 删除由此File表示的文件或目录
public boolean mkdir() 创建由此File表示的目录
public boolean mkdirs() 创建由此File表示的目录,包括任何必需但不存在的父目录。(创建多级目录)
public String[] list() 返回一个String数组,表示该File目录中的所有子文件或目录
public File[] listFiles() 返回一个File数组,表示该File目录中的所有的子文件或目录

练习

递归遍历目录以及子目录下的所有文件(见同目录下的IDEA文件)

输入输出流

字节流概述

IO分类之后的父类
输入流 输出流
字节流 字节输入流 InputStream 字节输出流 OutputStream
字符流 字符输入流 Reader 字符输出流 Writer
OutputStream与InputStream的继承关系

继承关系

字节流基流

3.1.1)InputStream:

字节输入流基类,抽象类是表示字节输入流的所有类的超类。

方法 功能
abstract int read() //每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回-1
int read(byte[] b) // 每次读取b的长度个字节到数组b中,返回读取到的有效字节个数,读取到末尾时,返回-1
int read(byte[] b, int off, int len) // 将输入流中从 off 开始最多 len 个数据字节读入 byte 数组
long skip(long n) // 跳过和丢弃此输入流中数据的 n个字节
void close() // 关闭此输入流并释放与该流关联的所有系统资源
3.1.2)OutputStream

OutputStream:字节输出流基类,抽象类是表示输出字节流的所有类的超类。

方法 功能
void write(byte[] b) // 将 b.length 个字节从指定的 byte 数组写入此输出流
void write(byte[] b, int off, int len) // 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流
abstract void write(int b) // 将指定的字节写入此输出流
void close() // 关闭此输出流并释放与此流有关的所有系统资源
void flush() // 刷新此输出流并强制写出所有缓冲的输出字节

字节流文件操作流

字节文件输入流 (FileInputStream)

FileInputStream:字节文件输入流,从文件系统中的某个文件中获得输入字节,用于读取诸如图像数据之类的原始字节流。

①构造函数
构造方法 解释
FileInputStream(File file) // 通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的File对象file指定
FileInputStream(String name) // 通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的路径name指定
②代码示例
常用方法:覆盖和重写了父类的的常用方法。
        //构造方法1
        //InputStream inputStream = new FileInputStream(new File("f://hello//test.txt"));

        //构造方法2
        InputStream inputStream2 = new FileInputStream("f://hello/test.txt");
        // 字节数组
        byte[] b = new byte[2];
        int i2 = 0;
 		//  一次读取一个字节数组 -->int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b中
        while ((i2 = inputStream2.read(b)) != -1) {       
            //表示从缓冲区数组中输出从0开始的1个字节,也就是一个字母,如果改成2,就输出AB CD
            System.out.print(new String(b, 0, 1) + " ");// A B C D
        } //关闭IO流
        inputStream2.close();
字节文件输出流 (FileOutputStream)

FileOutputStream:字节文件输出流是用于将数据写入到File,从程序中写入到其他位置。

①构造函数
构造方法 解释
FileOutputStream(File file) // 创建一个向指定File对象表示的文件中写入数据的文件输出流
FileOutputStream(File file, boolean append) // 创建一个向指定File对象表示的文件中追加数据的文件输出流
FileOutputStream(String name) // 创建一个向具有指定名称的文件中写入数据的输出文件流
FileOutputStream(String name, boolean append) // 创建一个向具有指定name的文件中追加数据的输出文件流
②代码示例
     OutputStream outputStream = new FileOutputStream(new File("test.txt"));
        // 写出数据
        outputStream.write("ABCD".getBytes());
        // 关闭IO流
        outputStream.close();
        // 当布尔值为真,表示进行内容追加。当布尔值为假,表示清空原数据再添加
        OutputStream outputStream2 = new FileOutputStream("test.txt", true);
        // 输出换行符
        outputStream2.write("\r\n".getBytes());
        // 输出追加内容
        outputStream2.write("hello".getBytes());
        // 关闭IO流
        outputStream2.close();

注:输出的目的地文件不存在,则会自动创建,不指定盘符的话,默认创建在项目目录下;输出换行符时一定要写\r\n不能只写\n,因为不同文本编辑器对换行符的识别存在差异性。

练习:使用字节流文件操作流进行文件复制
public static void copy() {
        //不能把两个对象写在try中,否则finally无法调用这两个对象
        InputStream inputStream = null;
        OutputStream fileOutputStream = null;
        try {
            inputStream = new FileInputStream("F:\\FileTest.txt");
            fileOutputStream = new FileOutputStream("F:\\Copy.txt");
            byte[] b = new byte[1024];
            int len;
           	//len表明当前字节长度,b是用于存储读到的数据
            while ((len = inputStream.read(b)) != -1) {
                fileOutputStream.write(b,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

字符流概述

为什么要用字符流

字节流读取中文字符时,可能不会显示完整字符,那是因为一个中文字符占用多个字节存储。因此,当需要高效处理字符时,最佳的选择往往是字符流操作

当文件内含有中文时,下面的使用字节流的代码将输出乱码。

         //FileInputStream为操作文件的字符输入流
        FileInputStream inputStream = new FileInputStream("a.txt");
        int len;
        while ((len=inputStream.read())!=-1){
           System.out.print((char)len);
        }

虽然可以通过字节组来缓存文件的数组大小个字节,以达到一次读出多个字节的目的,但是仍然比较麻烦。

		FileInputStream inputStream = new FileInputStream("a.txt");
        byte[] bytes = new byte[1024];
        int len;
        while ((len=inputStream.read(bytes))!=-1){
           //利用了String构造方法的解码功能
           System.out.print(new String(bytes,0,len));
        }
字符流Reader和Writer的关系

Reader与Writer

字符流基类

读取字符流(Reader )

Reader:读取字符流的抽象类.

①常用方法
方法 作用
int read() // 读取单个字符
int read(char[] cbuf) // 将字符读入数组
abstract int read(char[] cbuf, int off, int len) // 将字符读入数组的某一部分
long skip(long n) // 跳过字符
abstract void close() // 关闭该流并释放与之关联的所有资源
②构造方法
FileReader类

java.io.FileReader类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。

方法 作用
FileReader(File file) 创建一个新的 FileReader ,给定要读取的File对象
FileReader(String fileName) 创建一个新的 FileReader ,给定要读取的文件的字符串名称
③代码示例
/**
 * 字符流:读
 */
public class FRRead {
    public static void main(String[] args) throws IOException {
      	// 使用文件名称创建流对象
       	FileReader fr = new FileReader("a.txt");
      	// 定义变量,保存数据
        int b ;
        // 一次可以读出一个字符,不需要再设定字节数组
        while ((b = fr.read())!=-1) {
            System.out.println((char)b);
        }
		// 关闭资源
        fr.close();
    }
}
写入字符流(Writer)

Writer:写入字符流的抽象类

①常用方法
方法 作用
void write(char[] cbuf) // 写入字符数组
abstract void write(char[] cbuf, int off, int len) // 写入字符数组的某一部分
void write(int c)
void write(String str)
void write(String str, int off, int len)
// 写入单个字符
// 写入字符串
// 写入字符串的某一部分
Writer append(char c)
Writer append(CharSequence csq)
Writer append(CharSequence csq, int start, int end)
// 将指定字符添加到此 writer
// 将指定字符序列添加到此 writer
// 将指定字符序列的子序列添加到此 writer.Appendable
abstract void close() // 关闭此流,但要先刷新它
abstract void flush() // 刷新该流的缓冲
②构造方法
FileWriter类

java.io.FileWriter类是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。

方法 作用
FileWriter(File file) 创建一个新的 FileWriter,给定要读取的File对象。
FileWriter(String fileName) 创建一个新的 FileWriter,给定要读取的文件的名称。
③代码示例
public class FWWrite {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象
        FileWriter fw = new FileWriter("fw.txt");     
      	// 写出数据
      	fw.write(97); // 写出第1个字符
      	fw.write('b'); // 写出第2个字符
      	fw.write('C'); // 写出第3个字符
      	
        //关闭资源时,与FileOutputStream不同。 如果不关闭,数据只是保存到缓冲区,并未保存到文件。
        // fw.close();
    }
}
输出结果:
abC

【注意】关闭资源时,与FileOutputStream不同。 如果不关闭,数据只是保存到缓冲区,并未保存到文件。

关闭close和刷新flush

因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要flush 方法了。

flush :刷新缓冲区,流对象可以继续使用。
close :先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。

练习:FileReader和FileWriter类完成文本文件复制
public class CopyFile {
    public static void main(String[] args) throws IOException {
        //创建输入流对象
        FileReader fr=new FileReader("F:\\新建文件夹\\aa.txt");//文件不存在会抛出java.io.FileNotFoundException
        //创建输出流对象
        FileWriter fw=new FileWriter("C:\\copyaa.txt");
        //文本文件复制,一次读一个字符
        copyMethod1(fr, fw);
        //文本文件复制,一次读一个字符数组
        copyMethod2(fr, fw);
        fr.close();
        fw.close();
    }

    public static void copyMethod1(FileReader fr, FileWriter fw) throws IOException {
        int ch;
        while((ch=fr.read())!=-1) {//读数据
            fw.write(ch);//写数据
        }
        //写一个字符刷新一次
        fw.flush();
    }

    public static void copyMethod2(FileReader fr, FileWriter fw) throws IOException {
        char chs[]=new char[1024];
        int len=0;
        while((len=fr.read(chs))!=-1) {//读数据
            fw.write(chs,0,len);//写数据
        }
        //写一个字符数组刷新一次
        fw.flush();
    }
}

`

IO异常的处理

我们在学习的过程中可能习惯把异常抛出,而实际开发中并不能这样处理,建议使用try...catch...finally 代码块,处理异常部分


缓冲流

创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。

字节缓冲流

构造方法
//构造方式一: 创建字节缓冲输入流【但是开发中一般常用下面的格式申明】
FileInputStream fps = new FileInputStream(b.txt);
BufferedInputStream bis = new BufferedInputStream(fps)

//构造方式一: 创建字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("b.txt"));

///构造方式二: 创建字节缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.txt"));

字符缓冲流

构造函数
// 创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("b.txt"));
// 创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));

总结:使用缓冲流对文件进行读写操作,效率将会快很多!


转换流

避免因编码问题导致的乱码现象。字符流=字节流+编码表

字符集

字符集也叫编码表,是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。编码表

InputStreamReader类

字节流到字符流的桥梁,是Reader的子类。它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。

构造方法
InputStreamReader isr = new InputStreamReader(new FileInputStream("in.txt"));

InputStreamReader isr2 = new InputStreamReader(new FileInputStream("in.txt") , "GBK");
使用转换流解决编码问题的例子
public class ReaderDemo2 {
    public static void main(String[] args) throws IOException {
      	// 定义文件路径,文件为gbk编码
        String FileName = "C:\\A.txt";
      	// 创建流对象,默认UTF8编码
        InputStreamReader isr = new InputStreamReader(new FileInputStream(FileName));
      	// 创建流对象,指定GBK编码
        InputStreamReader isr2 = new InputStreamReader(new FileInputStream(FileName) , "GBK");
		// 定义变量,保存字符
        int read;
      	// 使用默认编码字符流读取,乱码
        while ((read = isr.read()) != -1) {
            System.out.print((char)read); // �����ʺ      
        }
        isr.close();
      
      	// 使用指定编码字符流读取,正常解析
        while ((read = isr2.read()) != -1) {
            System.out.print((char)read);// 叶斯摩拉
        }
        isr2.close();
    }
}

OutputStreamWriter类

字符流到字节流的桥梁,是Writer的子类.使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。

构造方法
OutputStreamWriter isr = new OutputStreamWriter(new FileOutputStream("a.txt")); //默认为UTF-8编码方式

OutputStreamWriter isr2 = new OutputStreamWriter(new FileOutputStream("b.txt") , "GBK"); //指定文件写出为GBK编码
指定编码构造代码的一个例子
public class OutputDemo {
    public static void main(String[] args) throws IOException {
      	// 定义文件路径
        String FileName = "C:\\s.txt";
      	// 创建流对象,默认UTF8编码
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(FileName));
        // 写出数据
      	osw.write("加油"); // 保存为6个字节
        osw.close();
      	
		// 定义文件路径
		String FileName2 = "D:\\A.txt";
     	// 创建流对象,指定GBK编码
        OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream(FileName2),"GBK");
        // 写出数据
      	osw2.write("哥们");// 保存为4个字节
        osw2.close();
    }
}

为了达到最高效率,可以考虑在 BufferedReader 内包装 InputStreamReader

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

打印流

print方法和println方法都来自于java.io.PrintStream类。PrintStream是OutputStream的子类,PrintWriter是Writer的子类,打印操作效率最高

字节输出打印流PrintStream复制文本文件

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;

public class PrintStreamDemo {
    public static void main(String[] args) throws IOException {
        BufferedReader br=new BufferedReader(new FileReader("copy.txt"));
        PrintStream ps=new PrintStream("printcopy.txt");
        String line;
        while((line=br.readLine())!=null) {
            ps.println(line);
        }
        br.close();
        ps.close();
    }
}

字符输出打印流PrintWriter复制文本文件

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
/**
 * 使用打印流复制文本文件
 */
public class PrintWriterDemo {
    public static void main(String[] args) throws IOException {
        BufferedReader br=new BufferedReader(new FileReader("aa.txt"));
        PrintWriter pw=new PrintWriter("printcopyaa.txt");
        String line;
        while((line=br.readLine())!=null) {
            pw.println(line);
        }
        br.close();
        pw.close();
    }
}

I/O操作好文

史上最骚的I/O操作

posted @ 2022-08-05 23:04  Tayoou  阅读(95)  评论(0编辑  收藏  举报