File、方法递归、IO流

File、方法递归、IO流,第1张

1、目前是怎么样存储数据的?弊端是什么?
int a = 10;
int [] arr = {1,2,3,4,5};
List list = new ArrayList<>();
在内存中存储的数据是用来处理、修改、运算的,不能长久保存。
2、计算机中,有没有一块硬件可以永久存储数据的?
磁盘中数据的形式就是文件,文件是数据的载体。

思路

1、先要定位文件
File类可以定位文件:进行删除、获取文本本身信息等 *** 作。
但是不能读写文件内容。
2、读写文件数据
IO流技术可以对硬盘中的文件进行读写
3、今日总体学习思路
先学会使用File类定位文件以及 *** 作文件本身
然后学习IO流读写文件数据。

File类概述

####File类概述

  1. File类在包java.io.File下、代表 *** 作系统的文件对象(文件、文件夹)。
  2. File类提供了诸如:定位文件,获取文件本身的信息、删除文件、创建文件(文件夹)等功能。

####File类创建对象

  • File对象可以定位文件和文件夹
  • File封装的对象仅仅是一个路径名,这个路径可以是存在的,也可以是不存在的。

####绝对路径和相对路径

package com.itheima.d1_file;

import java.io.File;

//学会创建File对象定位 *** 作系统的文件(文件/文件夹)
public class FileDemo {
    public static void main(String[] args) {
        //1.创建file对象(制定了文件路径)
        //路径写法:C:\Users\zhao\Pictures
        //        C:/Users/zhao/Pictures
        // API    File.separator   相当于一个分隔符
        //File f=new File("C:\Users\zhao\Pictures");
        //File f=new File("C:/Users/zhao/Pictures");
        File f=new File("C:"+File.separator+"Users"+File.separator+"zhao"+File.separator+"Pictures");
        long size=f.length();//文件的字节大小
        System.out.println(size);

        //2.File创建对象,支持绝对路径支持相对路径(重点)
        File f1=new File("C:\Users\zhao\Pictures\1d583c40ca3dee11.png!cc_300x150.jpg");//绝对路径
        System.out.println(f1.length());


        //相对路径一般定位模块中的文件的.相对于工程下!!(javamax)
        File f2=new File("file-io-app/src/data.txt");
        System.out.println(f2.length());

        //3.File创建对象,可以是文件也可以是文件夹
        File f3=new File("D/resources");
        System.out.println(f3.exists());//判断这个路径是否存在与否

    }
}

File类的常用API 判断文件类型、获取文件信息

package com.itheima.d1_file;
import java.io.File;
import java.text.SimpleDateFormat;

/**
 目标:File类的获取功能的API
 - public String getAbsolutePath()  :返回此File的绝对路径名字符串。
 - public String getPath()  : 获取创建文件对象的时候用的路径
 - public String getName()  : 返回由此File表示的文件或目录的名称。
 - public long length()  :    返回由此File表示的文件的长度。
 */
public class FileDemo02 {
    public static void main(String[] args) {
        // 1.绝对路径创建一个文件对象
        File f1 = new File("C:\Users\zhao\Pictures\03网易新闻右侧列表.png");
        // a.获取它的绝对路径。
        System.out.println(f1.getAbsolutePath());
        // b.获取文件定义的时候使用的路径。
        System.out.println(f1.getPath());
        // c.获取文件的名称:带后缀。
        System.out.println(f1.getName());
        // d.获取文件的大小:字节个数。
        System.out.println(f1.length()); // 字节大小
        // e.获取文件的最后修改时间
        long time = f1.lastModified();
        System.out.println("最后修改时间:" + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(time));
        // f、判断文件是文件还是文件夹
        System.out.println(f1.isFile()); // true
        System.out.println(f1.isDirectory()); // false

        System.out.println("-------------------------");

        File f2 = new File("file-io-app\src\data.txt");
        // a.获取它的绝对路径。
        System.out.println(f2.getAbsolutePath());
        // b.获取文件定义的时候使用的路径。
        System.out.println(f2.getPath());
        // c.获取文件的名称:带后缀。
        System.out.println(f2.getName());
        // d.获取文件的大小:字节个数。
        System.out.println(f2.length()); // 字节大小
        // e.获取文件的最后修改时间
        long time1 = f2.lastModified();
        System.out.println("最后修改时间:" + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(time1));
        // f、判断文件是文件还是文件夹
        System.out.println(f2.isFile()); // true
        System.out.println(f2.isDirectory()); // false
        System.out.println(f2.exists()); // true

        File file = new File("D:/");
        System.out.println(file.isFile()); // false
        System.out.println(file.isDirectory()); // true
        System.out.println(file.exists()); // true

        File file1 = new File("D:/aaa");
        System.out.println(file1.isFile()); // false
        System.out.println(file1.isDirectory()); // false
        System.out.println(file1.exists()); // false

    }
}

创建文件、删除文件功能 遍历文件夹 创建文件

`package com.itheima.d1_file;

import java.io.File;
import java.io.IOException;

/**
     目标:File类的创建和删除的方法
     - public boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,
              创建一个新的空文件。 (几乎不用的,因为以后文件都是自动创建的!)
     - public boolean delete() :删除由此File表示的文件或目录。 (只能删除空目录)
     - public boolean mkdir() :创建由此File表示的目录。(只能创建一级目录)
     - public boolean mkdirs() :可以创建多级目录(建议使用的)
 */
public class FileDemo03 {
    public static void main(String[] args) throws IOException {
        File f = new File("file-io-app\src\data.txt");
        // a.创建新文件,创建成功返回true ,反之 ,不需要这个,以后文件写出去的时候都会自动创建
        System.out.println(f.createNewFile());
        File f1 = new File("file-io-app\src\data02.txt");
        System.out.println(f1.createNewFile()); // (几乎不用的,因为以后文件都是自动创建的!)

        // b.mkdir创建一级目录
        File f2 = new File("D:/Temp/aaa");
        System.out.println(f2.mkdir());

        // c.mkdirs创建多级目录(重点)
        File f3 = new File("D:/Temp/ccc/ddd/eee/ffff");
//        System.out.println(f3.mkdir());
        System.out.println(f3.mkdirs()); // 支持多级创建

        // d.删除文件或者空文件夹
        System.out.println(f1.delete());
        File f4 = new File("D:/resources/xueshan.jpeg");
        System.out.println(f4.delete()); // 占用一样可以删除

        // 只能删除空文件夹,不能删除非空文件夹.
        File f5 = new File("D:/resources/aaa");
        System.out.println(f5.delete());
    }
}
删除文件

  • delete方法默认只能删除文件和空文件夹。
  • delete方法直接删除不走回收站
遍历

`package com.itheima.d1_file;

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

/**

    目标:File针对目录的遍历
    - public String[] list():
         获取当前目录下所有的"一级文件名称"到一个字符串数组中去返回。
    - public File[] listFiles()(常用):
         获取当前目录下所有的"一级文件对象"到一个文件对象数组中去返回(重点)
 */
public class FileDemo04 {
    public static void main(String[] args) {
        // 1、定位一个目录
        File f1 = new File("D:/Temp");
        String[] names = f1.list();
        for (String name : names) {
            System.out.println(name);
        }

        // 2.一级文件对象
        // 获取当前目录下所有的"一级文件对象"到一个文件对象数组中去返回(重点)
        File[] files = f1.listFiles();
        for (File f : files) {
            System.out.println(f.getAbsolutePath());
        }

        // 注意事项
        File dir = new File("D:/resources/ddd");
        File[] files1 = dir.listFiles();
        System.out.println(Arrays.toString(files1));
    }
}
`
listFiles方法注意事项
  • 当调用者不存在时,返回null 当调用者是一个文件时,返回null 当调用者是一个空文件夹时,返回一个长度为0的数组

  • 当调用者是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回

  • 当调用者是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏内容

  • 当调用者是一个需要权限才能进入的文件夹时,返回null

方法递归 递归的形式和特点 什么是方法递归?
  • 方法直接调用自己或者间接调用自己的形式称为方法递归( recursion)。
  • 递归做为一种算法在程序设计语言中广泛应用。
递归的形式
  • 直接递归:方法自己调用自己。
  • 间接递归:方法调用其他方法,其他方法又回调方法自己。

####方法递归存在的问题?

  • 递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出现象。
package com.itheima.d2_recusion;

/**
 * 递归
 */
public class RecursionDemo01 {
    public static void main(String[] args) {
        test2();
    }
    public static void test(){
        System.out.println("................test被执行......................");
        test();//方法递归(直接递归形式(自己调自己))
    }
    public static void test2(){
        System.out.println("................test2被执行......................");
        test3();
    }
    public static void test3(){
        System.out.println("................test3被执行......................");
        test2();
    }
}

递归的算法流程、核心要素

####递归案例导学-计算1-n的阶乘

需求:计算1-n的阶乘的结果,使用递归思想解决,我们先从数学思维上理解递归的流程和核心点。
分析
假如我们认为存在一个公式是 f(n) = 1234567*…(n-1)*n;
那么公式等价形式就是: f(n) = f(n-1) *n
如果求的是 1-5的阶乘 的结果,我们手工应该应该如何应用上述公式计算。
f(5) = f(4) * 5

f(4) = f(3) * 4

f(3) = f(2) * 3

f(2) = f(1) * 2

f(1) = 1

递归解决问题的思路:

把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。

递归算法三要素大体可以总结为:

递归的公式: f(n) = f(n-1) * n;
递归的终结点:f(1)
递归的方向必须走向终结点:
f(5) = f(4) * 5

f(4) = f(3) * 4

f(3) = f(2) * 3

f(2) = f(1) * 2

f(1) = 1

package com.itheima.d2_recusion;

/**
 * 目标:递归算法和执行流程
 */
public class RecursionDemo02 {
    public static void main(String[] args) {
        System.out.println(f(5));
    }
    public static int f(int n){
        if(n==1){
            return 1;
        }else {
            return f(n-1)*n;
        }
    }
}

递归常见案例

####递归案例导学-计算1-n的和

需求:计算1-n的和的结果,使用递归思想解决,我们先从数学思维上理解递归的流程和核心点。
分析
假如我们认为存在一个公式是 f(n) = 1 + 2 + 3 + 4 + 5 + 6 + 7 + …(n-1) + n;
那么公式等价形式就是: f(n) = f(n-1) + n
递归的终结点:f(1) = 1
如果求的是 1-5的和 的结果,应该如何计算。
f(5) = f(4) + 5

f(4) = f(3) + 4

f(3) = f(2) + 3

f(2) = f(1) + 2

f(1) = 1

package com.itheima.d2_recusion;

/**
 * 目标:1-n求和
 */
public class RecursionDemo03 {
    public static void main(String[] args) {
        System.out.println(f(5));
    }
    public static int f(int n){
        if(n==1){
            return 1;
        }else {
            return f(n-1)+n;
        }
    }
}

递归的经典问题 猴子吃桃问题

猴子第一天摘下若干桃子,当即吃了一半,觉得好不过瘾,于是又多吃了一个
第二天又吃了前天剩余桃子数量的一半,觉得好不过瘾,于是又多吃了一个
以后每天都是吃前天剩余桃子数量的一半,觉得好不过瘾,又多吃了一个
等到第10天的时候发现桃子只有1个了。
需求:请问猴子第一天摘了多少个桃子?
分析:
整体来看,每一天都是做同一个事件,典型的规律化问题,考虑递归三要素:
递归公式:
递归终结点:
递归方向:

package com.itheima.d2_recusion;

/**
 * 目标:猴子吃桃
 * 第一天          第二天
 * f(x)-f(x)/2-1=f(x+1)
 * 公式:f(x)=2f(x+1)+2
 * 求:f(1)=?
 * 终结点:f(10)=1
 */
public class RecursionDemo04 {
    public static void main(String[] args) {
        System.out.println(f(1));
    }
    public static int f(int n){
        if(n==10){
            return 1;
        }else {
            return 2*f(n+1)+2;
        }
    }
}
//1534
非规律化递归案例-文件搜索
  1. 在上述的案例中递归算法都是针对存在规律化的递归问题。

  2. 有很多问题是非规律化的递归问题,比如文件搜索。如何解决?

    非规律化递归问题自己看着办,需要流程化的编程思维。

需求:文件搜索、从C:盘中,搜索出某个文件名称并输出绝对路径。
分析:
先定位出的应该是一级文件对象
遍历全部一级文件对象,判断是否是文件
如果是文件,判断是否是自己想要的
如果是文件夹,需要继续递归进去重复上述过程

  • 文件搜索用到了什么技术
  • 递归,因为listFile只是搜索到了一级文件对象。
package com.itheima.d2_recusion;

import java.io.File;

/**
 * 目标:去D盘搜索一个文件DingtalkElevate.exe文件
 */
public class RecursionDemo05 {
    public static void main(String[] args) {
    //2.传入目录和文件名称
        searchFile(new File("D:/"),"DingtalkElevate.exe");
    }

    /**
     * 1.搜索某个目录下的全部文件,找到我们想要的文件
     * @param dir  被搜索的源目录
     * @param fileName  被搜索的文件名称
     */
    public static void searchFile(File dir,String fileName){
        //3.判断dir是否是目录
        if(dir!=null&&dir.isDirectory()){
            //可以找了
            //4.提取当前目录下的一级文件对象
            File[]files=dir.listFiles();
            //5.判断是否存在一级文件对象,存在才可以判断
            if(files!=null&&files.length>0){
                for (File file : files) {
                    //6.判断是否为文件还是文件夹
                    if (file.isFile()){
                        //7.是不是要找的文件,是的话输出路径
                        if (file.getName().contains(fileName)){
                            System.out.println("找到了:"+file.getAbsolutePath());
                        }
                    }else {
                        //8.是文件夹
                        searchFile(file,fileName);
                    }
                }
            }
        }else {
            System.out.println("您当前搜的不是文件夹");
        }
    }
}

非规律化递归案例-啤酒问题

需求:啤酒2元1瓶,4个盖子可以换一瓶,2个空瓶可以换一瓶,
请问10元钱可以喝多少瓶酒,剩余多少空瓶和盖子。
答案:15瓶 3盖子 1瓶子

package com.itheima.d2_recusion;

import java.io.File;

/**
 * 目标:需求:啤酒2元1瓶,4个盖子可以换一瓶,2个空瓶可以换一瓶,
 * 请问10元钱可以喝多少瓶酒,剩余多少空瓶和盖子。
 * 答案:15瓶 3盖子 1瓶子
 * @author zhao
 */
public class RecursionDemo06 {
    //定义一个静态的成员变量用于存储可以买的酒数量
    public static int totalNumber;//默认0瓶
    public static int lastBottleNumber;//记录每次剩余的瓶子个数
    public static int lastCoverNumber;//记录每次剩余盖子个数
    public static void main(String[] args) {
        //1.买酒
        buy(10);
        System.out.println("总数:"+totalNumber);
        System.out.println("剩余盖子数:"+lastCoverNumber);
        System.out.println("剩余瓶子数:"+lastBottleNumber);
    }
    public static void buy(int money){
        //2.看可以立马买多少瓶
        int buyNumber=money/2;
        totalNumber+=buyNumber;
        //3.把盖子和瓶子换算成钱
        //统计总的盖子数和瓶子数
        int coverNumber=lastCoverNumber+buyNumber;
        int bottleNumber=lastBottleNumber+buyNumber;
        //统计可以换算的钱
        int allMoney=0;
        if (coverNumber>=4){
            allMoney+=(coverNumber/4)*2;
        }
        lastCoverNumber=coverNumber%4;
        if (bottleNumber>=2){
            allMoney+=(bottleNumber/2)*2;
        }
        lastBottleNumber=bottleNumber%2;

        if(allMoney>=2){
            buy(allMoney);
        }
    }
}

字符集 常见字符集介绍


1.字符串常见的字符底层组成是什么样的?
英文和数字等在任何国家的字符集中都占1个字节
GBK字符中一个中文字符占2个字节
UTF-8编码中一个中文1般占3个字节
2.编码前的字符集和编码好的字符集有什么要求?
必须一致,否则会出现中文字符乱码
英文和数字在任何国家的编码中都不会乱码

###字符集的编码、解码 *** 作

####String编码

方法名称说明
byte[] getBytes()使用平台的默认字符集将该 String编码为一系列字节,将结果存储到新的字节数组中
byte[] getBytes(String charsetName)使用指定的字符集将该 String编码为一系列字节,将结果存储到新的字节数组中
String解码
构造器说明
String(byte[] bytes)通过使用平台的默认字符集解码指定的字节数组来构造新的 String
String(byte[] bytes, String charsetName)通过指定的字符集解码指定的字节数组来构造新的 String
package com.itheima.d3_charset;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

/**
 * 目标:学会自己进行文字的编码和解码,为以后可能会用到的场景做准备
 */
public class Test {
    public static void main(String[] args) throws UnsupportedEncodingException {
        //1.编码:把文字转换成字节(使用指定的编码)
        String name="abc我爱你中国";
        //以当前代码默认字符集进行编码(UTF-8)
        //byte[]bytes=name.getBytes(StandardCharsets.UTF_8);//length=18
        byte[]bytes=name.getBytes("GBK");//length=13
        System.out.println(bytes.length);
        System.out.println(Arrays.toString(bytes));

        //2.解码:把字节转换成对应的中文形式(编码前 和编码后 字符集必须一致,否则乱码)
        //String rs=new String(bytes);//默认的UTF-8乱码
        String rs=new String(bytes,"GBK");//指定GBK解码
        System.out.println(rs);

    }
}

IO流概述
  • I表示intput,是数据从硬盘文件读入到内存的过程,称之输入,负责读。
  • O表示output,是内存程序的数据从内存到写出到硬盘文件的过程,称之输出,负责写。

IO流分类

总结流的四大类
  • 字节输入流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流称为字节输入流。
  • 字节输出流:以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中去的流称为字节输出流。
  • 字符输入流:以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入到内存中去的流称为字符输入流。
  • 字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中去的流称为字符输出流。

  1. IO流的作用?

    读写文件数据的

  2. IO流是怎么划分的,大体分为几类,各自的作用?

    字节流:字节输入流,字节输出流(读写字节数数据的)

    字符流:字符输入流,字符输出流(读写字符数据的)

字节流的使用 文件字节输入流:每次读取一个字节 文件字节输入流:FileInputStream

作用:以内存为基准,把磁盘文件中的数据以字节的形式读取到内存中去。

构造器
构造器说明
public FileInputStream(File file)创建字节输入流管道与源文件对象接通
public FileInputStream(String pathname)创建字节输入流管道与源文件路径接通
方法
方法名称说明
public int read()每次读取一个字节返回,如果字节已经没有可读的返回-1
public int read(byte[] buffer)每次读取一个字节数组返回,如果字节已经没有可读的返回-1
  1. 文件字节输入流,每次读取一个字节的api是哪个?

    read

  2. 每次读取一个字节存在什么问题?

    性能较慢

    读取中文字符输出无法避免乱码问题。

package com.itheima.d4_byte_stream;

import java.io.*;

/**
 * @author zhao
 */
public class FileInputStreamDemo01 {
    public static void main(String[] args) throws Exception {
        //1.创建一个文件字节输入流管道与源文件接通
        //InputStream is=new FileInputStream(new File("file-io-app\src\data.txt"));
        InputStream is=new FileInputStream(("file-io-app\src\data.txt"));

//        //2.读取一个字节返回(每次读取一滴水)
//        int b1= is.read();
//        System.out.println(b1);//97
//        System.out.println((char)b1);//a
//
//        int b2= is.read();
//        System.out.println(b2);//98
//        System.out.println((char)b2);//b
//
//        int b3= is.read();
//        System.out.println(b3);//51
//        System.out.println((char)b3);//3

        //3.使用循环改进
        //定义一个变量记录每次读取的字节
        int b;
        while ((b=is.read())!=-1){
            System.out.print((char)b);
        }
    }
}

文件字节输入流:每次读取一个字节数组
方法名称说明
public int read()每次读取一个字节返回,如果字节已经没有可读的返回-1
public int read(byte[] buffer)每次读取一个字节数组返回,如果字节已经没有可读的返回-1
package com.itheima.d4_byte_stream;

import java.io.FileInputStream;
import java.io.InputStream;

/**目标:使用文件字节输入流读取一个字节数组的数据
 * @author zhao
 */
public class FileInputStreamDemo02 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个文件字节输入流管道与源文件接通
        InputStream is = new FileInputStream("file-io-app/src/data01.txt");
//
//        // 2、定义一个字节数组,用于读取字节数组
//        byte[] buffer = new byte[3]; // 3B
//        int len = is.read(buffer);
//        System.out.println("读取了几个字节:" + len);
//        String rs = new String(buffer);
//        System.out.println(rs);
//
//        int len1 = is.read(buffer);
//        System.out.println("读取了几个字节:" + len1);
//        String rs1 = new String(buffer);
//        System.out.println(rs1);
//        // buffer = [a b c]
//
//        // buffer = [a b c]  ==>  [c d c]
//        int len2 = is.read(buffer);
//        System.out.println("读取了几个字节:" + len2);
//        // 读取多少倒出多少
//        String rs2 = new String(buffer, 0, len2);
//        System.out.println(rs2);
//
//        int len3 = is.read(buffer);
//        System.out.println(len3); // 读取完毕返回-1

        //3.改进使用循环,每次读取一个字节数组
        byte[]buffer=new byte[3];
        int len;//记录每次读取的字节数
        while( (len=is.read(buffer))!=-1){
            //读多少倒多少
            System.out.print(new String(buffer,0,len));
        }
    }
}

  1. 每次读取一个字节数组存在什么问题?
    • 读取的性能得到了提升
    • 读取中文字符输出无法避免乱码问题。
文件字节输入流:一次读完全部字节

1、如何使用字节输入流读取中文内容输出不乱码呢?
定义一个与文件一样大的字节数组,一次性读取完文件的全部字节。

2、直接把文件数据全部读取到一个字节数组可以避免乱码,是否存在问题?
如果文件过大,字节数组可能引起内存溢出。

方式一
  • 自己定义一个字节数组与文件的大小一样大,然后使用读取字节数组的方法,一次性读取完成。
方法名称说明
public int read(byte[] buffer)每次读取一个字节数组返回,如果字节已经没有可读的返回-1
方式二
  • 官方为字节输入流InputStream提供了如下API可以直接把文件的全部数据读取到一个字节数组中
方法名称说明
public byte[] readAllBytes() throws IOException直接将当前字节输入流对应的文件对象的字节数据装到一个字节数组返回
  1. 如何使用字节输入流读取中文内容输出不乱码呢?
  • 一次性读取完全部字节。
  • 可以定义与文件一样大的字节数组读取,也可以使用官方API.
  1. 直接把文件数据全部读取到一个字节数组可以避免乱码,是否存在问题?
  • 如果文件过大,定义的字节数组可能引起内存溢出。
package com.itheima.d4_byte_stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

/**
   目标:使用文件字节输入流一次读完文件的全部字节。可以解决乱码问题。
 */
public class FileInputStreamDemo03 {
    public static void main(String[] args) throws Exception {
        //1.创建一个文件字节输入流管道与源文件接通
        File f=new File("file-io-app\src\data02.txt");
        InputStream is=new FileInputStream(f);

        //2.定义一个字节数组与文件的大小刚刚一样大
//       byte[]buffer=new byte[(int) f.length()];
//       int len=is.read(buffer);
//        System.out.println("读取了多少个字节"+len);
//        System.out.println("文件大小"+f.length());
//        System.out.println(new String(buffer));

        byte[]buffer=is.readAllBytes();
        System.out.println(new String(buffer));
    }
}

文件字节输出流:写字节数据到文件 文件字节输出流:FileOutputStream
  • 作用:以内存为基准,把内存中的数据以字节的形式写出到磁盘文件中去的流。
构造器说明
public FileOutputStream(File file)创建字节输出流管道与源文件对象接通
public FileOutputStream(File file,boolean append)创建字节输出流管道与源文件对象接通,可追加数据
public FileOutputStream(String filepath)创建字节输出流管道与源文件路径接通
public FileOutputStream(String filepath,boolean append)创建字节输出流管道与源文件路径接通,可追加数据
文件字节输出流(FileOutputStream)写数据出去的API
方法名称说明
public void write(int a)写一个字节出去
public void write(byte[] buffer)写一个字节数组出去
public void write(byte[] buffer , int pos , int len)写一个字节数组的一部分出去。
流的关闭与刷新
方法说明
flush()刷新流,还可以继续写数据
close()关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据
字节输出流如何实现数据追加
  1. public FileOutputStream(String filepath,boolean append)创建字节输出流管道与源文件路径接通,可追加数据
    字节输出流如何实现写出去的数据能换行
    os.write(“\r\n”.getBytes())
  2. 如何让写出去的数据能成功生效?
    flush()刷新数据
    close()方法是关闭流,关闭包含刷新,关闭后流不可以继续使用了。 | |
package com.itheima.d4_byte_stream;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;

/**
    目标:字节输出流的使用。

    IO流的体系:
            字节流                                   字符流
    字节输入流           字节输出流               字符输入流       字符输出流
    InputStream         OutputStream           Reader         Writer     (抽象类)
    FileInputStream     FileOutputStream       FileReader     FileWriter (实现类)

    a.FileOutputStream文件字节输出流。
        -- 作用:以内存为基准,把内存中的数据,按照字节的形式写出到磁盘文件中去。
                 简单来说,把内存数据按照字节写出到磁盘文件中去。
        -- 构造器:
            public FileOutputStream(File file):创建一个字节输出流管道通向目标文件对象。
            public FileOutputStream(String file):创建一个字节输出流管道通向目标文件路径。
            public FileOutputStream(File file , boolean append):创建一个追加数据的字节输出流管道通向目标文件对象。
            public FileOutputStream(String file , boolean append):创建一个追加数据的字节输出流管道通向目标文件路径。
        -- 方法:
           public void write(int a):写一个字节出去 。
           public void write(byte[] buffer):写一个字节数组出去。
           public void write(byte[] buffer , int pos , int len):写一个字节数组的一部分出去。
                           参数一,字节数组;参数二:起始字节索引位置,参数三:写多少个字节数出去。
    小结:
        记住。
        换行:  os.write("\r\n".getBytes()); // 换行
        追加数据管道: OutputStream os = new FileOutputStream("day10_demo/out01.txt" , true); // 追加管道!!
 */
public class OutputStreamDemo04 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个文件字节输出流管道与目标文件接通
        OutputStream os = new FileOutputStream("file-io-app/src/out04.txt" , true); // 追加数据管道
//        OutputStream os = new FileOutputStream("file-io-app/src/out04.txt"); // 先清空之前的数据,写新数据进入

        // 2、写数据出去
        // a.public void write(int a):写一个字节出去
        os.write('a');
        os.write(98);
        os.write("\r\n".getBytes()); // 回车 换行
        // os.write('徐'); // [ooo] 三个字节 乱码

        // b.public void write(byte[] buffer):写一个字节数组出去。
        byte[] buffer = {'a' , 97, 98, 99};
        os.write(buffer);
        os.write("\r\n".getBytes()); //回车 换行

        byte[] buffer2 = "我是中国人".getBytes();//编码
//        byte[] buffer2 = "我是中国人".getBytes("GBK");
        os.write(buffer2);
        os.write("\r\n".getBytes()); //回车 换行


        // c. public void write(byte[] buffer , int pos , int len):写一个字节数组的一部分出去。
        byte[] buffer3 = {'a',97, 98, 99};
        os.write(buffer3, 0 , 3);
        os.write("\r\n".getBytes()); //回车 换行

        // os.flush(); // 写数据必须,刷新数据 可以继续使用流
        os.close(); // 释放资源,包含了刷新的!关闭后流不可以使用了
    }
}

文件拷贝

需求:
把某个视频复制到其他目录下的“b.avi”

思路:
根据数据源创建字节输入流对象
根据目的地创建字节输出流对象
读写数据,复制视频
释放资源

  1. 字节流适合做一切文件数据的拷贝吗?
    任何文件的底层都是字节,拷贝是一字不漏的转移字节,只要前后文件格式、编码一致没有任何问题。
package com.itheima.d4_byte_stream;

import java.io.*;

/**
 * 目标:学会使用字节流完成文件的复制(支持一切文件类型的复制)
 */
public class CopyDemo05 {
    public static void main(String[] args) {
        //1.创建一个字节输入流管道与原视频接通
        try {
            InputStream is=new FileInputStream("C:\Users\zhao\Videos");

            //2.创建一个字节输出流管道与目标文件接通
            OutputStream os=new FileOutputStream("D:\Temp\new.avi");

            //3.定义一个字节数组转移数据
            byte[]buffer=new byte[1024];
            int len;//记录每次读取的字节数
            while((len=is.read(buffer))!=-1){
                os.write(buffer,0,len);
            }
            System.out.println("复制完成了!");

            //4.关闭流
            os.close();
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
资源释放的方式 try-catch-finally
  1. finally:在异常处理时提供finally块来执行所有清除 *** 作,比如说IO流中的释放资源
  2. 特点:被finally控制的语句最终一定会执行,除非JVM退出
  3. 异常处理标准格式:try….catch…finally

####try-catch-finally的作用

finally代码块是最终一定要执行的,可以在代码执行完毕的最后用于释放资源。

package com.itheima.d5_recourse;

import javax.imageio.IIOException;
import java.io.*;

/**
    目标:学会使用finall释放资源
 */
public class TryCatchFinallyDemo1 {
    public static void main(String[] args) throws Exception {
        InputStream is = null;
        OutputStream os = null;
        //1.创建一个字节输入流管道与原视频接通
        try {
            is = new FileInputStream("D:\BaiduNetdiskDownload\day19、File、递归、IO流(一)");

            //2.创建一个字节输出流管道与目标文件接通
            os = new FileOutputStream("D:\Temp\new.avi");

            //3.定义一个字节数组转移数据
            byte[] buffer = new byte[1024];
            int len;//记录每次读取的字节数
            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
            System.out.println("复制完成了!");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //无论代码是否正常结束,最后都要执行这里
            System.out.println("=============finally===============");
            try {
                //4.关闭流
                if (os != null) os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                //4.关闭流
                if (is != null) is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static int test(int a, int b) {
        try {
            int c = a / b;
            return c;
        } catch (Exception e) {
            e.printStackTrace();
            return -111111; // 计算出现bug.
        } finally {
            System.out.println("--finally--");
            // 哪怕上面有return语句执行,也必须先执行完这里才可以!
            // 开发中不建议在这里加return ,如果加了,返回的永远是这里的数据了,这样会出问题!
            return 100;
        }
    }
}

###try-with-resource

JDK 7 以及 JDK 9的()中只能放置资源对象,否则报错
什么是资源呢?
资源都是实现了Closeable/AutoCloseable接口的类对象

try-catch-resource的作用?
自动释放资源、代码简洁

package com.itheima.d5_recourse;

import java.io.*;

/**
    目标:JDK7释放资源
 */
public class TryCatchResouceDemo2 {
    public static void main(String[] args) throws Exception {
        try(//这里只能放置资源对象,用完会自动关闭,自动调用资源对象的close方法关闭资源(即出现异常也会做关闭 *** 作)
            //1.创建一个字节输入流管道与原视频接通
            InputStream is = new FileInputStream("file-io-app/src/out04.txt");
            //2.创建一个字节输出流管道与目标文件接通
            OutputStream os = new FileOutputStream("file-io-app/src/out05.txt");
                ) {
            //3.定义一个字节数组转移数据
            byte[] buffer = new byte[1024];
            int len;//记录每次读取的字节数
            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
            System.out.println("复制完成了!");

        } catch (Exception e) {
            e.printStackTrace();

        }
    }
}

package com.itheima.d5_recourse;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

/**
    目标:JDK9释放资源的方式
 */
public class TryCatchResouceDemo3 {
    public static void main(String[] args) throws Exception {
        //1.创建一个字节输入流管道与原视频接通
        InputStream is = new FileInputStream("file-io-app/src/out04.txt");
        //2.创建一个字节输出流管道与目标文件接通
        OutputStream os = new FileOutputStream("file-io-app/src/out05.txt");
        try(is;os) {
            //3.定义一个字节数组转移数据
            byte[] buffer = new byte[1024];
            int len;//记录每次读取的字节数
            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
            System.out.println("复制完成了!");

        } catch (Exception e) {
            e.printStackTrace();

        }
    }
}

字符流的使用 文件字符输入流-一次读取一个字符

  1. 字节流读取中文输出会存在什么问题?
    会乱码。或者内存溢出。
  2. 读取中文输出,哪个流更合适,为什么?
    字符流更合适,最小单位是按照单个字符读取的。
文件字符输入流:Reader
  • 作用:以内存为基准,把磁盘文件中的数据以字符的形式读取到内存中去。
构造器说明
public FileReader(File file)创建字符输入流管道与源文件对象接通
public FileReader(String pathname)创建字符输入流管道与源文件路径接通
方法名称说明
public int read()每次读取一个字符返回,如果字符已经没有可读的返回-1
public int read(char[] buffer)每次读取一个字符数组,返回读取的字符个数,如果字符已经没有可读的返回-1
package com.itheima.d6_char_stream;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.Reader;

/**
     目标:字符输入流的使用。

     IO流的体系:
            字节流                                   字符流
     字节输入流           字节输出流               字符输入流       字符输出流
     InputStream         OutputStream            Reader         Writer     (抽象类)
     FileInputStream     FileOutputStream        FileReader     FileWriter (实现类)

     c.FileReader:文件字符输入流。
         -- 作用:以内存为基准,把磁盘文件的数据以字符的形式读入到内存。
            简单来说,读取文本文件内容到内存中去。

         -- 构造器:
            public FileReader(File file):创建一个字符输入流与源文件对象接通。
            public FileReader(String filePath):创建一个字符输入流与源文件路径接通。

         -- 方法:
            public int read(): 读取一个字符的编号返回! 读取完毕返回-1
            public int read(char[] buffer):读取一个字符数组,读取多少个字符就返回多少个数量,读取完毕返回-1
     小结:
        字符流一个一个字符的读取文本内容输出,可以解决中文读取输出乱码的问题。
        字符流很适合 *** 作文本文件内容。
        但是:一个一个字符的读取文本内容性能较差!!
 */
public class FileReaderDemo01 {
    public static void main(String[] args) throws Exception {
        // 目标:每次读取一个字符。
        // 1、创建一个字符输入流管道与源文件接通
       Reader fr=new FileReader("file-io-app\src\datao6.txt");

       //2.读取一个字符返回,没有可读的字符返回-1
//        int code=fr.read();
//        System.out.println((char)code);
//
//        int code1=fr.read();
//        System.out.println((char)code1);

        //3.使用循环读取字符
        int code;
        while((code= fr.read())!=-1){
            System.out.print((char)code);
        }

    }
}
  1. 字符流的好处。每次读取一个字符存在什么问题?

    读取中文字符不会出现乱码(如果代码文件编码一致)

    性能较慢

文件字符输入流-一次读取一个字符数组 文件字符输入流:FileReader
  • 作用:以内存为基准,把磁盘文件中的数据以字符的形式读取到内存中去。
方法名称说明
public int read()每次读取一个字符返回,如果字符已经没有可读的返回-1
public int read(char[] buffer)每次读取一个字符数组,返回读取的字符数,如果字符已经没有可读的返回-1
package com.itheima.d6_char_stream;

import java.io.FileReader;
import java.io.Reader;

/**
     目标:字符输入流的使用-按照字符数组读取。

     IO流的体系:
            字节流                                       字符流
     字节输入流           字节输出流               字符输入流       字符输出流
     InputStream         OutputStream           Reader         Writer     (抽象类)
     FileInputStream     FileOutputStream       FileReader     FileWriter (实现类)

     c.FileReader:文件字符输入流。
         -- 作用:以内存为基准,把磁盘文件的数据以字符的形式读入到内存。
            简单来说,读取文本文件内容到内存中去。
         -- 构造器:
            public FileReader(File file):创建一个字符输入流与源文件对象接通。
            public FileReader(String filePath):创建一个字符输入流与源文件路径接通。
         -- 方法:
            public int read(): 读取一个字符的编号返回! 读取完毕返回-1
            public int read(char[] buffer):读取一个字符数组,
                    读取多少个字符就返回多少个数量,读取完毕返回-1
     小结:
         字符流按照字符数组循环读取数据,可以解决中文读取输出乱码的问题,而且性能也较好!!
 */
public class FileReaderDemo02 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个文件字符输入流与源文件接通
        Reader fr = new FileReader("file-io-app/src/data07.txt");

        // 2、用循环,每次读取一个字符数组的数据。  1024 + 1024 + 8
        char[] buffer = new char[1024]; // 1K字符
        int len;
        while ((len = fr.read(buffer)) != -1) {
            String rs = new String(buffer, 0, len);
            System.out.print(rs);
        }
    }
}

文件字符输出流 文件字符输出流(FileWriter)写数据出去的API
方法名称说明
void write(int c)写一个字符
void write(char[] cbuf)写入一个字符数组
void write(char[] cbuf, int off, int len)写入字符数组的一部分
void write(String str)写一个字符串
void write(String str, int off, int len)写一个字符串的一部分
void write(int c)写一个字符
流的关闭与刷新
方法说明
flush()刷新流,还可以继续写数据
close()关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据

字节流、字符流如何选择使用?

  • 字节流适合做一切文件数据的拷贝(音视频,文本)
  • 字节流不适合读取中文内容输出
  • 字符流适合做文本文件的 *** 作(读,写)
package com.itheima.d6_char_stream;

import java.io.File;
import java.io.FileWriter;
import java.io.Writer;

/**
     目标:字符输出流的使用。

     IO流的体系:
            字节流                                   字符流
     字节输入流           字节输出流               字符输入流       字符输出流
     InputStream         OutputStream           Reader         Writer     (抽象类)
     FileInputStream     FileOutputStream       FileReader     FileWriter (实现类)

     d.FileWriter文件字符输出流的使用。
        -- 作用:以内存为基准,把内存中的数据按照字符的形式写出到磁盘文件中去。
            简单来说,就是把内存的数据以字符写出到文件中去。
        -- 构造器:
           public FileWriter(File file):创建一个字符输出流管道通向目标文件对象。
           public FileWriter(String filePath):创建一个字符输出流管道通向目标文件路径。
           public FileWriter(File file,boolean append):创建一个追加数据的字符输出流管道通向目标文件对象。
           public FileWriter(String filePath,boolean append):创建一个追加数据的字符输出流管道通向目标文件路径。
        -- 方法:
             a.public void write(int c):写一个字符出去
             b.public void write(String c)写一个字符串出去:
             c.public void write(char[] buffer):写一个字符数组出去
             d.public void write(String c ,int pos ,int len):写字符串的一部分出去
             e.public void write(char[] buffer ,int pos ,int len):写字符数组的一部分出去
     小结:
        字符输出流可以写字符数据出去,总共有5个方法写字符。
        覆盖管道:
             Writer fw = new FileWriter("Day10Demo/src/dlei03.txt"); // 覆盖数据管道
        追加数据管道:
             Writer fw = new FileWriter("Day10Demo/src/dlei03.txt",true); // 追加数据管道
        换行:
             fw.write("\r\n"); // 换行
        结论:读写字符文件数据建议使用字符流。复制文件建议使用字节流。
 */
public class FileWriterDemo03 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个字符输出流管道与目标文件接通
        // Writer fw = new FileWriter("file-io-app/src/out08.txt"); // 覆盖管道,每次启动都会清空文件之前的数据
        Writer fw = new FileWriter("file-io-app/src/out08.txt", true); // 覆盖管道,每次启动都会清空文件之前的数据

//      a.public void write(int c):写一个字符出去
        fw.write(98);
        fw.write('a');
        fw.write('徐'); // 不会出问题了
        fw.write("\r\n"); // 换行

//       b.public void write(String c)写一个字符串出去
        fw.write("abc我是中国人");
        fw.write("\r\n"); // 换行


//       c.public void write(char[] buffer):写一个字符数组出去
        char[] chars = "abc我是中国人".toCharArray();
        fw.write(chars);
        fw.write("\r\n"); // 换行


//       d.public void write(String c ,int pos ,int len):写字符串的一部分出去
        fw.write("abc我是中国人", 0, 5);
        fw.write("\r\n"); // 换行


//       e.public void write(char[] buffer ,int pos ,int len):写字符数组的一部分出去
        fw.write(chars, 3, 5);
        fw.write("\r\n"); // 换行


        // fw.flush();// 刷新后流可以继续使用
        fw.close(); // 关闭包含刷线,关闭后流不能使用

    }
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/891133.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-14
下一篇 2022-05-14

发表评论

登录后才能评论

评论列表(0条)

保存