Java学习笔记06(I/O流)

I/O流

I/O流概述

I/O(input/output)流,输入输出流,可以对数据进行输入输出操作。

I/O流从三个方面分类:

  • 字符流和字节流;
  • 输入流和输出流;
  • 节点流和处理流;

Java中的 I/O 流主要定义咋java.io包下,有四个类 为 流 的顶级类;
分别为:InputStream, OutStream, Reader, Writer ; 前两种为字节流,后两种为字符流。 InputStream,Reader 是输入流,OutputStream,Writer 输入流;

四种类都是抽象类,是所有流的父类;

字节流

计算机中的文本、图片、视频都是以二进制字节形式存在的;
字节类的顶级父类为 InputStream,OutputStream; 所有的字节输入流都继承 InputStream,字节输出流继承 OutputStream;
输入输出是相对于程序来说的,向程序传输数据称为输入流,程序向外传输称为输出流;

InputStream OutputStream 的 常用方法;

// InputStream 
int read()            // 从输入流读取一个字节,并返回该字节的整数值;没有返回 -1
int read( byte[] b)   // 从输入流读取若干字节 , 将他们存入 b 数组 中 , 返回的整数代表读取的数目; 
int read( byte[] b, int off,int len)//  将读取的字节放入 b 数组 中, off 表示开始存储字节的下标, len 表示读取字节的数目;
    
//OutputStream
void write(int b);			// 向输出流写入一个字节
void write(byte[] b)		// 将 b 数组的所有字节写入输出流
void write(byte[] b, int off, int len)  // 将 b 数组中 从 off 开始 输出 len 个字节

字节流读写文件

用来进行对文件的读写;两个类:FileInputStream , FileOutputStream;

FileInputStream:InputStream的子类,用来 操作文件的 字节输入流;

代码举例:

 public static void main(String[] args) throws Exception{              //I/O 流必须要 处理异常
        FileInputStream in = new FileInputStream("E:\\test.txt");	  // 创建 文件字节输入流 in	,文件的 位置 E:\\test.txt
        int b;
        while ((b =in.read() ) != -1){         // read() 方法为 从输入流 读取一个8位的字节,将它转化为 0-255 之间的整数并返回,没有返回 -1
            System.out.println(b);
        }
        in.close();								// 关闭输入流 并 释放系统资源;
    }

FileOutoutStream:OutPutStream的子类,用来 操作文件的 字节输入流;

代码举例:

 public static void main(String[] args) throws Exception{
        FileOutputStream out = new FileOutputStream("E:\\out.txt");  // 创建的文件为 E:\out.txt 
        String str = "hello";
        out.write(str.getBytes());				// 写入 输出流 , getBytes()方法 返回 str的 字节 数组; write( byte[] b) 将b数组写入流;
        out.close();							//关闭输出流
    }

注意点:若 写入 的 文件中本来就存在数据, 则会把 文件中的数据情况 在 存入 新的数据;

若想要在 文件中追加 数据,用下面的构造方法 实例化对象:

// FileOutputStream(String fileName , boolean append);  将 append 设置为 true
FileOutputStream out = new FileOutputStream("E:\\out.txt",true);

注意点:一般在 finally 代码块中 关闭 输入输出流,防止因出现异常 导致 输入输出流无法正常关闭;

拷贝文件代码举例:

 public static void main(String[] args) throws Exception{
        FileInputStream in = new FileInputStream("C:\\Users\\86185\\Pictures\\Saved Pictures\\3.jpg");//创建输入流
        FileOutputStream out = new FileOutputStream("E:\\img.jpg");  //创建输出流对象
        int len = 0;
        long time1 = System.currentTimeMillis();
        while ((len = in.read()) != -1) {
            out.write(b);
        }
        long time2 =System.currentTimeMillis();
        System.out.println("使用时间" + (time2 - time1)+ "毫秒" );
        in.close();
        out.close();
    }

上述实现的字节流 是 一个字节一个字节进行的拷贝,效率极低 ,为了提高效率,我们需要用到缓冲区,来提高效率;
在拷贝文件时 一次性读取多个字节的数据,保存到字节数组中, 然后将字节数组一次性写入新文件;

 	    byte[] buff = new byte[1024];      //创建一个 字节 数组 来 当作 缓冲区
	    int len = 0;
        while ((len = in.read(buff)) != -1) {     // read(byte[] b) 方法 ,从输入流 读 若干字节放入 b(buff) 数组中;
            out.write(buff);					// 将buff中的字节 写入 文件
        }

字节缓冲流

BufferedInputStream, BufferedOunputStream; 带缓冲的字节流;他们的构造函数 接收 InputStream 和 OutputStream 类型的参数作为对象,在读写时提供缓冲功能; 继承 FileInputStream 和 FileOutputStream

public static void main(String[] args) throws Exception{
        FileInputStream in = new FileInputStream("C:\\Users\\86185\\Pictures\\Saved Pictures\\3.jpg");//创建输入流
        FileOutputStream out = new FileOutputStream("E:\\img.jpg");  //创建输出流对象
        BufferedInputStream bis = new BufferedInputStream(in);// 创建字节缓冲输入流对象
        BufferedOutputStream bos = new BufferedOutputStream(out);//创建字节缓冲输出流对象
        int len = 0;
        long time1 = System.currentTimeMillis();
        while (( len =  bis.read() )!= -1) {
            bos.write(len);
        }
        long time2 =System.currentTimeMillis();
        System.out.println("使用时间" + (time2 - time1)+ "毫秒" );
        in.close();
        out.close();
    }

两个字节缓冲流内部都定义了一个大小为 8192的 byte[] ,当调用 read() 和 write() 方法时 ,会 先将数据 存入到定义好的字节数组,然后将数组一次性读写入文件;

字符流

顶级父类: Reader 和 Writer 字符流;用来 读写 字符;

字符流操作文件

FileReaderFileWriter 分别为 文件输入流 和 文件输入流;

这两个类的使用方法和 之前的 FileInputStream 和 FileOutputStream 基本一致;

也可以使用 一个 字符数组 实现 缓冲 ,用来拷贝文件;

字符缓冲流

BufferedReader 和 BufferedWrite 字符缓冲流;

一个重要的方法 readLine() 一次读取一行文本;

 public static void main(String[] args) throws Exception {
        FileReader reader = new FileReader("reader.txt");   //文件
        FileWriter writer = new FileWriter("writer.txt");
        BufferedReader br = new BufferedReader(reader);         //字符缓冲输入流对象
        BufferedWriter bw = new BufferedWriter(writer);         //字符缓冲输出流对象
        String str;
        while ((str = br.readLine()) != null){            //readLine 用来读取一行,
            bw.write(str);                              //
            bw.newLine();                       // 每写入一行之后 进行换行。
        }
        br.close();
        bw.close();
    }

转换流

Java中提供两个类实现 字节流转化为字符流; 分别为 InputStreamReader (Reader 的一个子类) 和 OutputStreamWriter (Writer的一个子类), 前者是 将字节输入流转化为字符输入流,后者是 将 字节输出流转化为 字符输出流;

public static void main(String[] args) throws Exception {
        FileInputStream in = new FileInputStream("reader.txt");   //文件字节输入流
        InputStreamReader is = new InputStreamReader(in);               // 将字节输入流转化为 字符输入流
        BufferedReader br = new BufferedReader(is);                     // 创建字符流缓冲对象
        FileOutputStream out = new FileOutputStream("writer2.txt"); // 创建字节 输出流
        OutputStreamWriter os = new OutputStreamWriter(out);            //将字节输出流 转化为 字符输出流
        BufferedWriter bw = new BufferedWriter(os);                     //创建 字符缓冲流对象;
    }

注意点: 使用转化流时 ,只能将 文本文件的 字节流转化为字符流,若是图片视频,转换会照成数据丢失。

File类

I/O流可以操作文件内部数据,但是无法对整个个文件进行操作,File类可以就整个文件进行操作;

File类的常用方法举例:

public static void main(String[] args) throws Exception {
        File file = new File("test\\writer2.txt");   //创建一个文件对象;  参数为文件的 相对 或者 绝对路径
        file.getName();                                  //得到文件名称
        file.getPath();                                  //得到文件的相对路径
        file.getAbsolutePath();                          //得到文件的绝对路径
        file.getParent();                            //得到文件的父路径
        file.canRead();                                   //文件可读?true:false
        file.canWrite();                                //文件可写? true:false
        file.isFile();                                //是否为文件?true:false
        file.isDirectory();                          //是非为目录?true:false
        file.isAbsolute();                          //是否为绝对路径?true:false
        file.lastModified();                        //文件的最后修改时间;
        file.length();                              //文件的大小为多少字节
        file.delete();                              //是否成功删除文件
    }

File类中 有一个 遍历目录中所有文件名称 的 list() 方法,

   File file = new File("test");   //创建一个文件或者目录对象;
        if(file.isDirectory()) {                 //判断是否为目录
 0.         String[] fileNames = file.list();    // list() 返回一个 String数组
            // list()的一个重载方法,过滤文件;
 1.         String[] fileNames = file.list( (dir , name)-> name.endsWith(".txt") )  // 选择以 .txt 结尾的文件;
            for (String name : fileNames){       //遍历数组
                System.out.println(name);
            }
        }

listFile() 方法 , 返回 值 是一个 File对象数组,它一般用来 遍历目录中还存在目录的情况;

    public static void main(String[] args) throws Exception {
        File file = new File("test");   //创建一个file 对象;
        fileDir(file);
    }
    public static void fileDir(File file){
        File[] listFiles = file.listFiles();      //调用 listFiles()方法 ,返回一个File对象数组;
        for (File f : listFiles) {                // 遍历 File 对象 数组
            if(f.isDirectory()){                   // 判断 元素 是否为 目录。是 的 话 递归方法;
                fileDir(f);                         // 递归调用
            }
            System.out.println(f.getAbsolutePath());      //输出文件绝对路径
        }
    }

delete()方法,使用该方法删除 文件夹时,需要判断 文件夹中是否有内容,若没有 才可以删除;有内容,必须先把文件夹清空才可以删除;需要用到上面遍历文件夹中含有文件夹的方法;

注意,删除时直接删除,不会存到回收站。

随机存取文件

RandomAccessFile类,可以从文件的任意位置对文件内容进行操作;不同于之前的I/O流,只能从开始操作,它不属于流类;

两种构造方法:

RandomAccessFile(File file ,String mode);		//使用 File 指定被访问文件 mode 为 r读 rw只读 和 rws  rwd
RandomAccessFile(String name,String mode);		//使用name 指定 被访问文件的路径    mode为访问模式  四种 r rw rws rwd

常用方法举例:

long getFilePointer()		// 返回当前读写指针所处的位置;
void seek(long pos)			//设置指针的位置 距离 文件开发 pos个字节数
int skipBytes(int n)		// 从当前指针开始,跳过n个字节
void write(byte[] b)		// 将 b 字节数组 写入文件,从当前指针开始
final String readLine()		// 从 当前指针读取下一行内容

对象序列化

对象的序列化 Serializable : 将一个 Java 对象转化成 一个 I/O流中的字节序列的过程; 这是 为了 可以 将对象保存到磁盘或者 在网络中传输Java对象;

反序列化 Deserialize : 将一个I/O流中的字节序列 转化为 一个Java对象的过程;

想让一个类称为可序列化的 必须 实现 Serializable 或者 Externalizable 接口

Serializable 系统自动存储必要信息 容易实现 只需要实现接口即可 性能较差;
Externalize 程序员决定所存储的信息 ;
实际开发中经常使用 Serializable接口

只要给一个类 实现 Serializable 接口 ,该类即可序列化

public static Person implements Serializable {
    private static final long serializableVersionUID = 1L; // 表示序列化版本  ,不显示定义JVM会计算出一个serialVersionUID变量值
}

NIO

NIO(new I/O),为了替代传统的IO而出现, 它采用 内存映射的方式来处理输入和输出 ,将文件 或者 文件的一段 映射到内存中,这样就可以像访问内存一样来访问内存了;

标准I/O,使用字节流和字符流,在 NIO中,使用的是 通道(Channel) 和 缓冲区(Buffer)。数据从通道读入缓冲区,或从缓冲区写入通道;

NIO的三大核心部分:Buffer , Channel , Selector;

  • Buffer: 一个容器,本质是一个数组缓冲区 , 读入和写出到 Channel中的所有对象会先放在 Buffer 中;
  • Channel: 所有数据通过通道传输;
  • Selector : 选择器 , 用于监听多个通道事件,主要用于多线程;

Buffer

缓冲器:

buffer类似于一个数组,可以保存多个相同的类型的数组。
是一个抽象类,子类有 ByteBuffer, CharBuffer ,DoubuleBuffer, FloatBuffer ,IntBuffer ,LongBuffer ,ShortBuffer ;
buffer的子类没有构造方法,通过一个方法 static XxxBuffer allocate(int capacity) 来 创建 对象;

   CharBuffer charBuffer = CharBuffer.allocate(6);  // 创建一个 容量为 6 的 CharBuffer 对象

capacity (容量) ; limit(界限) ; position (位置)

  • capacity: 缓冲区能存入数据的最大容量,能存入多少数据;不能为 负, 不能改变;
  • limit : 表示 缓冲区不可读取区域的第一个索引, 0 – limit 区域的索引都能读取。之后的不可读取操作; 不能为 负, 不大于 capacity
  • position: 指定下一个被读取的区域索引; 新创建的 buffer position 为 0; 没执行一次自动加1;

Buffer 类中 一些方法距离:

   CharBuffer charBuffer = CharBuffer.allocate(6);  // 创建一个 容量为 6 的 CharBuffer 对象
        charBuffer.capacity();       // 返回缓冲区的容量
        charBuffer.limit();          //返回缓冲区的界限值
        charBuffer.position();       //返回缓冲区的位置
        charBuffer.put('x');         //像缓冲区内存入一个元素,  此时 position + 1
        charBuffer.flip();           //反转缓冲区,先将 limit 和 position 值互换,然后 position设置为0;
        charBuffer.get();            //取出 position 位置元素 , 取出后 position + 1 ; 若 带有索引,position不改变
        charBuffer.clear();          //清除缓冲区 position设置为0 limit 设置为 capacity , 缓冲区 元素 还存在

Channel

通道:

Channel 是 一个接口对象 ;
实现类: FileChannel 用于从文件中读写数据;
DatagramChannel 用于支持 UDP网络通信;
Pipe.SinkChannel 和 Pipe.SoureceChannel 用于支持线程之间的通信;
ServerSocketChannel 和 SocketChannel 用于 支持 TCP网络通信;

Channel 对象 通过 传统I/O的 getChannel 方法 来获得对应 的 Channel。

FileChannel 的一些方法:

public static void main(String[] args)  throws  Exception{
        RandomAccessFile infile = new RandomAccessFile("test\\time.txt", "rw");//创建一个随机存取文件对象,指定源文件
        FileChannel inChannel = infile.getChannel(); // 获取 RandomAccessFile 对象 对应的 通道 对象;
        RandomAccessFile outfile = new RandomAccessFile("test\\time1.txt","rw");  //创建对象,指定目标文件
        FileChannel outChannel = outfile.getChannel();          // 获取 复制 目标文件的通道
        long transferTo = inChannel.transferTo(0, inChannel.size(), outChannel);// transferTo()方法\
        //  long transferTO (long position , long count , WritableByteChannel target)  读取通道给定 位置 和大小,并写入目标通道
        //  long size() 方法 返回 通道的大小
        if (transferTo > 0){
            System.out.println(复制成功);
        }
        infile.close();
        inChannel.close();
        outChannel.close();
        outfile.close();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值