2020年javaIO流课堂笔记

IO流

1.IO流概述

在java中,将这种通过不同输入输出设备(键盘、内存、显示器、网络等)之间的数据传输抽象表述为“流”。

I/O流主要分为3类

  1. 字节流和字符流:按照流操作的数据单位的不同
  2. 输入流和输出流:按照流传输方向的不同
  3. 节点流和处理流:按照流的功能不同

本节用到的架构:

2020年javaIO流课堂笔记_第1张图片

2.字节流

字节流概述

字节流:计算机所有文件(如文本、图片、视频等)都以字节形式存在,针对字节的输入输出提供了一系列的流。

InputStream的常用方法

方法声明 功能描述
int read() 返回从输入流读取的一个字节转化成的整数,没有则返回-1
int read(byte[] b) 将读取的字节保存到字节数组b中
int read(byte[] b,int off,int len) 将从位置off开始,len个字节读取的字节保存到字节数组b中
void close() 关闭输入流

OutputStream的常用方法

方法声明 功能描述
void write(int b) 向输出流写入一个字节
void write(byte[] b) 把字节数组b的所有字节写到输出流
void write(byte[] b,int off,int len) 将字节数组b从位置off开始的len个字节写入输出流
void flush() 刷新并强制写出所有缓冲的输出字节
void close() 关闭输出流

字节流读写文件

FileInputStream类和FileOutputStream

作用:操作文件数据

FileInputStream类实例代码

import java.io.FileInputStream;

public class Example{
    public static void main(String[] args) throws Exception {
        //创建一个文件字节输入流读取文件
        //创建好test.txt文件,写上hello
        FileInputStream in = new FileInputStream("test.txt");
        int b = 0;
        while((b=in.read())!=-1){
            System.out.print((char)b);
        }
        in.close();
    }
}

FileOutputStream类实例代码

import java.io.FileOutputStream;

public class Example{
    public static void main(String[] args) throws Exception {
        //创建文件输出流对象,并制定文件名称
        //append参数:
        //   true:如果文件有内容,在内容后面新添内容
        //   false:如果文件有内容,文件数据会被清空,再写入新数据
        FileOutputStream out = new FileOutputStream("out.txt", true);
        String str = "hello";
        out.write(str.getBytes());
        out.close();
    }
}

注意:为了保证I/O流的close()方法一定被执行,通常会将关闭流的操作写在finally代码块里。

finally{
 try{
  if(in!=null){      //如果in不为空,关闭输入流
   in.close();
 }
}catch(Exception e){
  e.printStackTrace();
 }
 try{
  if(out!=null){     //如果out不为空,关闭输出流
   out.close();
 }
}catch(Exception e){
e.printStackTrace();
 }
}

文件的拷贝

在应用程序中,I/O流通常成对出现

实例代码

import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Example{
    public static void main(String[] args) throws Exception {
        //创建输入流对象读取文件
        FileInputStream in = new FileInputStream("in.jpg");
        //创建输出流对象将读取到的文件写入到指定文件中
        FileOutputStream out = new FileOutputStream("dest.jpg");
        int b = 0;
        long startTime = System.currentTimeMillis();
        while((b=in.read())!=-1){
            out.write(b);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("一个耗费"+(endTime-startTime)+"毫秒。"); 
        //一个耗费692毫秒。
        in.close();
        out.close();
    }
}

字节流的缓冲区

作用:创建一个字节数组作为缓冲区,可以更快的拷贝文件

实例代码

import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Example{
    public static void main(String[] args) throws Exception {
        //创建输入流对象读取文件
        FileInputStream in = new FileInputStream("in.jpg");
        //创建输出流对象将读取到的文件写入到指定文件中
        FileOutputStream out = new FileOutputStream("dest.jpg");
        int len = 0;
        byte[] bytes = new byte[1024];
        //将字节数组作为缓冲区
        long startTime = System.currentTimeMillis();
        while((len=in.read(bytes))!=-1){
            out.write(bytes,0,len);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("一个耗费"+(endTime-startTime)+"毫秒。");
        //一个耗费1毫秒。
        in.close();
        out.close();
    }
}

字节缓冲流

BufferedInputStream类和BuffedOutputStream

作用:让数据的读写效率更高

构造方法的参数接收InputStream和OutputStream类型的对象

实例代码

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Example{
    public static void main(String[] args) throws Exception {
        //创建输入流对象读取文件
        BufferedInputStream in = new BufferedInputStream(new FileInputStream("in.jpg"));
        //创建输出流对象将读取到的文件写入到指定文件中
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("dest.jpg"));
        int len = 0;
        byte[] bytes = new byte[1024];
        long startTime = System.currentTimeMillis();
        while((len=in.read(bytes))!=-1){
            out.write(bytes,0,len);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("一个耗费"+(endTime-startTime)+"毫秒。");
        //一个耗费0毫秒。
        in.close();
        out.close();
    }
}

3.字符流

字符流概述

Reader类和Writer

作用:在程序中操作字符,用法与字节流类似

字符流操作文件

FileReader类:字符输入流,从文件中读取一个或一组字符

FileWriter类:字符输出流,如果指定的文件不存在,则先创建文件,再写入数据,如果存在,则先清空文件的数据,再进行写入。

FileReader类实例代码

import java.io.FileReader;

public class Example{
    public static void main(String[] args) throws Exception {
        //创建FileReader对象,并指定需要读取的文件
        FileReader reader = new FileReader("test.txt");
        int len = 0;
        while((len = reader.read())!=-1){
            System.out.print((char)len);
        }
        reader.close();
    }
}

FileWriter writerer = new FileWriter(“out.txt”,true);表示新添内容

FileWriter类实例代码

import java.io.FileWriter;

public class Example{
    public static void main(String[] args) throws Exception {
        //创建FileWriter对象,并指定写入数据的目标文件
        FileWriter writerer = new FileWriter("out.txt");
        writerer.write("床前明月光\n");
        writerer.write("疑是地上霜\n");
        writerer.write("举头望明月\n");
        writerer.write("低头思故乡\n" );
        writerer.close();
    }
}

用字符流的缓冲区来进行读写操作,提高执行效率

import java.io.FileReader;
import java.io.FileWriter;

public class Example{
    public static void main(String[] args) throws Exception {
        FileReader reader = new FileReader("test.txt");
        FileWriter writer = new FileWriter("out.txt");
        long startTime = System.currentTimeMillis();
        char[] chars = new char[1024];
        while((reader.read(chars))!=-1){
            writer.write(chars,0,chars.length);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("一共耗费"+(endTime-startTime)+"毫秒"); //1
        reader.close();
        writer.close();
    }
}

带缓冲功能的字符缓冲流:BufferedReader类和BufferedWriter

注意:BufferedReader类中的readLine()方法**,用于一次读取一行文本**。

实例代码

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;

public class Example{
    public static void main(String[] args) throws Exception {
        BufferedReader reader = new BufferedReader(new FileReader("test.txt"));
        BufferedWriter writer = new BufferedWriter(new FileWriter("out.txt"));
        long startTime = System.currentTimeMillis();
        String str = null;

        while((str=reader.readLine())!=null){
            writer.write(str);
            writer.newLine();//换行
        }
        long endTime = System.currentTimeMillis();
        System.out.println("一共耗费"+(endTime-startTime)+"毫秒"); //0
        reader.close();
        writer.close();
    }

转换流

InputStreamReader类和OutputStream

作用:将字节流转化为字符流

注意:使用转换流时,只能针对操作文本文件的字节流进行转换

实例代码

import java.io.*;

public class Example{
    public static void main(String[] args) throws Exception {
        InputStreamReader reader = new InputStreamReader(new FileInputStream("test.txt"));
        OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("out.txt"));
        BufferedReader br = new BufferedReader(reader);
        BufferedWriter bw = new BufferedWriter(writer);
        String str = null;
        while((str = br.readLine())!=null){
            bw.write(str);
            bw.newLine();
        }
        br.close();
        bw.close();
    }
}

4.File类

File类的常用方法

File类常用的构造方法

方法声明 功能描述
常用:File(String path) 通过一个path路径来创建File类对象
File(String parent,String child) 根据父路径和子路径来创建File类对象
File(File parent,String name) 根据File类的父路径和子路径创建File类对象

File类的常用方法

方法声明 功能描述
boolean exists() 判断File对象对应的文件或目录是否存在
boolean delete() 删除File对象对应的文件或目录
boolean createNewFile() 当File对象对应的文件不存在时,则新建文件
String getName() 返回File对象表示的文件和文件夹的名称
String getpath() 返回File对象对应的相对路径
String getAbsolutePath() 返回File对象对应的绝对路径
String getParent() 返回File对象对应的父路径
boolean canRead() 判断File对象对应的文件或目录是否可读
boolean canWrite() 判断File对象对应的文件或目录是否可写
boolean isFile() 判断File对象对应的是否是文件(不是文件夹)
boolean isDirectory() 判断File对象对应的是否是文件夹(不是文件)
boolean isAbsolute() 判断File对象对应的文件或目录是否是绝对路径
long lastModified() 返回1970年1月1日0时0分0秒到文件最后修改时间的毫秒值
long length() 返回文件内容的长度

实例代码

import java.io.File;

public class Example{
    public static void main(String[] args) {
        File file = new File("out.txt");
        System.out.println("文件名称:"+file.getName());
        System.out.println("文件的相对路径::"+file.getPath());
        System.out.println("文件的绝对路径::"+file.getAbsolutePath());
        System.out.println("文件的父路径::"+file.getParent());
        System.out.println(file.canRead()?"文件可读":"文件不可读");
        System.out.println(file.canWrite()?"文件可写":"文件不可写");
        System.out.println(file.isFile()?"是文件":"不是文件");
        System.out.println(file.isDirectory()?"是目录":"不是目录");
        System.out.println(file.isAbsolute()?"是绝对路径":"不是绝对路径");
        System.out.println("文件的最后修改时间:"+file.lastModified());
        System.out.println("文件的长度:"+file.length());
        System.out.println("是否删除文件"+file.delete());
    }
}

遍历目录下的文件

File类的遍历方法

方法声明 功能描述
String[] list() 列出文件夹里的全部文件名称
String[] list(函数式接口) 通过该函数式接口可以只列出符合条件的文件
File[] listFiles() 返回一个包含了File对象所有子文件和子目录的File数组

实例代码1

import java.io.File;
import java.util.Arrays;

public class Example{
    public static void main(String[] args) {
       //创建File对象,并指定文件路径
        File file = new File("D:\\FFOutput");
        //判断是否是目录
        if(file.isDirectory()){
            String[] list = file.list();
            Arrays.stream(list).forEach(System.out::println);
        }
    }
}

需求:如果只获取特定类型的文件,使用list(FilenameFilter filter)方法过滤文件。

FilenameFilter:函数式接口,即文件过滤器

内部有抽象方法accept(File dir,String name)对文件筛选。

实例代码2

import java.io.File;

public class Example{
    public static void main(String[] args) {
        File file = new File("D:\\FFOutput");
        //判断是否是目录
        if(file.isDirectory()){
            //过滤出以flv结尾的文件
            String[] lists = file.list(((dir, name) -> name.endsWith(".flv")));
            for (String list : lists) {
                System.out.println(list);
            }
        }
    }
}

需求:如果目录下还有子目录,如果想得到所有子目录下的File类型对象,则使用listFiles()方法

实例代码3

import java.io.File;

public class Example{
    public static void main(String[] args) {
        File files = new File("D:\\FFOutput");
        fileDir(files);

    }
   //迭代目录或文件
    public static void fileDir(File files){
       if(files.isDirectory()){
           File[] files1 = files.listFiles();
           for (File file : files1) {
               if(file.isDirectory()){
                   fileDir(file);
               }
               else{
                   System.out.println(file.getName());
               }
           }
       }else{
           System.out.println(files.getName());
       }
    }
}

删除文件或目录

需求:用delete()方法删除某一目录下的文件或文件夹

用法:先判断目录下是否有文件,如果存在则需要先删除内部文件,然后再删除空的文件夹

实例代码

import java.io.File;

public class Example{
    public static void main(String[] args) {
        File files = new File("D:\\java实验");
        deleteDir(files);
    }
    public static void deleteDir(File files){
        if(files.isDirectory()){
            File[] files1 = files.listFiles();
            for (File file : files1) {
                if(files.isDirectory()){
                    deleteDir(file);
                }
                file.delete();
            }
        }
            files.delete();
    }
}

注意:delete()方法删除的文件不经过回收站,永久性删除!!!谨慎使用!!!

5.RandomAccessFile类

作用:可以随机的从文件的任意位置开始执行读写操作

RandomAccessFile类的构造方法

方法声明 功能描述
RandomAccessFile(File file,String mode) 使用参数file指定被访问的文件,并使用mode来指定访问模式
RandomAccessFile(String name,String mode) 使用参数name指定被访问文件的路径,并使用mode来指定访问模式

参数mode指定访问文件的模式,即文件的操作权限

参数mode的4个值:

  • r:表示以“只读”的方式打开文件
  • rw:表示以“读写”的方式打开文件,如果文件不存在,则自动创建该文件
  • rws:“读写”,与“rw”相比,会将文件内容或源数据的更新同步写入底层的存储设备
  • rwd:“读写”,与“rw”相比,会将文件内容的更新同步写入底层的存储设备

RandomAccessFile类对象中包含一个记录指针来标识当前读写处的位置。

RandomAccessFile类中的常用方法

方法声明 功能描述
long getFilePointer() 获取当前记录指针所在的位置
void seek(long pos) 设定读写指针的位置,与文件开头相隔pos个字节数
int skipBytes(int n) 使读写指针从当前位置开始,跳过n个字节
void write(byte[] b) 将指定的字节数组写入到这个文件,并将指针移到其后面
void setLength(long newLength) 设置此文件的长度
final String readLine() 从指定文件当前指针读取下一行内容

实例代码

import java.io.RandomAccessFile;

public class Example{
    public static void main(String[] args) throws Exception {
        //创建RandomAccessFile对象,并以读写模式打开time.txt文件
        RandomAccessFile raf = new RandomAccessFile("time.txt", "rw");
        int times = Integer.parseInt(raf.readLine()) - 1;
        if(times > 0){
            System.out.println("您还可以使用"+times+"次!");
            raf.seek(0);
            raf.write((times+"").getBytes());
        }else{
            System.out.println("试用次数已经用完");
        }
        //关闭随机存取文件流并释放任何系统
        raf.close();
    }
}

6.对象序列化

java的对象序列化作用:将对象永久性地保存到磁盘上

  • 对象序列化:将一个java对象转换为一个I/O流中字节序列的过程。

  • 对象的反序列化:将I/O流中的字节序列恢复成java对象的过程。

在Java中,实现可序列化必须实现SerializableExternalizable这两个接口之一

SerializableExternalizable区别

实现Serializable接口(常用) 实现Externalizable接口
系统自动存储必要的信息 由程序员决定所存储的信息
java内部支持,易于实现,实现该接口即可 接口中提供了两个空方法,实现复杂
性能差 性能较好

7.NIO

NIO概述

NIO采用内存映射文件的方式处理输入输出

NIO传统I/O流的区别

  • 标准I/O中,使用字节流和字符流
  • 在NIO中,使用通道和缓冲区

NIO的三大核心部分:Buffer、channel、Selector

  • Buffer是一个容器,本质是数组缓冲区
  • Channel通道,是对传统的输入输出的模拟
  • Selector用于监听多个通道的事件(如:连接打开、数据到达等),主要用于多线程处理

本节用到的架构:

2020年javaIO流课堂笔记_第2张图片

Buffer(缓冲器)

要想创建Buffer对象,通过子类的static XxxBuffer allocate(int capacity)方法来实现

  • Xxx表示不同的数据类型
  • capacity表示容量

CharBuffer buffer = CharBuffer.allocate(6);

Buffer的3个重要概念

  1. capacity(容量):缓冲区的容量表示该Buffer的最大数据容量。缓冲区的值不能为负数,也不能够改变
  2. limit(界限):Buffer容器中索引为0到limit之间的区域都可以进行读取,limit不为负数,且不大于其容量
  3. position(位置):用于指定下一个可以被读写的缓冲区位置索引,position默认值为0,每进行一次读取或写入操作,position的值会自动向后移动一步

Buffer抽象类的常用方法

方法声明 功能描述
int capacity() 获取缓冲区的大小
Buffer clear() 清空缓冲区,即position为0,limit为capacity
Buffer flip() 反转缓冲区,即将limit设置为当前position位置,再将position设置为0
boolean hasRemaining() 判断position和limit之间是否还有元素
int limit 获取Buffer的limit位置
Buffer limit(int newLimit) 获取limit的值,并返回一个新的limit缓冲区对象
Buffer mark() 获取Buffer的标记,只能在0与position之间做标记
int position() 获取Buffer中position值
Buffer position(int newPosition) 设置Buffer的position值
int remaining() 获取当前位置和界限之间的元素个数
Buffer reset() 将此缓冲区的位置重置为先前标记的位置
Buffer rewind() 倒带缓冲区,将position为0,取消设置的标记

Buffer的所有子类中都额外提供了**put()get()**方法用于向Buffer中放入数据和取出数据

实例代码

import java.nio.CharBuffer;

public class Example {
    public static void main(String[] args) {
        //创建CharBuffer对象
        CharBuffer buffer = CharBuffer.allocate(6);
        System.out.println("容量:"+buffer.capacity());   //6
        System.out.println("界限值:"+buffer.limit());    //6
        System.out.println("初始位置:"+buffer.position());  //0
        //向CharBuffer对象中放入3个元素
        buffer.put('a');
        buffer.put('b');
        buffer.put('c');
        buffer.put('d');
        System.out.println("加入元素后的界限值:"+buffer.limit()); //6
        System.out.println("加入元素后的位置:"+buffer.position()); //4
        //执行flip()方法
        buffer.flip();
        System.out.println("执行flip()后的界限值:"+buffer.limit());   //4
        System.out.println("执行flip()后的位置::"+buffer.position());  //0
        //取出第1个元素
        System.out.println("取出第一个元素为:"+buffer.get());          //a
        System.out.println("取出元素后的界限值:"+buffer.limit());      //4
        System.out.println("取出元素后的位置:"+buffer.position());     //1
        //执行clear()方法
        buffer.clear();
        System.out.println("执行clear()后的界限值:"+buffer.limit());  //6
        System.out.println("执行clear()后的位置:"+buffer.position());  //0
        //取出第1个元素
        System.out.println("取出第一个元素为:"+buffer.get(0));   //a
        System.out.println("取出元素后的界限值:"+buffer.limit());   //6
        System.out.println("取出元素后的位置:"+buffer.position());  //0


    }
}

注意:执行完clear()方法后,Buffer对象中的数据依然存在,并且通过索引取出元素值后,position的值依然为0不变

Channel(通道)

Channel是一个接口对象,特点:

  • Channel可以异步地执行I/O读写操作
  • Channel的读写操作**是双向的(**流是单向的)
  • Channel可以直接将指定文件的部分或全部直接映射成Buffer
  • Channel只能与Buffer进行交互,程序不能直接读写Channel的数据

Channel对象是通过传统I/O的getChannel()方法来获取对应的Channel。

注意:不同的实现类所获取的Channel是不同的。

详解FileChannnel类

FileChannel类的常用方法

方法声明 功能描述
long position() 返回该通道的文件位置
int read(ByteBuffer dst) 从此通道读取一个字节序列给缓冲区dst
int read(ByteBuffer dst,long position) 从位置position开始,从此通道读取一个字节序列给缓冲区dst
long read(ByteBuffer[] dists,int offfset,int length) 从此通道读取一个字节序列给缓冲区dsts的子序列
long size() 返回该通道文件的当前大小
long transferTo(long position,long count,目标通道) 读取该通道从位置position开始,长count的字节数,并将它们写入目标通道
int write(ByteBuffer src) 将缓冲区src写入这个通道的字节序列
long write(ByteBuffer[] srcs,int offset,int length) 将缓冲区srcs的子序列中写入该通道的字节序列
int write(ByteBuffer src,long position) 将缓冲区src从位置position开始向通道写入一个字节序列

实例代码

import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;

public class Example {
    public static void main(String[] args) throws Exception {
        //获取读取文件的通道
        RandomAccessFile in = new RandomAccessFile("in.jpg", "rw");
        FileChannel inChannel = in.getChannel();
        //获取复制目标文件的通道
        RandomAccessFile out = new RandomAccessFile("dest_01.jpg", "rw");
        FileChannel outChannel = out.getChannel();
        //使用transferTo()方法整体复制
        long to = inChannel.transferTo(0, inChannel.size(), outChannel);
        if(to>0){
            System.out.println("复制成功");
        }
        //关闭资源
        in.close();
        out.close();
        inChannel.close();
        outChannel.close();
    }
}

8.NIO.2

NIO.2中提供了两个工具类paths类Files类

Paths类提供了两个静态方法来创建Path对象

方法声明 功能描述
Path Paths.get(URL url) 通过文件路径创建Path对象

(另一个极少用)

path接口

Path接口的常用方法

方法声明 功能描述
boolean endsWith(String other) 判断当前路径是否以字符串other结尾
Path getName(int index) 获取此路径的名称元素作为路径对象
int getNameCount() 返回路径中名称元素的数量
Path getParent() 返回父路径,没有返回null
Path getRoot() 返回根路径没有则返回null
Path toAbsolutePath() 返回此路径的绝对路径的路径对象
URI toUri() 返回此路径的URL地址

实例代码

import java.nio.file.Path;
import java.nio.file.Paths;

public class Example {
    public static void main(String[] args) throws Exception {
        Path path = Paths.get("C:\\Users\\lenovo\\Desktop\\MarkDown");
        System.out.println("path的父路径:"+path.getParent());
        System.out.println("path的根路径:"+path.getRoot());
        System.out.println("path的路径名称数"+path.getNameCount());
        //循环输出路径名称
        for (int i = 0; i < path.getNameCount(); i++) {
            Path name = path.getName(i);
            System.out.println("索引为"+i+"的路径的名称:"+name);
        }
        System.out.println("path的URL路径为"+path.toUri());
        System.out.println("path的绝对路径为"+path.toAbsolutePath());
    }
}

Files工具类

Files工具类的常用方法

方法声明 功能描述
static Path createDirectories(Path dir,FileAttribute…attrs) 创建多级文件目录
static Path createFile(Path path,FileAttribute…attrs) 创建一个空文件,如果文件存在,则创建失败
static Path copy(Path source,Path target,参数) 将一个文件复制到目标文件,参数:指定如何复制
static ListreadAllLines(Path path) 从文件中读取所有行
static long size(Path path) 返回文件的大小
static Stream list(Path dir) 将指定路径dir转化为Stream流对象
static Path write(Path path,集合,写入模式) 将文本行写入文件,并传入指定的写入模式

实例代码

public class Example {
    public static void main(String[] args) throws Exception {
        //文件目录不存在,否则异常
        Path directortypath = Paths.get("D:\\java的Files工具类\\实验");
        Files.createDirectories(directortypath);
        System.out.println("创建目录成功!");
        //定义一个文件路径的Path对象
        //文件名称不存在,否则异常
        Path file = Paths.get("D:\\java的Files工具类\\实验\\world.txt");
        Files.createFile(file);
        //根据Path对象创建一个文件
        ArrayList<String> list = new ArrayList<>();
        list.add("这是一个测试文件");
        Files.write(file,list, StandardOpenOption.APPEND);
        List<String> lines = Files.readAllLines(file);
        System.out.println("文件大小:"+Files.size(file));
        System.out.println("文件中的内容:"+lines);
    }
}

你可能感兴趣的:(java)