3.3 核心类库-IO

一、IO的概述

  • IO流概述
    • 可以将这种数据传输操作,看做一种数据的流动 , 按照流动的方向分为输入Input和输出Output
    • Java中的IO操作主要指的是 java.io包下的一些常用类的使用. 通过这些常用类对数据进行读取(输入Input) 和 写出(输出Output)

  • IO流的分类:
    • 按照流的方向来分,可以分为:输入流和输出流.
    • 按照流动的数据类型来分,可以分为:字节流和字符流

- 怎么判断输出流还是输入流?
输出流和输入流是相对于内存而言的,从内存出来就是输出,进入内存就是输入

  • 字节流:
    •      -   输入流 :   InputStream
      
    •      -   输出流 :   OutputStream
      
  • 字符流:
  • 字符流 = 字节流 + 编码表
    •      -   输入流 :   Reader
      
    •      -   输出流 :   Writer
      

  • 一切皆字节:
    •  计算机中的任何数据(文本,图片,视频,音乐等等)都是以二进制的形式存储的.
      
    •  在数据传输时 也都是以二进制的形式存储的.
      

在这里插入图片描述

在这里插入图片描述


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

二、OutputStream

  • java.io.OutputStream抽象类是表示字节输出流的所有类的超类(父类),将指定的字节信息写出到目的地,它定义了字节输出流的基本共性功能方法。
  • 字节输出流的基本共性功能方法(子类都会共享以下方法):
    • 1、 public void close() :关闭此输出流并释放与此流相关联的任何系统资源。
      2、 public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
      3、 public void write(byte[] b):将 b.length个字节从指定的字节数组写入此输出流。
      4、 public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。 也就是说从off个字节数开始读取一直到len个字节结束
      5、 public abstract void write(int b) :将指定的字节输出流。

  • FileOutputStream类
    OutputStream有很多子类,我们从最简单的一个子类FileOutputStream开始。看名字就知道是文件输出流,用于将数据写出到文件。
  • 构造方法:
    • 1、 public FileOutputStream(File file):根据File对象为参数创建对象。
      2、 public FileOutputStream(String name): 根据名称字符串为参数创建对象。(常用)
  •  FileOutputStream outputStream = new FileOutputStream("abc.txt");
    
public class FileOutputStreamConstructor throws IOException {
    public static void main(String[] args) {
   	 	// 使用File对象创建流对象
        File file = new File("G:\\自动创建的文件夹\\a.txt");
        FileOutputStream fos = new FileOutputStream(file);
      
        // 使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("G:\\b.txt");
    }
}
  • 创建一个流对象时,必须直接或者间接传入一个文件路径。比如现在我们创建一个FileOutputStream流对象,在该路径下,如果没有这个文件,会创建该文件。如果有这个文件,会清空这个文件的数据。

  • FileOutputStream写出字节数据
  • public void write(int b)
    public void write(byte[] b)
    public void write(byte[] b,int off,int len) //从off索引开始,len个字节
public class IoWrite {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("fos.txt");     
      	// 写出数据
      	fos.write(97); // 写出第1个字节
      	fos.write(98); // 写出第2个字节
      	fos.write(99); // 写出第3个字节
      	// 关闭资源
        fos.close();//流操作完毕后,必须释放系统资源!!!!!!!!!
    }
}
输出结果:
abc

public class FOSWrite {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("fos.txt");     
      	// 字符串转换为字节数组
      	byte[] b = "一二三四五".getBytes();
      	// 写出字节数组数据
      	fos.write(b);
      	// 关闭资源
        fos.close();
    }
}
输出结果:
一二三四五

public class FOSWrite {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("fos.txt");     
      	// 字符串转换为字节数组
      	byte[] b = "abcde".getBytes();
		// 写出从索引2开始,2个字节。索引2是c,两个字节,也就是cd。
        fos.write(b,2,2);
      	// 关闭资源
        fos.close();
    }
}
输出结果:
cd

  • public FileOutputStream(File file, boolean append)
    public FileOutputStream(String name, boolean append)
    这两个构造方法,第二个参数中都需要传入一个boolean类型的值,true 表示追加数据,false 表示不追加也就是清空原有数据。这样创建的输出流对象,就可以指定是否追加
public class FOSWrite {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("fos.txt"true);     
      	// 字符串转换为字节数组
      	byte[] b = "abcde".getBytes();
		// 写出从索引2开始,2个字节。索引2是c,两个字节,也就是cd。
        fos.write(b);
      	// 关闭资源
        fos.close();
    }
}
文件操作前:cd
文件操作后:cdabcde

public class FOSWrite {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("fos.txt");  
      	// 定义字节数组
      	byte[] words = {97,98,99,100,101};
      	// 遍历数组
        for (int i = 0; i < words.length; i++) {
          	// 写出一个字节
            fos.write(words[i]);
          	// 写出一个换行, 换行符号转成数组写出
            fos.write("\r\n".getBytes());
        }
      	// 关闭资源
        fos.close();
    }
}

输出结果:
a
b
c
d
e

三、InputStream

其实用法方法和输出流类似,直接上代码解释:

public class FileInputStreamConstructor throws IOException{
    public static void main(String[] args) {
   	 	// 使用File对象创建流对象
        File file = new File("a.txt");
        FileInputStream fos = new FileInputStream(file);
      
        // 使用文件名称创建流对象
        FileInputStream fos = new FileInputStream("b.txt");
    }
}

  • FileInputStream读取字节数据:read方法,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回-1
public class FISRead {
    public static void main(String[] args) throws IOException{
      	// 使用文件名称创建流对象
       	FileInputStream fis = new FileInputStream("read.txt");//read.txt文件中内容为abcde
      	// 读取数据,返回一个字节
        int read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
      	// 读取到末尾,返回-1
       	read = fis.read();
        System.out.println( read);
		// 关闭资源
        fis.close();
    }
}
输出结果:
a
b
c
d
e
-1

  • 通过循环优化:
public class FISRead {
    public static void main(String[] args) throws IOException{
      	// 使用文件名称创建流对象
       	FileInputStream fis = new FileInputStream("read.txt");
      	// 定义变量,保存数据
        int b ;
        // 循环读取
        while ((b = fis.read())!=-1) {//也可以写一个死循环
            System.out.println((char)b);
        }
		// 关闭资源
        fis.close();
    }
}
输出结果:
a
b
c
d
e
  • 开发中实际的写法:
package io;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class input2 {
    public static void main(String args[]){
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream("a.txt");
            int len = 0 ;
            byte[] bys = new byte[1024];
            while ((len = inputStream.read(bys)) != -1) {
                System.out.println(new String(bys,0,len));
            }
        
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}


四、Reader

  • java.io.Reader抽象类是字符输入流的所有类的超类(父类),可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。
  • 方法:
  • 1、public void close() :关闭此流并释放与此流相关联的任何系统资源。
    2、 public int read(): 从输入流读取一个字符。
    3、 public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中

  • FileReader类
    java.io.FileReader类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区
    • 构造方法:
      1、FileReader(File file): 创建一个新的 FileReader ,给定要读取的File对象。
      2、 FileReader(String fileName): 创建一个新的 FileReader ,给定要读取的文件的字符串名称。
public class FileReaderConstructor throws IOException{
    public static void main(String[] args) {
   	 	// 使用File对象创建流对象
        File file = new File("a.txt");
        FileReader fr = new FileReader(file);
      
        // 使用文件名称创建流对象
        FileReader fr = new FileReader("b.txt");
    }
}


  • 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

  • java.io.Writer抽象类是字符输出流的所有类的超类(父类),将指定的字符信息写出到目的地。它同样定义了字符输出流的基本共性功能方法
  • 字符输出流的基本共性功能方法:
    1、void write(int c) 写入单个字符。
    2、void write(char[] cbuf)写入字符数组。
    3、 abstract void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
    4、 void write(String str)写入字符串。
    5、void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
    6、void flush()刷新该流的缓冲。
    7、void close() 关闭此流,但要先刷新它。

  • FileWriter类
    java.io.FileWriter类是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
    * 构造方法:
    1、 FileWriter(File file): 创建一个新的 FileWriter,给定要读取的File对象。
    2、FileWriter(String fileName): 创建一个新的 FileWriter,给定要读取的文件的名称。
public class FileWriterConstructor {
    public static void main(String[] args) throws IOException {
   	 	// 第一种:使用File对象创建流对象
        File file = new File("a.txt");
        FileWriter fw = new FileWriter(file);
      
        // 第二种:使用文件名称创建流对象
        FileWriter fw = new FileWriter("b.txt");
    }
}


  • 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不同。 如果不关闭,数据只是保存到缓冲区,并未保存到文件。


六、Flush

  • flush :刷新缓冲区,流对象可以继续使用。
    close:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
public class FlushDemo {
    public static void main(String[] args) throws Exception {

        //这个就是把读到的内容存到另一个文件中去

        //源   也就是输入流【读取流】 读取a.txt文件
        FileReader fr=new FileReader("a.txt");  //必须要存在a.txt文件,否则报FileNotFoundException异常
        //目的地  也就是输出流
        FileWriter fw=new FileWriter("b.txt");  //系统会自动创建b.txt,因为它是输出流!
        int len;
        while((len=fr.read())!=-1){
           fw.write(len);
        }
    fr.close();
    fw.flush();
    fw.close();
}
}

  • flush()这个函数是清空的意思,用于清空缓冲区的数据流,进行流的操作时,数据先被读到内存中,然后再用数据写到文件中,那么当你数据读完时,我们如果这时调用close()方法关闭读写流,这时就可能造成数据丢失,为什么呢?因为,读入数据完成时不代表写入数据完成,一部分数据可能会留在缓存区中,这个时候flush()方法就格外重要了。
public class FWWrite {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象
        FileWriter fw = new FileWriter("fw.txt");
        // 写出数据,通过flush
        fw.write('刷'); // 写出第1个字符
        fw.flush();
        fw.write('新'); // 继续写出第2个字符,写出成功
        fw.flush();
      
      	// 写出数据,通过close
        fw.write('关'); // 写出第1个字符
        fw.close();
        fw.write('闭'); // 继续写出第2个字符,【报错】java.io.IOException: Stream closed
        fw.close();
    }
}


  • FileReader和FileWriter类完成文本文件复制
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

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");
        /*创建输出流做的工作:
         *      1、调用系统资源创建了一个文件
         *      2、创建输出流对象
         *      3、把输出流对象指向文件        
         * */
        //文本文件复制,一次读一个字符
        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();
    }
}




六、字节缓冲流

  • 构造方法
    public BufferedInputStream(InputStream in) :创建一个新的缓冲输入流,注意参数类型为InputStream。
    public BufferedOutputStream(OutputStream out): 创建一个新的缓冲输出流,注意参数类型为OutputStream
//构造方式一: 创建字节缓冲输入流【但是开发中一般常用下面的格式申明】
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"));


缓冲流的根本就是为了加快文件传输的速度,尤其争对大内存的文件。

public class BufferedDemo {
    public static void main(String[] args) throws FileNotFoundException {
      	// 记录开始时间
        long start = System.currentTimeMillis();
		// 创建流对象
        try (
		 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("py.exe"));
		 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copyPy.exe"));
        ){
          	// 读写数据
            int len;
            byte[] bytes = new byte[8*1024];
            while ((len = bis.read(bytes)) != -1) {
                bos.write(bytes, 0 , len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
		// 记录结束时间
        long end = System.currentTimeMillis();
        System.out.println("缓冲流使用数组复制时间:"+(end - start)+" 毫秒");
    }
}
缓冲流使用数组复制时间:521 毫秒  // 相比基本的传输方法速度有快很多


七、字符缓冲流

字符缓冲流的基本方法与普通字符流调用方式一致,这里不再阐述,我们来看字符缓冲流具备的特有方法。

BufferedReader:public String readLine(): 读一行数据。 读取到最后返回null
BufferedWriter:public void newLine(): 换行,由系统属性定义符号。

public class BufferedWriterDemo throws IOException {
  public static void main(String[] args) throws IOException  {
    	// 创建流对象
  	BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
    	// 写出数据
      bw.write("2222");
    	// 写出换行
      bw.newLine();
     
  	// 释放资源
      bw.close();
  }
}
输出效果:
2222
  • 综合代码
public class BufferedTest {
    public static void main(String[] args) throws IOException {
        // 创建map集合,保存文本数据,键为序号,值为文字
        HashMap<String, String> lineMap = new HashMap<>();

        // 创建流对象  源
        BufferedReader br = new BufferedReader(new FileReader("a.txt"));
        //目标
        BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));

        // 读取数据
        String line  = null;
        while ((line = br.readLine())!=null) {
            // 解析文本
            String[] split = line.split("\\."); //  \\是转义符 别理解错了 就是单纯加一个 . 去间隔key和value
            // 保存到集合
            lineMap.put(split[0],split[1]);//0是key的下标 
        }
        // 释放资源
        br.close();

        // 遍历map集合
        for (int i = 1; i <= lineMap.size(); i++) {
            String key = String.valueOf(i);
            // 获取map中文本
            String value = lineMap.get(key);
          	// 写出拼接文本
            bw.write(key+"."+value);
          	// 写出换行
            bw.newLine();
        }
		// 释放资源
        bw.close();
    }
}


八、转换流

  • InputStreamReader类-----(字节流到字符流的桥梁)
  • 构造方法
    InputStreamReader(InputStream in): 创建一个使用默认字符集的字符流。
    InputStreamReader(InputStream in, String charsetName): 创建一个指定字符集的字符流。
  • 构造代码如下:
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类-----(字符流到字节流的桥梁)
  • 构造方法
    OutputStreamWriter(OutputStream in): 创建一个使用默认字符集的字符流。
    OutputStreamWriter(OutputStream in, String charsetName): 创建一个指定字符集的字符流。
  • 构造举例,代码如下:
OutputStreamWriter isr = new OutputStreamWriter(new FileOutputStream("a.txt"));
OutputStreamWriter isr2 = new OutputStreamWriter(new FileOutputStream("b.txt") , "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("我是人"); 
        osw.close();
      	
		// 定义文件路径
		String FileName2 = "D:\\A.txt";
     	// 创建流对象,指定GBK编码
        OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream(FileName2),"GBK");
        // 写出数据
      	osw2.write("我是人");
        osw2.close();
    }
}


在这里插入图片描述


  • 为了达到最高效率,可以考虑在 BufferedReader 内包装 InputStreamReader
BufferedReader in = new BufferedReader(new InputStreamReader(System.in))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值