首页 > 其他分享 >05 IO基础

05 IO基础

时间:2024-11-10 21:19:26浏览次数:4  
标签:文件 字节 05 基础 路径名 IO 字符 序列化 out

目录

1.File类

主要功能

2.IO流——输入与输出

字节流

字符流

示例:字节流读取文件

示例:字符流读取文件

3.缓冲流

1.为啥要学字节缓冲流

2.字节缓冲流

3.字符缓冲流

4.转换流

5.序列化与反序列化

序列化

反序列化

关键点解释

注意事项


1.File类

Java的File类是java.io包中的一个抽象表示形式,用于表示文件或目录路径名。它提供了一系列方法来操作文件系统中的文件和目录,但不涉及文件内容的读写操作。要读写文件内容,通常需要使用其他java.io包下的类,如FileInputStreamFileOutputStream等。

主要功能
  1. 创建文件或目录

    • createNewFile():当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。

    • mkdir():创建此抽象路径名表示的目录。

    • mkdirs():创建此抽象路径名命名的目录,包括所有必需但不存在的父目录。

  2. 删除文件或目录

    • delete():删除此抽象路径名表示的文件或目录。

  3. 检查文件或目录的状态

    • exists():测试此抽象路径名表示的文件或目录是否存在。

    • isDirectory():测试此抽象路径名表示的文件是否为目录。

    • isFile():测试此抽象路径名表示的文件是否为普通文件。

    • canRead():测试应用程序是否可以读取此抽象路径名表示的文件。

    • canWrite():测试应用程序是否可以修改此抽象路径名表示的文件。

    • isHidden():测试此抽象路径名表示的文件是否是一个隐藏文件。

  4. 获取文件或目录的信息

    • length():返回由此抽象路径名表示的文件的长度。

    • lastModified():获取文件最后修改的时间。

    • list():返回一个字符串数组,包含此抽象路径名表示的目录中的文件和子目录的名称。

    • listFiles():返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件和子目录。

  5. 重命名或移动文件

    • renameTo(File dest):将此抽象路径名表示的文件重命名为指定的文件。

  6. 获取文件路径

    • getAbsolutePath():返回此抽象路径名的绝对路径名字符串。

    • getPath():将此抽象路径名转换为一个路径名字符串。

    • getParent():返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回null。

    • getName():返回由此抽象路径名表示的文件或目录的名称。

    public static void main(String[] args) {
        String fileParentPath = "D:\\qxl\\img"; // 真实存在的文件夹路径
        String fileName = "03next.png"; // 真实存在的文件名
​
        String fileParentPathNoExist = "D:\\qxl\\img1"; // 不存在的文件夹路径
        String fileNameNoExist = "03next.png1"; // 不存在的文件名
​
        // 当前工作目录是项目路径,注意多模块下,需要加上模块路径
        System.out.println("当前工作目录(项目路径):" + System.getProperty("user.dir"));
​
        File file = new File(fileParentPath, fileName);
        System.out.println("真实文件是否存在:" +file.exists());
        System.out.println("真实文件名称:" +file.getName());
        // 相对路径没有盘符
        System.out.println("真实文件相对路径:" +file.getPath());
        // 绝对路径盘符开头
        System.out.println("真实文件绝对路径:" +file.getAbsolutePath());
​
        File fileNoExist = new File(fileParentPathNoExist, fileNameNoExist);
        System.out.println("虚假文件是否存在:" +fileNoExist.exists());
        System.out.println("虚假文件名称:" +fileNoExist.getName());
        // 相对路径没有盘符
        System.out.println("虚假文件相对路径:" +fileNoExist.getPath());
        // 绝对路径盘符开头
        System.out.println("虚假文件绝对路径:" +fileNoExist.getAbsolutePath());
​
        try {
            System.out.println("创建已存在的文件:" + file.createNewFile());
            File fileNew = new File(fileParentPath, "03next1.png");
            System.out.println("创建不存在的文件:" + fileNew.createNewFile());
            System.out.println("创建不存在的文件目录+文件:" + fileNoExist.createNewFile());
​
            System.out.println("删除存在的文件:" + fileNew.delete());
            System.out.println("删除存在的空字节文件:" + fileNew.delete());
            System.out.println("删除不存在的文件目录+文件:" + fileNoExist.delete());
​
        } catch (Exception e) {
            System.out.println("创建文件失败:" + e.getMessage()); // 异常信息
        }
    }

注意:

  • 创建File对象的时候,需要传递一个路径,这个路径定为到哪个文件或者文件夹上,我们的File就代表哪个对象

  • createNewFile():当且仅当具有该名称的文件尚不存在时,创建一个新的空文件

    • 如果文件存在,不做操作,返回false

    • 如果文件不存在

      • 路径合法:创建新的空文件

      • 路径不合法:抛出异常信息 -> 系统找不到指定的路径

  • delete():不抛出校验文件路径检查异常信息,在 File 类的内部实现中,有一个私有的 isInvalid 字段,用于标记文件路径是否无效。无效的文件路径进行删除会返回false;正确的情况删除成功返回true且删除对应文件。

2.IO流——输入与输出

File类的createNewFile()方法可以创建空文件,但文件内容的读取写入是以来IO流的。

Java的IO(输入/输出)流是用于处理数据输入和输出的一组类和接口。这些类和接口位于 java.io 包中,提供了丰富的功能来处理文件、网络连接和其他输入输出资源。IO流主要分为两大类:字节流和字符流。

字节流

字节流用于处理二进制数据,如图像、音频文件等。字节流的基本类是 InputStreamOutputStream

  • InputStream:用于从源读取字节。

    • FileInputStream:从文件中读取字节。

    • ByteArrayInputStream:从字节数组中读取字节。

    • BufferedInputStream:带缓冲的输入流,提高读取效率。

    • DataInputStream:可以从输入流中读取基本数据类型。

  • OutputStream:用于向目的地写入字节。

    • FileOutputStream:向文件写入字节。

    • ByteArrayOutputStream:向字节数组写入字节。

    • BufferedOutputStream:带缓冲的输出流,提高写入效率。

    • DataOutputStream:可以向输出流中写入基本数据类型。

字符流

字符流用于处理文本数据,支持字符编码,如UTF-8、GBK等。字符流的基本类是 ReaderWriter

  • Reader:用于从源读取字符。

    • FileReader:从文件中读取字符。

    • StringReader:从字符串中读取字符。

    • BufferedReader:带缓冲的字符输入流,提高读取效率。

    • InputStreamReader:将字节流转换为字符流。

  • Writer:用于向目的地写入字符。

    • FileWriter:向文件写入字符。

    • StringWriter:向字符串写入字符。

    • BufferedWriter:带缓冲的字符输出流,提高写入效率。

    • OutputStreamWriter:将字符流转换为字节流。

示例:字节流读取文件
    public static void main(String[] args) throws IOException {
        File file = new File("test.txt");
        try {
            file.createNewFile();
        } catch (IOException e) {
            System.out.println("创建文件失败");
        }
        System.out.println(file.getAbsolutePath());
​
        // 将文件读取成输入字节流
        FileInputStream inputStream = new FileInputStream(file);
​
        // 输入字节流将读取的文件写入指定位置
        FileOutputStream outputStream = new FileOutputStream("test2.txt");
​
        byte[] buffer = new byte[1024];
        int byteRead;
        // 读取字节流
        while ((byteRead = inputStream.read(buffer))!= -1) {
            for(int i = 0; i < byteRead; i++) {
                outputStream.write(buffer[i]);
            }
        }
        outputStream.close();
        inputStream.close();
    }

注意:

  • test.txt是一个字符文件,使用字节流读取时没有指定编码,结果会乱码。处理乱码:

    • 使用字符流:字符流(如 FileReaderFileWriter)会自动处理字符编码问题。你可以指定字符编码,确保读取和写入时使用相同的编码。

    • 使用 InputStreamReaderOutputStreamWriter:这些类可以将字节流转换为字符流,并允许你指定字符编码。

  • 读取到文件末尾的判定条件:inputStream.read()方法规定,如果读到了文件的结束标记,方法直接返回-1

  • inputStream.read()读取字节是一个一个读取的,read()方法也可以接收一个带有长度的字节数组参数,进行批量读取

示例:字符流读取文件
public class CharStreamExample {
    public static void main(String[] args) {
        BufferedReader br = null;
        FileWriter fw = null;
​
        try {
            // 创建输入流和输出流
            br = new BufferedReader(new FileReader("input.txt"));
            fw = new FileWriter("output.txt");
​
            String line;
            // 读取并写入字符
            while ((line = br.readLine()) != null) {
                fw.write(line);
                fw.write(System.lineSeparator()); // 写入换行符
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (br != null) br.close();
                if (fw != null) fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

3.缓冲流

1.为啥要学字节缓冲流

之前所写的FileOutputStream,FileInputStream,FileReader,FileWriter这都叫做基本类,其中FileInputStream和FileOutputStream的读写方法都是本地方法(方法声明上带native),本地方法是和系统以及硬盘打交道的,也就是说这两个对象的读和写都是在硬盘之间进行读写的,效率不高;缓冲流中底层带一个长度为8192的数组(缓冲区),此时读和写都是在内存中完成的(在缓冲区之间完成),内存中的读写效率非常高 使用之前需要将基本流包装成缓冲流,其实就new对象时,传递基本流

2.字节缓冲流

a.BufferedOutputStream:字节缓冲输出流 构造:BufferedOutputStream(OutputStream out) 使用:和FileOutputStream一样 b.BufferedInputStream:字节缓冲输入流 构造:BufferedInputStream(InputStream in) 使用:和FileInputStream一样

3.字符缓冲流

a.BufferedWriter:字符缓冲输出流

构造:BufferedWriter(Writer w) 使用:和FileWriter一样 特有方法:newLine() 换行

b.BufferdReader:字符缓冲输入流

构造:BufferedReader(Reader r)

使用:和FileReader一样

特有方法:String readLine(),一次读一行,读到结尾返回null

4.转换流

想要不乱码,编码和解码遵循的规则(字符编码)要一致

想要不乱码,最重要的是先知道这个字符按照什么编码去存的 UTF-8中一个汉字占3个字节 GBK中一个汉字占2个字节

  • 字节流通向字符流的桥梁 -> 读数据:

构造:InputStreamReader(InputStream in,String charsetName),charsetName:指定编码,不区分大小写 作用: 可以直接指定编码,按照指定的编码去读内容 用法:基本用法和FileReader一样

  • 字符流通向字节流的桥梁 -> 写数据:

    构造:OutputStreamWriter(OutputStream out,String charsetName)

    作用:按照指定的编码规则去存数据 用法:和FileWriter一样

5.序列化与反序列化

序列化(Serialization)和反序列化(Deserialization)是将对象的状态保存到文件或内存中,以及从文件或内存中恢复对象状态的过程。序列化通常用于在网络传输、持久化存储和对象复制等场景中。

示例代码

序列化
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
​
class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private String name;
    private int age;
​
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
​
    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }
}
​
public class SerializationExample {
    public static void main(String[] args) {
        Person person = new Person("John Doe", 30);
​
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"))) {
            oos.writeObject(person);
            System.out.println("对象已序列化到文件 person.ser");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
反序列化
import java.io.FileInputStream;
import java.io.ObjectInputStream;
​
public class DeserializationExample {
    public static void main(String[] args) {
        Person person = null;
​
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser"))) {
            person = (Person) ois.readObject();
            System.out.println("对象已反序列化: " + person);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
关键点解释
  1. 实现 Serializable 接口

    • Person 类实现了 Serializable 接口,表示该类的对象可以被序列化。

    • serialVersionUID 是一个版本控制字段,用于确保序列化和反序列化时类的版本一致性。

  2. 序列化过程

    • 创建一个 ObjectOutputStream 对象,将其包装在一个 FileOutputStream 对象中。

    • 调用 writeObject 方法将对象写入文件。

  3. 反序列化过程

    • 创建一个 ObjectInputStream 对象,将其包装在一个 FileInputStream 对象中。

    • 调用 readObject 方法从文件中读取对象,并将其强制转换回原来的类类型。

注意事项
  1. transient 关键字

    • 如果你不希望某个字段被序列化,可以使用 transient

      private transient int secret;
  2. 自定义序列化

    • 你可以通过实现writeObject()和readObject()方法来自定义序列化和反序列化过程。例如:

      private void writeObject(ObjectOutputStream out) throws IOException {
          out.defaultWriteObject();
          out.writeInt(secret);
      }
      ​
      private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
          in.defaultReadObject();
          secret = in.readInt();
      }
  3. 序列化版本控制

    • serialVersionUID 字段用于版本控制。如果你更改了类的结构(例如添加或删除字段),但希望旧版本的序列化数据仍然可以被正确反序列化,可以通过显式设置 serialVersionUID 来实现。

  4. 安全性

    • 序列化和反序列化过程中可能存在安全风险,特别是当处理不受信任的数据时。建议对反序列化的数据进行严格的验证。

标签:文件,字节,05,基础,路径名,IO,字符,序列化,out
From: https://blog.csdn.net/Elaine2391/article/details/143594850

相关文章

  • 04集合基础-哈希表
    目录1.集合类的线程安全实现1.同步包装器(SynchronizedWrappers)保证线程安全的方式2.并发集合类(ConcurrentCollections)常见的并发集合类保证线程安全的方式3.不可变集合(ImmutableCollections)2.哈希表1.高效的查找、插入和删除操作2.减少内存占用3.支持唯一......
  • DataStudio连接opengauss报错Invalid username/password,login denied
    1、具体现象2、解决办法(1)密码不正确如果不确认密码是否正确可以重新修改密码,并进行gsql连接测试(2)修改参数确认密码正确,服务端可以正常连接,检查pg_hba.conf配置文件vim/opt/opengauss/data/single_node/ph_hba.conf此规则采用md5方式对密码加密两种解决方式:一种是......
  • 第一章 ECMAScript6 基础
    学习目标1.1ECMAScript6介绍1.1.1ECMAScript的概念1.1.2各浏览器对ES6的支持1.1.3ES6转码ES5支持老版浏览器1.2let与const命令1.2.1let命令1.2.2const命令1.3变量的解构赋值1.3.1数组解构赋值1.3.2对象解构赋值1.3.3字符串解构赋值1.3.4函数参数解构赋值......
  • 2024-2025-1 20241406刘书含《计算机基础与程序设计》第七周学习总结
    作业信息作业课程 2024-2025-1-计算机基础与程序设计作业要求 2024-2025-1计算机基础与程序设计第七周作业作业目标 数组与链表,基于数组和基于链表实现数据结构,无序表与有序表,树,图,子程序与参数作业正文 2024-2025-120241328《计算机基础与程序设计》第七周学习总结教材学习......
  • 2024-2025-1 20241408陈烨南《计算机基础与程序设计》第七周学习总结
    这个作业属于哪个课程2024-2025-1-计算机基础与程序设计)这个作业要求在哪里https://www.cnblogs.com/rocedu/p/9577842.html#WEEK07这个作业的目标数组与链表、基于数组和基于链表实现数据结构、无序表与有序表、树、图、子程序与参数作业正文本博客链接教......
  • 使用Visual Studio Code 快速新建Net项目
    前言最近,总是听大家说VisualStudioCode写后端代码非常好用,蓝后,就自己亲身体验了一下,还是很香的。正文1.首先需要安装DotnetSDK,我这里安装的8.0版本,如下图:2.安装完DotNetSDK,就可以使用命令创建控制台应用了,如下图:3.新建的控制台应用如下图,有一......
  • MissingServletRequestParameterException(Required String parameter ‘code‘ is not
    文章目录1、控制台2、ExceptionHandle3、anti-counterfeiting.js4、AntiFakeController5、解决方案方案一:修改前端请求格式方案二:拼接URL参数(适用于`GET`请求或带参数的`POST`请求)方案三:后端改用`@RequestBody`总结1、控制台2024-11-0614:45:40.557ERROR......
  • 单调栈基础模板
    #include<bits/stdc++.h>usingnamespacestd;constintN=1000005;intn,ansl[N],ansr[N],a[N];intf[N],r,x;intmain(){cin>>n;for(inti=0;i<n;i++)cin>>a[i],ansl[i]=ansr[i]=-1;for(inti=0;i<n;i++){......
  • 黑马PM- B端产品-B端基础知识
    什么是B端产品B端产品市场介绍B端产品常见分类B端与C端产品区别供应链简介......
  • C++中string字符串的基础操作,学习
    string字符串常用函数substring()string.length()&&string.size()string.find()string.replace()string.substr()string初始化和声明#include<bits/stdc++.h>usingnamespacestd; intmain(){stringstr1;//空字符串stringstr2="hello,w......