JAVA文件基本操作与概念

news2025/1/17 8:53:37

文件的概念

狭义的文件:

存储在硬盘上的数据,以文件为单位,进行组织;文件夹也叫做"目录",也是一种特殊的文件(文件里存储的也是文件)

这章笔记的内容都是指狭义的文件

广义的文件:

操作系统负责管理软硬件资源,操作系统往往会把这些资源统一抽象成文件进行管理-----"一切皆文件"

比如,有一个网卡,就把这个网卡抽象成一个"文件",创建了特殊的文件来表示网卡;从网卡接收数据,就读取这个文件,往网卡发送数据,就写这个文件

再比如,有一个键盘,想从键盘种读取数据,也是将键盘抽象成一个"文件"(stdin),读这个文件就能读取到用户输入的内容了

绝对路径与相对路径

绝对路径是指目录下的绝对位置,直接到达目标位置,通常是从盘符开始的路径,完整的描述文件位置的路径就是绝对路径

路径之间使用\(反斜杠)分隔,当然/(斜杠)也可以,一般推荐使用/(斜杠)来分隔

相对路径首先需要一个"基准路径"(现在的位置),以基准路径为起点,往下继续走直到到达目标路径的表示方式

什么是缓冲区

我们知道 I/O 的速度是很慢的,所以,大多的 OutputStream 为了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写入设备中,这个区域一般称为缓冲区

缓冲区一般分为输入缓冲区和输出缓存区,输入缓冲区是输入设备与内存通信的缓冲区,输出缓冲区是内存与输出设备通信的缓冲区

但造成一个结果,就是我们写的数据,很可能会遗留一部分在缓冲区中。需要在最后或者合适的位置,调用 flush(刷新)操作,将数据刷到设备中

File类中的文件操作

文件操作是属于操作系统层面提供的一些API,不同的操作系统提供的API是不一样的,JAVA作为一个跨平台语言,为了统一代码,就在JVM中把不同系统的文件操作API进行了封装~~

构造File对象:

File 对象名 = new File("路径");

根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径

File类当中的常用方法:

修饰符及返回值类型方法名说明
StringgetParent()返回 File 对象的父目录路径
StringgetName()返回 FIle 对象的文件名(含后缀名)/目录名
StringgetPath()返回 File 对象的文件路径(构造对象时写的啥显示啥)
StringgetAbsolutePath()返回 File 对象的绝对路径
StringgetCanonicalPath()返回 File 对象的修饰过的绝对路径
booleanexists()判断 File 对象描述的文件是否真实存在
booleanisDirectory()判断 File 对象代表的文件是否是一个目录
booleanisFile()判断 File 对象代表的文件是否是一个普通文件
booleancreateNewFile()根据 File 对象,自动创建一个空文件。成功创建后返回 true
booleandelete()根据 File 对象,删除该文件。成功删除后返回 true
voiddeleteOnExit()进程退出时,根据 File 对象,删除该文件
String[]list()返回 File 对象代表的目录下的所有文件名
File[]listFiles()返回 File 对象代表的目录下的所有文件,以 File 对象表示
booleanmkdir()创建 File 对象代表的单层目录
booleanmkdirs()创建 File 对象代表的多层目录
booleanrenameTo(File dest)传递一个File对象,进行文件改名
booleancanRead()判断用户是否对文件有可读权限
booleancanWrite()判断用户是否对文件有可写权限

文本文件与二进制文件

数据文件被分为文本文件或者二进制文件

数据在内存中以二进制的形式存储,如果不加转换的输出到硬盘,就是二进制文件

如果要求在硬盘上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件

文件内容的读写操作

把硬盘上的数据往内存上面写就是输入

把内存上的数据往硬盘上面写就是输出

文件内容的读写也叫做"流"(stream),计算机中的流其实是一种信息的转换,把文件内容的读写操作比喻成水流,java标准库在"流"的概念上,提供了一组类,完成文件内容的读写操作~~

读写文件分为两种:一种是字节流(按字节读和写),一种是字符流(按字符读和写)

InputStream和OutputStream是字节流的,Reader和Writer是字符流的,Scanner和PrintWriter也是字符流的

打开文件以后一定要记得close()文件,不然会出现文件资源泄露的情况!!!

字节流InputStream:

读数据,把数据从硬盘读到内存中,InputStream 只是一个抽象类,要使用还需要具体的实现类,使用FileInputStream

修饰符及返回值类型方法名说明
intread()读取一个字节的数据,返回 -1 代表已经完全读完了
intread(byte[] b)把读到的内容放到字节数组b中,返回实际读到的字节数;返回 -1 代表以及读完了
intread(byte[] b, int off, int len)从字节数组b下标为off位置开始读len个字节,返回实际读到的字节数;返回 -1 代表以及读完了
voidclose()关闭字节流(关闭文件)

FileInputStream:

InputStream的具体实现类

方法名说明
FileInputStream(File file)利用 File 构造文件输入流(打开文件)
FileInputStream(String name)利用文件路径构造文件输入流(打开文件)
public class Test2 {
    public static void main(String[] args) throws IOException {
        //打开文件
        InputStream inputStream = new FileInputStream("bbb.txt");
        //读取文件内容
        while (true) {
            int b = inputStream.read();
            if (b == -1) {
                break;
            }
            System.out.println(b);
        }
        //关闭文件
        inputStream.close();
    }
}

字节流OutputStream:

写数据,把数据从内存写入到硬盘中,OutputStream只是一个抽象类,要使用还需要具体的实现类,使用FileOutputStream

使用OutputStream写文件的时候,只要打开文件成功,就会把文件原有内容清空~~如果文件不存在会自动创建

修饰符及返回值类型方法名说明
voidwrite(int b)写入一个字节的数据
voidwrite(byte[] b)把字节数组里的所有内容都写到文件中
intwrite(byte[] b, int off, int len)把b字节数组从下标off位置开始写,写len个字节
voidclose()关闭字节流(关闭文件),也有清空缓冲区的作用
voidflush()重要:我们知道 I/O 的速度是很慢的,所以,大多的 OutputStream 为了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写入设备中,这个区域一般称为缓冲区。但造成一个结果,就是我们写的数据,很可能会遗留一部分在缓冲区中。需要在最后或者合适的位置,调用 flush(刷新)操作,将数据刷到设备中。

FileOutputStream:

OutputStream的具体实现类

方法名说明
FileOutputStream(File file)利用 File 构造文件输出流(打开文件)
FileOutputStream(String name)利用文件路径构造文件输出流(打开文件)
public class Test1 {
    public static void main(String[] args) throws IOException {
        //打开文件
        OutputStream outputStream = new FileOutputStream("./bbb.txt");
        //OutputStream只要打开文件成功,就会把文件原有内容清空,如果文件不存在会自动创建
        outputStream.write(97);
        outputStream.write(98);
        outputStream.write(99);
        //关闭文件
        outputStream.close();
    }
}

字符流Reader:

读数据,把数据从硬盘读到内存中,Reader 只是一个抽象类,要使用还需要具体的实现类,使用FileReader

修饰符及返回值类型方法名说明
intread()读取一个字符的数据,返回 -1 代表已经完全读完了
intread(char[] b)把读到的内容放到字符数组b中,返回实际读到的字符数;返回 -1 代表以及读完了
intread(char[] b, int off, int len)从字符数组b下标为off位置开始读len个字符,返回实际读到的字符数;返回 -1 代表以及读完了
voidclose()关闭字符流(关闭文件)

字符流FileReader:

Reader的具体实现类

方法名说明
FileReader(File file)利用 File 构造文件输入流(打开文件)
FileReader(String name)利用文件路径构造文件输入流(打开文件)
public class Test2 {
    public static void main(String[] args) throws IOException {
        //打开文件
        Reader reader = new FileReader("./bbb.txt");
        //读取文件内容
        while (true) {
            int ret = reader.read();
            if (ret == -1) {
                break;
            }
            char ch = (char) ret;
            System.out.println(ch);
        }
        //关闭文件
        reader.close();
    }
}

Writer:

写数据,把数据从内存写入到硬盘中,Writer只是一个抽象类,要使用还需要具体的实现类,使用FileWriter

使用Writer写文件的时候,只要打开文件成功,就会把文件原有内容清空~~如果文件不存在会自动创建

修饰符及返回值类型方法名说明
voidwrite(int b)写入一个字符的数据
voidwrite(char[] b)把字符数组里的所有内容都写到文件中
voidwrite(String b)写入b字符串数据
intwrite(char[] b, int off, int len)把b字符数组从下标off位置开始写,写len个字符
intwrite(String b,int off,int len)把b字符串从下标off位置开始写,写len个字符
voidclose()关闭字符流(关闭文件),也有清空缓冲区的作用
voidflush()重要:我们知道 I/O 的速度是很慢的,所以,大多的 OutputStream 为了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写入设备中,这个区域一般称为缓冲区。但造成一个结果,就是我们写的数据,很可能会遗留一部分在缓冲区中。需要在最后或者合适的位置,调用 flush(刷新)操作,将数据刷到设备中。

FileWriter:

Writer的具体实现类

方法名说明
FileWriter(File file)利用 File 构造文件输出流(打开文件)
FileWriter(String name)利用文件路径构造文件输出流(打开文件)
public class Test3 {
    public static void main(String[] args) throws IOException {
        //打开文件
        Writer writer = new FileWriter("./bbb.txt");
        //Writer只要打开文件成功,就会把文件原有内容清空,如果文件不存在会自动创建
        writer.write("hello world");
        //关闭文件
        writer.close();
    }
}

Scanner:

使用字符流进行读操作的时候,还可以使用Scanner来进行读取~~

public class Test4 {
    public static void main(String[] args) throws IOException {
        //打开文件
        InputStream inputStream = new FileInputStream("./bbb.txt");
        //使用Scanner作为一个字符流对象(传递字节流对象)
        Scanner scanner = new Scanner(inputStream);
        while (scanner.hasNext()) {
            System.out.println(scanner.next());
        }
        //关闭文件
        inputStream.close();
    }
}

PrintWriter:

使用字符流进行写操作的时候,还可以使用PrintWriter来进行写操作~~

public class Test5 {
    public static void main(String[] args) throws IOException {
        //打开文件
        OutputStream outputStream = new FileOutputStream("./bbb.txt");
        //使用PrintWriter作为一个字符流对象(传递字节流对象)
        PrintWriter writer = new PrintWriter(outputStream);
        writer.printf("a = %d\n",10);
        writer.println();
        writer.print("abc");
        //关闭文件
        outputStream.close();
    }
}

所有代码都需要考虑close是否一定能被执行的问题:

public class Test6 {
    public static void main(String[] args) throws IOException {
        OutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream("./bbb.txt");
            PrintWriter writer = new PrintWriter(outputStream);
            writer.printf("a = %d\n",10);
            writer.println();
            writer.print("hello world");
        }finally {
            outputStream.close();
        }
    }
}
​
-----------------------------------------------------------------------------------------
​
public class Test6 {
    public static void main(String[] args) throws IOException {
        try(OutputStream outputStream = new FileOutputStream("./bbb.txt")) {
            PrintWriter writer = new PrintWriter(outputStream);
            writer.printf("a = %d\n",10);
            writer.println();
            writer.print("hello world");
        }
    }
}

文件操作的一些实例

一、扫描指定目录,并找到名称中包含指定字符的所有普通文件(不包含目录),并且后续询问用户是否要删除该文件~~

操作:

1、先让用户输入要扫描的路径+要查找的词

2、遍历目录,找到名字匹配的文件

3、询问用户是否删除

public class Test7 {
    public static void main(String[] args) throws IOException {
        //从键盘输入目录路径
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要扫描的路径: ");
        File rootDir = new File(scanner.next());
        //判断目录路径是否存在
        if (!rootDir.isDirectory()) {
            System.out.println("您输入的目录不存在");
            return;
        }
        //从键盘输入关键词
        System.out.println("请输入要搜索的关键词: ");
        String toDelete = scanner.next();
        //遍历目录
        scanDir(rootDir,toDelete);
    }
​
    //借助这个方法进行递归遍历
    public static void scanDir(File rootDir, String toDelete) throws IOException {
        File[] files = rootDir.listFiles();
        if (files == null) {
            //说明rootDir是一个空的目录
            return;
        }
        //rootDir非空,循环遍历每个元素
        for (File f : files) {
            //当前rootDir是目录
            if (f.isDirectory()) {
                //递归里面的内容
                scanDir(f,toDelete);
            }else {
                //不是目录,是普通文件,判定文件名是否符合要求,是否要进行删除
                checkDelete(f,toDelete);
            }
        }
    }
​
    //删除操作
    public static void checkDelete(File f, String toDelete) throws IOException {
        if (f.getName().contains(toDelete)) {
            System.out.println("该单词" + toDelete + "被" + 
                    f.getCanonicalPath() + "包含了" + ",是否要删除? (Y/N)");
            Scanner scanner = new Scanner(System.in);
            String choice = scanner.next();
            if (choice.equals("Y") || choice.equals("y")) {
                f.delete();
            }
        }
    }
}

二、普通文件的复制

操作:把第一个文件打开,把里面的内容逐个字节的读取出来,写入到第二个文件中即可~~

public class Test8 {
    public static void main(String[] args) throws IOException {
        //1.先输入要复制哪个文件(源文件),以及把这个文件复制到哪里去(目标文件)~~
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入源文件: ");
        //srcFile 形如 d:/cat.jpg
        File srcFile = new File(scanner.next());
        System.out.println("请输入目标文件: ");
        //destFile 形如 d:/cat2.jpg
        File destFile = new File(scanner.next());
        if (!srcFile.isFile()) {
            System.out.println("输入的源文件有误");
            return;
        }
        if (!destFile.getParentFile().isDirectory()) {
            System.out.println("输入的目标文件有误");
            return;
        }
        //2.打开源文件,按照字节读取内容,再依次写入到目标文件
        try (InputStream inputStream = new FileInputStream(srcFile);
        OutputStream outputStream = new FileOutputStream(destFile)){
            //读src的每个字节,写入到dest中
            while (true) {
                int ret = inputStream.read();
                if (ret == -1) {
                    break;
                }
                outputStream.write(ret);
            }
        }
    }
}

三、扫描指定目录,并找到名称或者内容中包含指定字符的所有普通文件(不包含目录)

操作:

1、先让用户输入要扫描的路径+要查找的词

2、遍历目录,找到文件名匹配与内容匹配的文件

public class Test9 {
    public static void main(String[] args) throws IOException {
        //1.输入路径和要查询的关键词
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要扫描的路径: ");
        File rootDir = new File(scanner.next());
        System.out.println("请输入要查询的词: ");
        String toFind = scanner.next();
        //2.递归的扫描目录
        scanDir(rootDir,toFind);
    }
​
    public static void scanDir(File rootDir, String toFind) throws IOException {
        File[] files = rootDir.listFiles();
        if (files == null) {
            return;
        }
        for (File f : files) {
            if (f.isDirectory()) {
                scanDir(f,toFind);
            }else {
                checkFile(f,toFind);
            }
        }
    }
​
    public static void checkFile(File f, String toFind) throws IOException {
        //1.先检查文件名
        if (f.getName().contains(toFind)) {
            System.out.println(f.getCanonicalPath() + " 文件名中包含 " + toFind);
        }
        //2.再检查文件内容
        try (InputStream inputStream = new FileInputStream(f)){
            StringBuilder stringBuilder = new StringBuilder();
            Scanner scanner = new Scanner(inputStream);
            while (scanner.hasNextLine()) {
                stringBuilder.append(scanner.nextLine() + "\n");
            }
            if (stringBuilder.indexOf(toFind) > -1) {
                System.out.println(f.getCanonicalPath() + " 文件内容包含 " + toFind);
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/93617.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker安装emqx详解(配置SSL证书、开启WSS、鉴权)

EMQX 是一款大规模可弹性伸缩的云原生分布式物联网 MQTT 消息服务器。 1 端口介绍 1883:MQTT 协议端口8084:MQTT/SSL 端口8083:MQTT/WebSocket 端口8080:HTTP API 端口18083:Dashboard 管理控制台端口 2 拉取镜像 …

视频文件转M3U8

前言 前段时间遇到一个播放视频的项目,为了防止登录的用户下载项目的视频,所以需要对视频加密,即使用户下载也不能播放;因为前端采用videojs,最后确认方案是将mp4转m3u8文件格式,来实现视频文件加密播放。下…

公共用房管理系统有哪些管理功能?

数图互通房产管理 数图互通公共用房管理系统的管理功能范围包括: 1、对全部公房进行图形化、电子化、规范、动态化管理。 2、房屋数据定义:可对校区、片区、建筑物、楼层、房间数据进行增删改查,对房间属性数据进行批量修改。 3、档案及多类型附件管理:可对房产的…

对antd-vue输入框的二次封装,显示长度限制,兼容v-decorator和v-model

背景&#xff1a;antd组件中输入框长度限制没有显示&#xff0c;不能像elementUI一样&#xff0c;所以自己来封装实现 目的&#xff1a;对antd-vue输入框的二次封装&#xff0c;显示长度限制&#xff0c;兼容v-decorator和v-model 效果图&#xff1a; 代码&#xff1a; <…

JAVA方向程序设计PTA期末考试小测试

目录 1.方法重载 2.实例成员与类成员 3.static类成员 4.对象的组合 5. 对象的先上转型 6.引用类型&#xff08;数组&#xff09;参数传递 7.三角形类 8.机动车类补全代码 9.数组的引用与元素 10.求最大值 11.接口回调 12*.接口实现-Comparable 13.集体评分 14. 动…

@Windows server 2022安装使用(Workstation)

文章目录1.windows [iso下载](https://www.microsoft.com/zh-cn/evalcenter/evaluate-windows-server-2022)2.准备[workstation](https://www.vmware.com/products/workstation-pro/workstation-pro-evaluation.html)&#xff08;个人测试&#xff09;3.安装windows server4.wi…

QT 使用第三方库QtXlsx操作Excel表

一直以来&#xff0c;都想学习一下C/C如何操作excel表&#xff0c;在网上调研了一下&#xff0c;觉得使用C/C去操作很麻烦&#xff0c;遂转向QT这边&#xff1b;QT有一个自带的类QAxObject&#xff0c;可以使用他去操作&#xff0c;但随着了解的深入&#xff0c;觉得他并不是很…

打造企业数智化管理新引擎,中国首份指标中台市场研究报告重磅发布!

12月15日&#xff0c;中国首份指标中台市场研究报告正式对外发布。该报告由专注数字化市场的研究咨询机构爱分析联合指标中台代表厂商 Kyligence 共同打造&#xff0c;内容聚焦指标管理和数据分析痛点&#xff0c;全面地梳理了指标中台概念、价值和应用落地方法论&#xff0c;并…

如何快乐地自学Python?阿里讲师用“四点”,说透快乐学习的方法

前言 由于我是自学Python&#xff0c;非科班出身&#xff0c;所以只能分享一些关于我的学习心得&#xff0c;如果有不对地方欢迎指正。 不过非科班出身虽然是一个痛点&#xff0c;但是在工作上&#xff0c;我其实不输给我其他同事&#xff0c;这点我倒是很有自信&#xff0c;…

活用 F12 开发者工具,测试效率原来可以提高这么多

推荐阅读&#xff1a; [内部资源] 想拿年薪30W的软件测试人员&#xff0c;这份资料必须领取~ Python自动化测试全栈性能测试全栈&#xff0c;挑战年薪40W 从功能测试进阶自动化测试&#xff0c;熬夜7天整理出这一份超全学习指南【附网盘资源】 什么是F12? F12开发者工具是…

HTTP详细介绍

HTTP 内容协商 什么是内容协商 在 HTTP 中&#xff0c;内容协商是一种用于在同一 URL 上提供资源的不同表示形式的机制。内容协商机制是指客户端和服务器端就响应的资源内容进行交涉&#xff0c;然后提供给客户端最为适合的资源。内容协商会以响应资源的语言、字符集、编码方…

FS32R294JCK0MJDT功能、FS32R294KCK0MJDT特点、FS32R294KAK0MJDT雷达微控制器

S32R294的特点与优势&#xff1a;内置雷达信号加速单元&#xff0c;简称SPT2.8&#xff0c;是专门服务于FMCW雷达的信号处理加速单元。同时&#xff0c;它是16纳米Power架构的处理器&#xff0c;与上一代处理器有非常好的软件兼容性&#xff0c;软件复用率高达80%&#xff1b;S…

【愚公系列】2022年12月 使用NSSM工具部署ELK三件套为Windows服务

文章目录前言一、使用NSSM工具部署ELK三件套为Windows服务1.安装ElasticSearch服务2.安装Kibana服务3.安装Logstash服务4.验证ELK服务前言 nssm是一个服务封装程序&#xff0c;它可以将普通exe程序封装成服务&#xff0c;实现开机自启动&#xff0c;同类型的工具还有微软自己的…

计算机硬件基础

目录 一、计算机组成原理 1.计算机的组成 输入设备&#xff1a; 输出设备&#xff1a; 存储器&#xff1a; 运算器&#xff1a; 控制器&#xff1a; 2.总线 总线 DMA总线 二、多级存储 1.三级存储结构 Cache 主存储器 辅助存储器 2.地址空间 三、CPU工作原理概述…

Java培训Mycat全局序列

全局序列 1、本地文件方式 不推荐&#xff0c;如在Mycat主机中用本地文件方式创建全局序列&#xff0c;当这台机器宕机时会出现&#xff0c;序列文件丢失&#xff0c;造成序列冲突问题 Java培训Mycat全局序列 2、数据库方式 2.1、原理 利用数据库一个表 来进行计数累加。…

干货 | 数字经济创新创业——软件研究

下文整理自清华大学大数据能力提升项目能力提升模块课程“Innovation & Entrepreneurship for Digital Economy”&#xff08;数字经济创新创业课程)的精彩内容。主讲嘉宾&#xff1a;Kris Singh: CEO at SRII, Palo Alto, CaliforniaVisiting Professor of Tsinghua Unive…

计算机毕设Python+Vue校园食堂订餐系统(程序+LW+部署)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【IntelliJ IDEA技巧】:如何生成.jar文件

问题描述&#xff1a; 由于上交给上级或者特殊使用&#xff0c;我们需要将jar文件提交给上级&#xff0c;那就是要学会如何生成jar文件&#xff0c;个人找了很久解决了问题&#xff0c;主要是网上太多参差不齐的回答&#xff0c;我觉着很浪费时间&#xff0c;当然有些也是比较好…

MySQL zip安装包 的安装过程

以前怎么安装的Mysql已经不记得了&#xff0c;感觉就是傻瓜式安装。这次又要用上了&#xff0c;发现和原先的记忆完全不一样了&#xff0c;也许是自己全忘了。这次记在这里&#xff0c;日后好参照&#xff0c;有需要的同学也可直接拿去。 1.下载&#xff0c;直接去官网吧 MyS…

人乳铁蛋白ELISA试剂盒操作注意事项及步骤丨艾美捷方案

人乳铁蛋白(LTF)ELISA试剂盒操作注意事项&#xff1a; 1.试剂应按标签说明书储存&#xff0c;使用前恢复到室温。稀稀过后的标准品应丢弃&#xff0c;不可保存。 2.实验中不用的板条应立即放回包装袋中&#xff0c;密封保存&#xff0c;以免变质。 3.不用的其它试剂应包装好…