IO流详解

1. File

1.1 File类概述和构造方法

File:它是文件和目录路径名的抽象表示

  • 文件和目录是可以通过File封装成对象的

  • 对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名。它是可以存在的,也可以不存在的。将来要通过具体的操作把这个路径的内容转换为具体存在

构造方法:

方法名 说明
File(String pathname) 通过给定的路径名字符串转换为抽象路径名来创建新的File实例
File(String parent,String child) 从父路径名字符串和子路径名字符串创建新的File实例
File(File parent,String child) 从父抽象路径名和子路径字符串创建新的File实例
        File f1=new File("D:\\FileCast\\java.txt");
        System.out.println(f1);

        File f2=new File("D:\\FileCast","java.txt");
        System.out.println(f2);

        File f3= new File("D:\\FileCast");
        File f4= new File(f3,"java.txt");
        System.out.println(f4);

1.2 File类创建功能

方法名 说明
public boolean createNewFile() 当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件
public boolean mkdir() 创建由此抽象路径名命名的目录
public boolean mkdirs() 创建由此抽象路径名命名的目录,包括任何必须但不存在的父目录
        public static void main(String[] args) throws IOException {
        File f1 = new File("D:\\FileCast\\java.txt");
        System.out.println(f1.createNewFile());//如果文件存在,不创建文件,返回false   如果文件不存在,创建文件,返回true

        File f2 = new File("D:\\FileCast\\Java");
        System.out.println(f2.mkdir());//如果目录存在,不创建目录,返回false   如果目录不存在,创建目录,返回true

        File f3 = new File("D:\\FileCast\\JavaSE\\HTML");
        System.out.println(f3.mkdirs());//mkdirs创建多级目录

        File f4 = new File("D:\\FileCast\\javase.txt");
        System.out.println(f4.mkdir());//true->最终创建了一个目录:javase.txt
    }

1.3 File类删除功能

方法名 说明
public boolean delete() 删除由此抽象路径名表示的文件或目录
        File f1 = new File("D:\\FileCast\\java.txt");
        System.out.println(f1.createNewFile());

        System.out.println(f1.delete());//删除目录应当首先删除文件

删除目录时注意事项

如果一个目录中有内容(目录、文件),不能直接删除,应该先删除目录中的内容,最后删除目录

1.4 File类的判断和获取功能

方法名 说明
public boolean isDirectory() 测试此抽象路径名表示的File是否为目录
public boolean isFile() 测试此抽象路径名表示的File是否为文件
public boolean exists() 测试此抽象路径名表示的File是否存在
public String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串
public String getPath() 将此抽象路径名转换为路径名字符串
public String getName() 返回由此抽象路径名表示的文件和目录的名称
public String[] list() 返回由此抽象路径名表示的文件和目录的名称字符串数组
public File[] listFiles() 返回此抽象路径名表示的目录中的文件和目录的File对象数组

1.5 递归

概述:

以编程的角度来看,递归指的是方法定义中调用方法本身的现象

        //斐波那契数列
        int[] arr = new int[20];
        arr[0] = 1;
        arr[1] = 1;

        for (int i = 2; i < arr.length; i++) {
            arr[i] = arr[i - 1] + arr[i - 2];
        }

        System.out.println(arr[19]);

递归实现:

public static void main(String[] args) {
    System.out.println(f(20));    
}

public static int f(int n) {
    if (n == 1 || n == 2) {	//不加if判断://StackOverflowError:堆栈溢出,递归太深
        return 1;
    } else {
        return f(n - 1) + f(n - 2);
    }
}

递归解决问题要找到两个内容:

  • 递归出口:否则会出现内存溢出
  • 递归规则:与原问题相似的规模较小的问题

递归求阶乘:

public static void main(String[] args) {
        System.out.println(f(5));
    }
public static int f(int n) {
    if (n == 1) {
        return 1;
    }else if (n == 0){
        return 1;
    } else {
        return n * f(n - 1);
    }
}

2. IO流

2.1 IO流概述和分类

概述

  • IO:输入/输出

  • 流:是一种抽象概念,是对数据传输的总称。也就是说数据在设备间的传输称为流流的本质是数据传输

  • IO流就是用来处理设备间数据传输问题的

    ​ 常见的应用:文件复制;文件上传;文件下载

IO流分类:

  • 按照数据的流向:

    • 输入流:读数据
    • 输出流:写数据
  • 按照数据类型来分

    • 字节流:字节输入流、字节输出流
    • 字符流:字符输入流、字符输出流

一般来说,我们说的IO流的分类是按照数据类型来分的

如果数据通过Windows自带的记事本软件打开,我们可以读出里面的内容,就用字符流,否则使用字节流,如果不知道用哪类型的流,就用字节流。

2.2 字节流写数据

字节流抽象基类

  • InputStream:这个抽象类是表示字节输入流的所有类的超类
  • OutputStream:这个抽象类是表示字节输出流的所有类的超类
  • 子类名特点:子类名称都是以其父类作为子类名的后缀

FileOutputStream(String name):创建文件输出流以指定的名称写入文件

        FileOutputStream fos=new FileOutputStream("MyIO\\fos.txt");
        /*
        * ①调用系统功能创建文件
        * ②创建字节输出流对象
        * ③让字节输出流对象指向创建好的文件*/
        fos.write(97);  //void write(int b):将指定的字节写入此文件输出流  输出结果:a  转换为ASCII码对应字符
        fos.write(57);    9
        fos.write(55);    7
        //所有和IO操作相关的内容最终都要释放资源:void close():关闭此输出流并释放与此流关联的所有系统资源。关闭的流无法执行输出操作,也无法重新打开。
        fos.close();

2.3 字节流写数据的三种方式

方法名 说明
void write(int b) 将指定的字节写入此文件输出流
void write(byte[] b) 将b.length字节从指定的字节数组写入此文件输出流,一次写一个字节数组
void write(byte[] b,int off,int len) 将len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流,一次写一个字节数组的部分数据
        FileOutputStream fos=new FileOutputStream("MyIO\\fos.txt");
        //源码:    this(name != null ? new File(name) : null, false);
        //底层:    FileOutputStream ofs=new FileOutputStream(new File("MyIO\\fos.txt"));
        /*还可以写:File file=new File("MyIO\\fos.txt");
        FileOutputStream fos2=new FileOutputStream(file);*/

        //void write(int b):将指定的字节写入此文件输出流
        fos.write(97);
        fos.write(98);
        fos.write(99);
        fos.write(100);
        fos.write(101);

        //void write(byte[] b):将b.length字节从指定的字节数组写入此文件输出流,一次写一个字节数组
        byte[] bys={97,98,99,100,101};
        fos.write(bys);
        //void write(byte[] b,int off,int len) 将len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流,一次写一个字节数组的部分数据
        fos.write(bys,0,bys.length);

2.4 字节流写数据的两个问题

字节流写数据如何实现换行

​ 写完数据后加换行符

        FileOutputStream fos=new FileOutputStream("MyIO\\fos.txt");

        for (int i = 0; i < 10; i++) {
            fos.write("hello".getBytes());
            fos.write("\n".getBytes());//win:\r\n   linux:\n    mac:\r
        }

        fos.close();

字节流写数据如何实现追加写入

public FileOutputStream(File file,boolean append)
创建文件输出流以写入由指定的File对象表示的文件。 如果第二个参数是true ,则字节将写入文件的末尾而不是开头。

FileOutputStream fos=new FileOutputStream("MyIO\\fos.txt",true);

for (int i = 0; i < 10; i++) {
    fos.write("hello".getBytes());
    fos.write("\n".getBytes());//win:\r\n   linux:\n    mac:\r
}

fos.close();

2.5 字节流写数据加异常处理

finally:在异常处理时提供finally块来执行所有清楚操作,比如IO流中的释放资源

特点:被finally控制的语句一定会执行,除非JVM退出

try {
    可能出现异常的代码
}catch (IOException e){
    异常的处理代码
}finally {
    执行所有清楚操作
}
FileOutputStream fos = null;
try {
    fos = new FileOutputStream("MyIO\\fos.txt");
    fos.write("hello".getBytes());
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (fos != null) {
        try {
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.6 字节流读数据(一次读一个字节数据)

FileInputStream:从文件系统中的文件获取输入字节

  • FileInputStream(String name):通过打开实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名

使用字节输入流读数据的步骤:

① 创建字节输入流对象

② 调用字节输入流对象的读数据方法

③ 释放资源

FileInputStream fis = new FileInputStream("MyIO\\fos.txt");

/*
// int read():从该输入流读取一个字节数据
int by =fis.read();
System.out.println(by);//104
System.out.println((char)by);//h
//读取第二个数据
by =fis.read();
System.out.println(by);//104
System.out.println((char)by);//h
by =fis.read();
System.out.println(by);//10:换行
by =fis.read();
System.out.println(by);//-1
*/

/*
//如果到达文件末尾:-1
int by = fis.read();
while (by != -1) {
    System.out.print((char) by);
    by = fis.read();
}
*/

//⭐⭐⭐优化上面的程序
int by;
while ((by = fis.read()) != -1) {
    System.out.print((char) by);
}
/*
 * fis.read():读数据
 * by = fis.read():把读到的数据复制给by
 * by != -1:判断读取到的数据是否为-1
 */

fis.close();

2.7 字节流读数据(一次读一个字节数组数据)

FileInputStream fis=new FileInputStream("MyIO\\fos.txt");


//read(byte[] b) 从输入流中读取最多b.length的字节数并将它们存储到一个字节数组。
byte[] bys=new byte[5];

int len = fis.read(bys);
System.out.println(len);
//System.out.println(new String(bys));
/*  5
    hello
*/
System.out.println(new String(bys,0,len));

len = fis.read(bys);
System.out.println(len);
//System.out.println(new String(bys));
/*  5

    worl
*/
System.out.println(new String(bys,0,len));

len = fis.read(bys);
System.out.println(len);
//System.out.println(new String(bys));
/*  2
    d
    orl
* */
System.out.println(new String(bys,0,len));
/*
 *  2
 *  d
 */
//所以之前的应该也改写成System.out.println(new String(bys,0,len));

//⭐⭐⭐优化上面的程序
byte[] bytes =new byte[1024];//1024及其整数倍
int length;
while((length= fis.read(bytes))!=-1){
    System.out.print(new String(bytes,0,length));
}

fis.close();

2.8 字节缓冲流

  • BufferedOutputStream:该类实现缓冲输出流,通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用。
  • bufferedInputStream:创建BufferedInputStream时,将创建一个内部缓冲区数组。 当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次有多个字节。

构造方法

  • 字节缓冲输入流:BufferedInputStream(InputStream in)
  • 字节缓冲输出流:BufferedoutputStream(OutputStream out)

为什么构造方法需要的是字节流,而不是具体的文件或者路径呢?

  • 字节缓冲流仅仅提供缓冲区,而真正读写数据还得依靠基本的字节流对象进行操作
//FileOutputStream fos=new FileOutputStream("MyIO:\\fos.txt");
//BufferedOutputStream bos=new BufferedOutputStream(fos);
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("MyIO\\fos.txt"));

bos.write("hello\r\n".getBytes());
bos.write("world\r\n".getBytes());

bos.close();


BufferedInputStream bis =new BufferedInputStream(new FileInputStream("MyIO\\fos.txt"));

int by;
while((by=bis.read())!=-1) {
    System.out.print((char) by);
}

bis.close();

通过四种方式复制视频

public static void main(String[] args) throws IOException {
    //记录开始时间
    long startTime=System.currentTimeMillis();

    //复制视频
    //1.基本字节流一次读写一个字节
    //method1();
    //2.基本字节流一次读写一个字节数组
    //method2();
    //字节缓冲流一次读写一个字节
    //method3();
    //字节缓冲流一次读写一个字节数组
    method4();
    //记录结束时间
    long endTime=System.currentTimeMillis();
    System.out.println("共耗时:"+(endTime-startTime)+"毫秒");
}

public static void method1() throws IOException {
    FileInputStream fis=new FileInputStream("D:\\FileCast\\08.mp4");
    FileOutputStream fos=new FileOutputStream("MyIO\\08.mp4");

    int by;
    while((by=fis.read())!=-1){
        fos.write(by);
    }
    fis.close();
    fos.close();
}

public static void method2() throws IOException{
    FileInputStream fis=new FileInputStream("D:\\FileCast\\08.mp4");
    FileOutputStream fos=new FileOutputStream("MyIO\\08.mp4");

    byte[] bys=new byte[1024];
    int len;
    while((len=fis.read(bys))!=-1){
        fos.write(bys,0,len);
    }
    fis.close();
    fos.close();
}

public static void method3() throws IOException{
    BufferedInputStream bis=new BufferedInputStream(new FileInputStream("D:\\FileCast\\08.mp4"));
    BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("MyIO\\08.mp4"));

    int by;
    while((by=bis.read())!=-1){
        bos.write(by);
    }
    bis.close();
    bos.close();
}

public static void method4() throws IOException{
    BufferedInputStream bis=new BufferedInputStream(new FileInputStream("D:\\FileCast\\08.mp4"));
    BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("MyIO\\08.mp4"));

    byte[] bys=new byte[1024];
    int len;
    while ((len= bis.read(bys))!=-1){
        bos.write(bys,0,len);
    }

    bis.close();
    bos.close();
}

3.字符流

3.1 为什么会出现字符流

由于字节流操作中文不是特别方便,所以Java就提供了字符流

  • 字符流=字节流+编码表

用字节流复制文本时,文本文件也会有中文,但是没有问题,原因时最终底层操作会自动进行字节拼接成中文,如何识别中文?

  • 汉字在存储的时候,无论选择那种编码存储,第一个字节都是负数

3.2 字符串中的编码解码问题

编码:

  • byte[] getBytes():使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中
  • byte[] getBytes(String charsetName):使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中

解码:

  • String(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的String
  • String(byte[] bytes,String charsetName):过使用指定的字符集解码指定的字节数组来构造新的String
String s="中国";
byte[] bys = s.getBytes();//[-28, -72, -83, -27, -101, -67]

//byte[] bys = s.getBytes("UTF-8");//[-28, -72, -83, -27, -101, -67]

//byte[] bys = s.getBytes("GBK");//[-42, -48, -71, -6]

//String ss=new String(bys);

String ss=new String(bys,"UTF-8");//中国
//String ss=new String(bys,"GBK");//涓浗
System.out.println(ss);

3.3 字符流中的编码解码问题

字符流抽象基类

  • Reader:字符输入流的抽象类
  • Writer:字符输出流的抽象类
//FileOutputStream fos=new FileOutputStream("MyIO\\fos.txt");
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("MyIO\\fos.txt"));
osw.write("中国");

osw.close();

InputStreamReader isr=new InputStreamReader(new FileInputStream("MyIO\\fos.txt"));

//一次读取一个字符数据
int ch;
while ((ch=isr.read())!=-1){
    System.out.print((char) ch);
}
isr.close();
posted @   风吹头蛋凉OvO  阅读(62)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示