• 【Java】一文认识IO操作流


    快速上手IO流

    一、什么是文件?

    这个我想大家都知道,ppt啊,world文件,都是文件

    二、什么是文件流

    文件是在程序中已流的形式来操作的

    实在不行你们就理解为下面的 (杯子是文件)(水是数据)

    水到胃就是输入流,往肚子里面输,

    胃到水就是输出流,往肚子外吐。

    三、常用的文件操作

    1.创建文件

    方式一

    1. public static void main(String[] args) throws IOException {
    2. //方式1
    3. String filePath = "e:\\news1.txt"; //声明存放的地方,和文件名
    4. File file = new File(filePath); //把信息放出来
    5. file.createNewFile(); //创建文件
    6. System.out.println("创建成功");
    7. }

    方式二 (根据父目录(就是存放路径)+子路径(就是文件名))

    1. public static void main(String[] args) throws IOException {
    2. File filePath = new File("E:\\test"); //存放路径
    3. String fileName = "news2.txt"; //文件名称
    4. File file = new File(filePath,fileName);
    5. file.createNewFile();
    6. System.out.println("创建成功");
    7. }

    有人在想为什么有第一个File对象 ,下面还有一个?

    其实在计算机,如果有File对象,只是在内存中有这么一个对象,但是在硬盘里面还没有,我们需要createNewFile()这个操作,把这个对象放进去硬盘。

    相当于:孩子妈肚子里有孩子,但是没有出来,需要createNewFile(),才可以出来。

    方式三

    1. public static void main(String[] args) throws IOException {
    2. String filePath = "E:\\test"; //存放路径
    3. String fileName = "news3.txt"; //文件名称
    4. File file = new File(filePath,fileName);
    5. file.createNewFile();
    6. System.out.println("创建成功");
    7. }

    也是上面差不多,只不过上面的是File 对象,加String

    这个是2个String

    要注意存放路径 \\ ,也可以使用一个/

    2.获取文件的相关信息

    1. public static void main(String[] args) {
    2. String filePath = "e:\\news1.txt";
    3. File file = new File(filePath);
    4. System.out.println("得到文件名"+file.getName());
    5. System.out.println("得到文件绝对路径"+file.getAbsolutePath());
    6. System.out.println("得到文件父级目录"+file.getParent());
    7. System.out.println("得到文件大小(按字节)"+file.length()); //utf-8 一个英文1个字节1个汉字3个字节
    8. System.out.println("文件是否存在"+file.exists());
    9. System.out.println("是不是一个文件"+file.isFile());
    10. System.out.println("是不是一个目录"+file.isDirectory());
    11. }

    输出

    3.目录的创建和文件删除

    判断e:\news1.txt文件是否存在,存在就删除

    delete方法返回的是布尔值

    1. public static void m1(){
    2. String filePath = "e:\\news1.txt";
    3. File file = new File(filePath);
    4. if (file.exists()){
    5. if (file.delete()){
    6. System.out.println("删除成功");
    7. }else{
    8. System.out.println("删除失败");
    9. }
    10. }else{
    11. System.out.println("文件不存在");
    12. }
    13. }

    需要注意java中目录也是一个特殊的文件 也可以进行操作

    1. public static void m2(){
    2. String filePath = "E:\\del"; //这里是目录
    3. File file = new File(filePath);
    4. if (file.exists()){
    5. if (file.delete()){
    6. System.out.println("删除成功");
    7. }else{
    8. System.out.println("删除失败");
    9. }
    10. }else{
    11. System.out.println("目录不存在");
    12. }
    13. }

    需注意:目录里面有文件 delete删除不了

    判断目录是否存在,没有就创建

    需注意mkdirs()是创建多级目录,创建一级目录(就是一个文件夹)使用mkdir(),不正确使用会报错

    1. public static void m3(){
    2. String DirectoryPath = "E:\\del\\a\\b\\c";
    3. File file = new File(DirectoryPath);
    4. if (file.exists()){
    5. System.out.println("目录存在");
    6. }else{
    7. if (file.mkdirs()){
    8. System.out.println("该目录创建成功");
    9. }else{
    10. System.out.println("创建失败");
    11. }
    12. }
    13. }

    四、IO流原理及流的分类

    1.流的分类和原理:

    1)按照数据单位不同分为:

    字节流(8 bit),字符流

    注意字符流并不可以确定是多大单位,因为是要看编码格式的,

    它们的效率谁好,那肯定字符流,因为字节流读取单位小,

    应用场景:

    那为什么要字节流,字节流可以操作二进制文件,比如音乐,视频,可以进行无损操作。

    字符流用来操作文本文件这样的比较好。

    2)按照数据流的流向分为:

    输入流

    输出流

    3)按照流的角色不同分为:

    节点流,处理流/包装流

    字节流和字符流分别对应两种流

    字节流的两大类:字节输入流,字节输出流

    它们2个的顶级父类,分别是InputSream 和OutputStream 都是抽象类

    使用的时候要实现它们的子类才可以

    字符流的两大类:字符输入流,字符输出流

    它们2个的顶级父类,分别是Reader 和Writer 都是抽象类

    使用的时候要实现它们的子类才可以

    Java的IO有40多个类,实际上非常规则,都是从上面4个抽象类派生出来的

    由这四个类派生出来的子类名称都是以其父类名当子类名后缀。

    IO流体系图:

    文件 vs 流:

    我们通过画图来看清楚流到底是什么:

    物品(数据) 通过外卖小哥(流) 来传达到用户(程序)手上

    反之一样

    2.常用的类

    2.1 字节流的常用流

    1. FileInputStream:文件输入流
    2. BufferedInputStream:缓冲字节输入流
    3. ObjectInputStream:对象字节输入流

    来看看关系,发现BufferedInputStream的父类其实是FilterInputStream,但是这个父类也是InputStream的子类

    2.1.1 FileInputStream常用类

    构造方法:

    那些参数是什么意思呢,其实我们看第一个就比较形象了,File对象是个文件(这里当物品/东西),FileInputStream 是外卖小哥,小哥拿着物品去送出去,物品和小哥之间有一定的联系。

    开始操作:

    使用read()无参数构造方法,读取完毕返回-1

    1. public static void readFile01(){
    2. String filepath = "E:\\test\\hello.txt";
    3. FileInputStream fileInputStream = null; //如果定义在try里面 finally使用不了
    4. int readDate = 0;
    5. try {
    6. //创建FileInputStream对象用于读取文件
    7. fileInputStream = new FileInputStream(filepath);
    8. //read() 返回-1代表读取完毕
    9. while((readDate = fileInputStream.read()) != -1){
    10. //为什么要循环因为读取的内容可能不是一次
    11. System.out.print((char)readDate);
    12. }
    13. } catch (IOException e) {
    14. e.printStackTrace();
    15. }finally {
    16. //关闭流 流是一种资源,不关闭会造成浪费
    17. try {
    18. fileInputStream.close();
    19. } catch (IOException e) {
    20. e.printStackTrace();
    21. }
    22. }
    23. }

    使用read无参构造方法,其实还是有不好的单个效率太低,我们可以使用read的其他构造参数。

    使用read()字符数组构造方法,读取完毕返回-1,未结束反复字符数组的长度,

    1. public static void readFile02(){
    2. //字节数组
    3. byte[] buf = new byte[8];//一次读8个字节
    4. int readDate = 0; //接收字符的长度
    5. String filepath = "E:\\test\\hello.txt";
    6. FileInputStream fileInputStream = null; //如果定义在try里面 finally使用不了
    7. try {
    8. //创建FileInputStream对象用于读取文件
    9. fileInputStream = new FileInputStream(filepath);
    10. //read() 返回-1代表读取完毕
    11. while((readDate = fileInputStream.read(buf)) != -1){
    12. //为什么要循环因为读取的内容可能不是一次
    13. System.out.print(new String(buf,0,readDate));//
    14. }
    15. } catch (IOException e) {
    16. e.printStackTrace();
    17. }finally {
    18. //关闭流 流是一种资源,不关闭会造成浪费
    19. try {
    20. fileInputStream.close();
    21. } catch (IOException e) {
    22. e.printStackTrace();
    23. }
    24. }
    25. }

    2.1.2 FileOutputStream常用类

    构造方法:

    类图:

    题目:

     
            
    1. public static void writerFile(){
    2. //创建一个FileOutPutStream
    3. String filePath = "E:\\test\\a.txt";
    4. FileOutputStream fileOutputStream = null;
    5. try {
    6. //得到FileOutputStream对象
    7. fileOutputStream = new FileOutputStream(filePath);
    8. //写入一个字节
    9. //fileOutputStream.write('a');
    10. //写入一个字符串
    11. String str = "hello,world";
    12. fileOutputStream.write(str.getBytes());
    13. // String的方法,把字符串转为字符数组,write() 会覆盖
    14. System.out.println("写入成功");
    15. } catch (IOException e) {
    16. e.printStackTrace();
    17. }finally {
    18. try {
    19. fileOutputStream.close();
    20. } catch (IOException e) {
    21. e.printStackTrace();
    22. }
    23. }
    24. }

    Write ()会覆盖,如果不想覆盖就,第二个参数变成true,追加到文字后。

    2.1.3 使用字节输入输入出流拷贝一个文件

    1. public static void main(String[] args) {
    2. //src 原目标文件 dest 拷贝到什么位置
    3. String srcfilePath = "C:\\Users\\Administrator\\Pictures\\Saved Pictures\\QQ图片20210806104237.jpg";
    4. String destfilePath = "D:\\A1\\QQ.jpg";
    5. FileInputStream fileInputStream = null;
    6. FileOutputStream fileOutputStream = null;
    7. try {
    8. fileInputStream = new FileInputStream(srcfilePath); //先图片输入到程序
    9. fileOutputStream = new FileOutputStream(destfilePath); //在从程序输出到文件夹
    10. //定义字节数组提高效率
    11. byte [] buf = new byte[1024];
    12. int readLen = 0;
    13. while ((readLen = fileInputStream.read(buf))!= -1){
    14. //读取到程序就由程序写出去 通过fileOutputStream
    15. //边读边写
    16. fileOutputStream.write(buf,0,readLen);
    17. //一定使用这个方法 带这些参数 为什么呢?因为怕其他的冗余数据进去 破坏文件 1039个字节,一次1024 还有剩余可能会有问题
    18. }
    19. System.out.println("拷贝OK");
    20. } catch (IOException e) {
    21. e.printStackTrace();
    22. }finally {
    23. //关闭输入输出流
    24. if(fileInputStream != null){
    25. try {
    26. fileInputStream.close();
    27. } catch (IOException e) {
    28. e.printStackTrace();
    29. }
    30. }
    31. if(fileOutputStream != null){
    32. try {
    33. fileOutputStream.close();
    34. } catch (IOException e) {
    35. e.printStackTrace();
    36. }
    37. }
    38. }
    39. }

    2.2 字符流的常用流

    1. FileReader:

    类图:

    1. FileWriter:z

    类图:

    2.2.1 FileReader常用类

    1. public static void main(String[] args) {
    2. String filePath = "E:\\test\\story.txt";
    3. //1.创建一个对象
    4. FileReader fileReader = null;
    5. int date = 0;
    6. try {
    7. fileReader = new FileReader(filePath);
    8. while((date = fileReader.read())!=-1){
    9. System.out.print((char) date);
    10. }
    11. } catch (IOException e) {
    12. e.printStackTrace();
    13. }finally {
    14. try {
    15. fileReader.close();
    16. } catch (IOException e) {
    17. e.printStackTrace();
    18. }
    19. }
    20. }

    使用字符数组来

    1. public static void main(String[] args) {
    2. String filePath = "E:\\test\\story.txt";
    3. //1.创建一个对象
    4. FileReader fileReader = null;
    5. int readLen = 0;
    6. char [] buf = new char[1024];
    7. try {
    8. fileReader = new FileReader(filePath);
    9. //循环读取 使用read(buf) ,返回实际读取到的字符数,返回-1 文件结束
    10. while((readLen = fileReader.read(buf))!=-1){
    11. System.out.print(new String(buf,0,readLen));
    12. }
    13. } catch (IOException e) {
    14. e.printStackTrace();
    15. }finally {
    16. try {
    17. fileReader.close();
    18. } catch (IOException e) {
    19. e.printStackTrace();
    20. }
    21. }
    22. }

    new String(buf,0,readLen) 从什么数组,从几下标开始,取多少个

    2.2.2 FileWriter常用类

    1. public static void main(String[] args) {
    2. String FilePath = "E:\\test\\a.txt";
    3. FileWriter fileWriter = null;
    4. char [] chars = {
    5. 'y','y'};
    6. try {
    7. fileWriter = new FileWriter(FilePath);
    8. //写入单个字符
    9. fileWriter.write('H');
    10. //写入指定的数组
    11. fileWriter.write(chars);
    12. //写入数组的指定部分
    13. fileWriter.write("Blog,666".toCharArray(),0,4);
    14. //写入整个字符串
    15. fileWriter.write("北京你好");
    16. //写入字符串指定的指定部分
    17. fileWriter.write("上海天津",0,2);
    18. } catch (IOException e) {
    19. e.printStackTrace();
    20. }finally {
    21. try {
    22. fileWriter.close();
    23. //对应FileWriter ,一定要关闭流,或者flush才可以真正的把数据写进去
    24. } catch (IOException e) {
    25. e.printStackTrace();
    26. }
    27. }
    28. }

    注意一定要使用close()或者flush()方法,不然数据不会成功写入。

    这篇文章就不讲为什么,有兴趣的可以自己去那个方法的底层看看或者看看别人的博客。

    3.节点流,处理流

     

    节点流:可以简单说是直接与数据源进行操作,是什么类型的文件就使用支持的节点流(上面有分类)

    但是我们现在要对数组进行操作,我们还得换一个节点流。一点不灵活

    但是我们现在想让文件操作功能变得强大一点就使用包装流类,也就是上面说的处理流,可以即对文件类型操作,也可以对数组源来操作, 我们使用BufferedReader 和 BufferedWriter

    那么为什么他们可以这么灵活呢,我们去看看源码

    BufferedReader 的源码里面就有个属性Reader, 这个Reader的子类有那些节点流子类,那么就说我们以后可以直接使用Reader的任意子类。

    Reder的子类有多少呢,我们来看一部分

    BufferedWriter也是一样的,里面有个属性Writer

    类图:Writer的子类

    所以这就是BufferedReader 和 BufferedWriter的强大的地方

    3.1节点流和处理流的区别和联系

    节点流很底层的~~直接和数据打交道

    3.2 处理流-BufferedReader 和 BufferedWriter

    3.2.2 BufferedReader

    看看关系先

    关闭的时候,其实会自己去关闭他的包装的节点流

    操作案列~~

    代码:

    1. public static void main(String[] args) throws Exception {
    2. //要操作的文件路径
    3. String pathFile = "E:\\test\\j.txt";
    4. //创建BuffeReader
    5. BufferedReader bufferedReader = new BufferedReader(new FileReader(pathFile));
    6. //读取
    7. String line;
    8. //按行读取,效率高
    9. //1.bufferedReader.readLine() 按行读取 返回空 读取完毕
    10. while((line = bufferedReader.readLine())!=null){
    11. System.out.println(line);
    12. }
    13. //关闭流 只需要关闭外层流(BufferedReader) 会自己关闭FileReader的
    14. bufferedReader.close();
    15. }

    我们来看看为什么直接关闭外层流,其实他底层是关闭的是那个参数的close();

    可以看出来这个in就是你使用的那个对象的节点流.

    3.2.3 BufferedWriter

    代码:

    1. public static void main(String[] args) throws IOException {
    2. String filePath = "E:\\test\\a.txt";
    3. //创建一个BufferedWriter
    4. BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath));
    5. bufferedWriter.write("哈哈哈写进文件1");
    6. bufferedWriter.newLine(); //插入一个和系统相关的换行符
    7. bufferedWriter.write("哈哈哈写进文件2");
    8. bufferedWriter.newLine(); //插入一个和系统相关的换行符
    9. bufferedWriter.write("哈哈哈写进文件3");
    10. //插入一个换行
    11. //关闭外层流即可
    12. bufferedWriter.close();
    13. }

    newLine() 插入一个和系统相关的换行符,没有这个不会换行

    如果我们要追加,不可以到bufferedWriter加true,因为不支持

    但是我们可以到

    这个后面加true

    3.2.4BufferedReader 和 BufferedWriter 完成文本拷贝

    1. public static void main(String[] args) throws IOException {
    2. String srcFilePath ="E:\\test\\j.txt";
    3. String descFilePath = "E:\\test\\T2\\j1.txt";
    4. String ScrLine ;
    5. // 把源文件写到程序里面
    6. BufferedReader bufferedReader = new BufferedReader(new FileReader(srcFilePath));
    7. // 把程序的源文件写到硬盘中
    8. BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(descFilePath));
    9. while((ScrLine = bufferedReader.readLine())!= null){
    10. //读取一行就写进去 没有带换行符
    11. bufferedWriter .write(ScrLine);
    12. //换行
    13. bufferedWriter.newLine();
    14. }
    15. //关闭流
    16. bufferedReader.close();
    17. bufferedWriter.close();
    18. }

    这里建议try finally 这样保证关闭资源,不过我这里就简单搞搞,知道大概意思就可以了。

    3.3 处理流-BufferedInputStream 和 BufferedOutputStream

    BufferedInputStream

    看看BufferedInputStream 的类图:

    来看看他们的属性参数:

    父类的属性in 类型是一个inputStream 那么就是说只要是inputStream的子类节点流都可以操作。

    BufferedOutputStream

    BufferedOutputStream的类图

    本类的buf是缓冲区 进行了优化,父类也有out 也是outPutStreamread 类型,子类的字节流操作都可以使用

    3.3.4 使用BufferedInputStream 和 BufferedOutputStream拷贝文件

    1. public static void main(String[] args) {
    2. String srcFilePath = "E:\\test\\QQ1.jpg";
    3. String DescFilePath = "E:\\test\\T2\\QQ2.jpg";
    4. //创建BufferedInputStream和BufferedInputStream对象
    5. BufferedInputStream bis = null;
    6. BufferedOutputStream bos = null;
    7. try {
    8. //为什么使用这个 因为我们要操作的不是一个文本,
    9. // 我们最好使用字节流来操作,无损,所以使用这个字节流,而且是InputStream的子类
    10. bis = new BufferedInputStream(new FileInputStream(srcFilePath));
    11. bos = new BufferedOutputStream(new FileOutputStream(DescFilePath));
    12. //循环读取文件 ,并写入到DescFilePath
    13. byte [] buf = new byte[1024];
    14. int readlen =0;
    15. //read() 没有文件返回-1
    16. while((readlen = bis.read(buf))!= -1){
    17. bos.write(buf,0,readlen); //写
    18. }
    19. } catch (IOException e) {
    20. e.printStackTrace();
    21. }
    22. finally {
    23. //关闭流
    24. if (bis!=null){
    25. try {
    26. bis.close();
    27. } catch (IOException e) {
    28. e.printStackTrace();
    29. }
    30. }
    31. if (bos!=null){
    32. try {
    33. bos.close();
    34. } catch (IOException e) {
    35. e.printStackTrace();
    36. }
    37. }
    38. }
    39. }

  • 相关阅读:
    bus使用清除keepalive缓存
    sql更新语句的执行流程
    数据治理的核心是什么?_光点科技
    Unity SKFramework框架(二十三)、MiniMap 小地图工具
    Day8、9、10、11 计算机网络——数据链路层
    WPF 控件小技巧记录(持续更新)
    setup中使用watch
    BOM操作——window对象(一)
    tensorflow 1.3.1 安装及报错解决
    UG\NX二次开发 获取装配部件的相关信息UF_ASSEM_ask_component_data
  • 原文地址:https://blog.csdn.net/guanshengg/article/details/126540440