Java--IO流总结

在这里插入图片描述
一、流
1、概念:一组有顺序、有起点和终点的字节集合,是对数据传输的总称或抽象。
2、本质:数据传输
根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作,一般用于文件操作、socket等。
3、分类
(1)根据操作单元分:字符流和字节流
①字节流【InputStream、OutputStream】:操作8bit字节,将数据解释成原始的二进制数,读写均为字节数据,因为不需要编码和解码的,比文本i/o效率高,
可移植,java中可以按照最小字节单位读取的流,即每次读写一个字节,字节流直接连接到输入源。
②字符流【Reader、Writer】:操作16位字符,将原始数据解释成字符的序列,输入和输出需要进行编码和解码,因为数据编码的不同,而有了对字符进行高效操作的流对象,本质是基于字节流读取时,去查指定的码表。
字符流和字节流的区别:
①读写单位不同
字节流以字节(8bit)为单位;字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
②处理对象不同
字节流能处理所有类型的数据;字符流只能处理字符类型的数据。
③读入读出字节位不同
字节流一次读入或读出是8位二进制;字符流一次读入或读出是16位二进制。
注:设备上的数据无论是图片、视频、文字,都以二进制存储的。二进制最终都以一个8位为数据单元进行体现,计算机中的最小数据单元就是字节。意味着,字节流可以处理设备上的所有数据,所以字节流一样可以处理字符数据。
结论:只要是处理纯文本数据,优先考虑使用字符流, 除此之外都使用字节流。
(2)根据数据流向分:输入流和输出流
①输入流【InputStream、Reader】:存储介质→程序,读取数据(从磁盘、硬盘、键盘、socket等)到程序中。
②输出流【OutputStream、Writer】:程序→目标源,将程序中的数据输出(到磁盘、硬盘、显示器、socket等)。
(3)根据流的角色分:节点流和处理流
①节点流(节点:文件、内存缓冲区如Byte数组,Char数组,StringBuffer对象等):也叫做原始流,直接和IO设备相连,主要指从具体介质上读取或写入数据的类。
②处理流:主要指FilterInputStream/FilterOutStream和FilterReader/FilterWriter的子类,过滤流使用节点流作为输入或者输出,对其包装的节点流进行特定的处理。直接使用节点流读写不方便,为了更快读写文件,才有了处理流。
4、编码表
①ASCII表(一个字符中的7位就可以表示):对应的字节都是正数 0-XXXXXXX;
②ISO-8859-1:拉丁码表latin,用一个字节中的8位表示,可表示整数和负数1-XXXXXXX;
③GBK:目前最常用的中文码表,用2个字节表示,约2万的中文和符号,2个字节的第一个字节开图是1,第二个字节的开头是0;
④Unicode:国际标准码表,用2个字节存储utf-8,基于Unicode,一个字节就可以存储数据,不要用两个字节存储,而且这个码表更加标准化,在每一个字节头加入了编码信息(API中可查找)。
二、常用IO流类
(一)InputStream——字节输入抽象类(各字节输入类的基类)
在这里插入图片描述
在这里插入图片描述
(1)节点流
FileInputStream:文件字节输入流(操作对象为File文件对象)
ByteArrayInputStream:字节数组输入流(操作对象为字节数组)
(2)处理流
FilterInputStream:过滤字节输入流(简单的实现了InputSteam类,一般用它的子类BufferedInputSteam、DataInputStream等)
BufferedInputStream:字节输入缓冲流
DataInputStream:基本数据类型输入处理流
ObjectInputStream:引用数据类型输入处理流(对象反序列化)
(二)OutputStream——字节输出抽象类(各字节输出类的基类)
在这里插入图片描述
在这里插入图片描述
(1)字节流
FileOutputStream:文件字节输出流(操作对象为File文件对象)
ByteArrayOutputStream:字节数组输出流(操作对象为字节数组)
(2)处理流
FilterOutputStream:过滤字节输出流(简单的实现了OutputStream类,一般用它的子类BufferedOutputSteam、DataOutputStream等)
BufferedOutputStream:字节输出缓冲流
DataOutputStream:基本数据类型输出处理流
ObjectOutputStream:引用数据类型输出处理流(对象序列化)
(三)Reader——字符输入抽象类(各字符输入类的基类)
在这里插入图片描述

//常用方法
 public int read() throws IOException {}//读取单个字符,返回作为整数读取的字符,如果已到达流的末尾返回-1
 public int read(char[] cbuf) throws IOException {}//将字符读入数组,返回读取的字符数
 public abstract int read(char[] cbuf, int off, int len) throws IOException {}//读取 len 个字符的数据,并从数组cbuf的off位置开始写入到这个数组中
 public abstract void close() throws IOException {}//关闭该流并释放与之关联的所有资源
 public long skip(long n) throws IOException {}//跳过n个字符。
 public int available()  //还可以有多少能读到的字节数

(1)节点流
FileReader:文件字符输入流(操作对象为File文件对象)
CharArrayReader:字符数组输入流(操作对象为字符数组)
(2)处理流
BufferedReader:字符输入缓冲流
InputStreamReader:字符输入格式处理流(可以设置字符编码等)
(四)Writer——字符输出抽象类(各字符输出类的基类)
在这里插入图片描述

 public void write(int c) throws IOException {} //写入单个字符
 public void write(char[] cbuf) throws IOException {} //写入字符数组
 public abstract void write(char[] cbuf, int off, int len) throws IOException {} //写入字符数组的某一部分
 public void write(String str) throws IOException {} //写入字符串
 public void write(String str, int off, int len) throws IOException {}//写字符串的某一部分
 public abstract void close() throws IOException {}  //关闭此流,但要先刷新它
 public abstract void flush() throws IOException {}  //刷新该流的缓冲,将缓冲的数据全写到目的地

(1)节点流
FileWriter:文件字符输出流(操作对象为File文件对象)
CharArrayWriter:字符数组输出流(操作对象为字符数组)
(2)处理流
BufferedWriter:字符输出缓冲流
OutputStreamWriter:字符输出格式处理流(可以设置字符编码等)

以FileReader、FileWriter为例:

//FileReader构造方法:
FileReader(File file) //在给定从中读取数据的 File 的情况下创建一个新 FileReader
FileReader(String fileName)// 在给定从中读取数据的文件名的情况下创建一个新 FileReader

//FileReader常用方法:
int read() //读取单个字符
int read(char[] cbuf) //将字符读入数组
int read(char[] cbuf,int off, int len)//将字符读入数组的某一部分
void close()//关闭该流并释放与之关联的所有资源。
//FileWriter构造方法:
FileWriter(File file)//根据给定的 File 对象构造一个 FileWriter 对象。
FileWriter(File file,boolean append)//根据给定的 File 对象构造一个 FileWriter 对象,写入的内容追加在上次写入内容后面。
FileWriter(String fileName)//根据给定的文件名构造一个 FileWriter 对象。
FileWriter(String fileName,boolean append)//根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。(追加)

//FileWriter常用方法:
void write(int c)//写入单个字符
void write(char[] cbuf,int off,int len)//写入字符数组的一部分
void writer(String str,int off,int len)//写入字符串的某一部分
void flush()//刷新该流的缓冲
void close()//关闭此流,但要先刷新它

三、关于序列化和反序列化
(1)序列化:是一种对象持久化的手段,是将对象转化为字节流的过程。
(2)反序列化:将字节流装换为对象的过程。
(3)序列化需要使用ObjectOutputStream,反序列化使用ObjectInputStream。
(4)要实现对象的序列化和反序列化需要类实现java.io.Serializable
(5)Transient关键字:作用是控制变量的序列化。序列化过程中在变量前加该关键字,可以阻止该变量参与序列化;反序列化过程中,Transient修饰变量的值被设置为初始值(例如int类型初始值是0, String对象类型初始值是null)。
(6)虚拟机是否允许反序列化,不仅取决于类路径的代码是否一致,还取决于两个类的序列化ID是否一致(private static final long serialVersionUID)
(7)如果是类的父类需要实现序列化和反序列化,则父类也需要实现Serializable接口。
(8)序列化和反序列化应用场景:在网络中进行数据传输时,对于敏感的信息不在网络中传输,需要使用对象序列化和反序列化中的关键字Transient。
(9)serialVersionUID(串行化版本统一标识符):用来表示类中不同版本的兼容性。有两种生成方式:①默认是1L;②根据类名、类路径、接口名、属性、方式生成的64位的哈希字段。
UID的默认值依赖于JAVA编译器,对于同一个类,不同的编译器UID可能不同。
显性定义UID的作用:①确保不同版本有不同的UID;②在类中新增或者修改属性不设置UID会抛出异常。
(10)writeObject、readObject
序列化过程中,如果被序列化的类中定义了writeObject和readObject方法,虚拟机会试图调用来类中的writeObject和readObject方法进行自定义序列化和反序列化。如果没有这个方法则默认调用ObjectOutputStream中的defaultWriteObject操作。反序列化过程则调用ObjectInputStream中的defaultWriteObject操作。
(11)ArrayList中存储数据的elementData属性添加Transient,为什么ArrayList还能进行序列化和反序列化?
ArrayList->writeObject->writeObject0
(12)在对象的序列化过程中,接口Serializable中并没有任何需要实现的方法,
抛出NotSerializableExecption异常是?
答:序列化和反序列化的实例必须是String、Array、Enum、Serializable的实例。
四、关于随机访问文件类RandomAccessFile
(1)构造函数

public RandomAccessFile(String name, String mode)
public RandomAccessFile(File file, String mode)

(2)模式
r:可读模式,该模式只可读取,不能写入,否则抛异常
rw:读写模式,该模式可读可写
rws:读写模式,将更新的内容和元数据更新到存储设备
rwd:读写模式,将更新的内容更新到存储设备
(3)常用方法

length() //返回此文件的长度。
getFilePointer() //返回此文件中的当前偏移量。
skipBytes(int) //尝试跳过输入的 n 个字节以丢弃跳过的字节。
seek(long) //设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。
read(byte[] b, int off, int len) //将最多 len 个数据字节从此文件读入 byte 数组。
write(byte[] b, int off, int len) //将 len 个字节从指定 byte 数组写入到此文件,并从偏移量 off 处开始。
writeUTF(String) //使用 modified UTF-8 编码以与机器无关的方式将一个字符串写入该文件。
writeBytes(String s) //按字节序列将该字符串写入该文件。
writeChars(String s) //按字符序列将一个字符串写入该文件。
writeBoolean(boolean v) //按单字节值将 boolean 写入该文件。
writeByte(int v) // 按单字节值将 byte 写入该文件。
writeChar(int v) //按双字节值将 char 写入该文件,先写高字节。
writeInt(int v) // 按四个字节将 int 写入该文件,先写高字节。

练习:使用RandomAccessFile像文件中指定位置插入数据。

import java.io.IOException;
import java.io.RandomAccessFile;

public class InsertBufferDemo {
    public static void addContent(String srcFile, int index, String append) {
        RandomAccessFile randomAccessFile = null;
        try {
            randomAccessFile = new RandomAccessFile(srcFile, "rw");
            randomAccessFile.seek(index);

            StringBuffer sb = new StringBuffer();
            byte[] b = new byte[100];
            int len;
            while ((len = randomAccessFile.read(b)) != -1) {
                sb.append(new String(b, 0, len));
            }
            randomAccessFile.seek(index);
            randomAccessFile.write(append.getBytes());
            randomAccessFile.write(sb.toString().getBytes());

        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            randomAccessFile.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {

        InsertBufferDemo ic = new InsertBufferDemo();
        ic.addContent("C:\\Users\\Administrator\\Desktop\\新建文本文档.txt", 3,"A");
    }
}

五、File类
用来操作文件,存在java.io目录下
1、构造函数
相对路径:不带盘符。cd . 表示当前目录。cd . . 表示当前目录的父目录。
绝对路径:带有盘符。例:C:\java\test\test1.txt
File(String pathname) 直接传入路径
File(String parent,String child) 传入父路径和子路径
File(File parent,String child) 传入file实例
File(URI uri) 远程链接
2、常用方法

boolean exists() //判断路径是否存在
String getAbsolutePath() //获取当前文件的绝对路径
boolean isFile() //判断实例是否是文件
boolean isDirectory() //判断实例是否是目录
boolean mkdir() //新创建目录
boolean createNewFile() throws IOException  //创建新文件(在文件夹不存在的情况下文件创建不成功)
boolean delete() //删除文件,立即执行删除操作
void deleteOnExit() //删除文件,在程序退出时才删除
String getName() //获取名字
String[] list() //获取目录下的所有文件
//获取指定的内容(注:实现FilenameFilter接口)
FilenameFilter filter = new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.startsWith("Java");
}
};
//获取文件目录,返回的是file类型的数组
File[] files = file.listFiles();
File[] files1 = file.listFiles(filter);

六、练习(运用IO流、HashMap、PriorityQueue等对文档中数据进行读取并统计出重复次数最多的五组数据)

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

public class IOTest {
    public static void main(String[] args) {
        File f = new File("C:\\Users\\Administrator\\Desktop\\上课\\JavaSE\\笔记\\readerFile.txt");
        //读取文件
        FileRead(f);
        //获取重复次数最多的五个数据
        getLastFive(f);
    }

    public static ArrayList FileRead(File f) {
        String path = f.getPath();
        ArrayList arrayList = new ArrayList();
        try {
            FileInputStream fileInputStream = new FileInputStream(path);
            InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
            BufferedReader bufferedReader= new BufferedReader(inputStreamReader);
            String s = bufferedReader.readLine();
            //将每行读取的数据存入s
            while(s!=null){
                String[] split = s.split(",");
                for(int i=0;i<split.length;i++){
                    arrayList.add(Integer.valueOf(split[i]));
                }
                s=bufferedReader.readLine();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return arrayList;
    }

    public static void getLastFive(File f) {
        ArrayList arrayList=FileRead(f);
        HashMap<Integer, Integer> hashMap = new HashMap<Integer, Integer>();
        Iterator<Integer> iterator = arrayList.iterator();
        while (iterator.hasNext()) {
            Integer value = iterator.next();
            if (hashMap.containsKey(value)) {
                hashMap.put(value, hashMap.get(value) + 1);
            } else {
                hashMap.put(value, 1);
            }
        }
        Comparator<Map.Entry<Integer, Integer>> comparator = new Comparator<Map.Entry<Integer, Integer>>() {
            @Override
            public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
                return o1.getValue() - o2.getValue();
            }
        };
        PriorityQueue<Map.Entry<Integer, Integer>> priorityQueue = new
                PriorityQueue<Map.Entry<Integer, Integer>>(5, comparator);
        Iterator<Map.Entry<Integer, Integer>> iterator1 = hashMap.entrySet().iterator();
        while (iterator1.hasNext()) {
            Map.Entry<Integer, Integer> entry = iterator1.next();
            if (priorityQueue.size() < 5) {
                priorityQueue.add(entry);
            } else {
                Map.Entry<Integer, Integer> entry1 = priorityQueue.peek();
                if (entry.getValue() > entry1.getValue()) {
                    //当前value值大于队列顶的元素
                    priorityQueue.poll();
                    priorityQueue.add(entry);
                }
            }
        }

        Iterator<Map.Entry<Integer, Integer>> iterator2 = priorityQueue.iterator();
        while (iterator2.hasNext()) {
            Map.Entry<Integer, Integer> entry = iterator2.next();
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值