当前位置: 首页 > news >正文

File和IO

元数据与文件读写

Java 的 File 表示文件的元数据。元数据是什么?元数据就是描述数据的数据。文件的元数据就是文件名、文件大小、文件路径等信息。

要读写文件内容,需要用到 Java 的 IO 流,而 IO 流需要提供 File 对象。

File 的常用方法

File 的构造方法需要提供文件的路径,支持绝对路径、相对路径以及网络路径,不过这个路径可以不存在。

  • boolean exists():判断传入的路径是否对应一个真实存在的文件
    • 如果不存在则可以新建文件
      • boolean createNewFile(),新建文件也只会创建文件,文件可以没有后缀
      • boolean mkdir(),创建单级目录
      • boolean mkdirs(),创建多级目录
    • 如果文件存在,可以判断是文件夹还是文件,如果文件不存在则这两个方法都返回 false
      • boolean isFile()
      • boolean isDirectory()
  • 获取文件信息
    • String getAbsolutePath(),返回文件的绝对路径
    • String getPath(),返回构造方法中传入的路径
    • String getParent(),返回父级路径字符串
    • File getParentFile(),返回父级路径 File 对象
    • String getName(),返回文件夹名称、文件名(有后缀带后缀)
    • long length(),返回文件的大小(字节),如果是文件夹也有返回值但是不正确
    • long lastModified():最近修改的时刻
  • 文件权限相关
    • boolean canRead()
    • boolean canWrite()
    • boolean isHidden()
  • list,如果 File 对象不存在、File 对象不是文件夹、File 对象需要的权限不足返回 null,否则返回文件夹下的所有文件(如果是空文件夹则返回一个空数组)
    • String[] list()
    • File[] listFiles()
  • 危险操作
    • boolean delete(),删除文件和空目录,不走回收站
    • boolean renameTo(File dest),重命名或者移动文件,原文件不会保留

基础 IO 流

基础 IO 流可以分成字节流、字符流、输入流和输出流。两两组合就得到了四种搭配:

  • 字节输入流:InputStream

    • int read():每次读取一个字节,取值在 [0, 255] 区间,读完返回 -1。

    • int read(byte[] b) : 读取是尽量将数组填满,返回实际读取的字节数,读完返回-1。

    • int read(byte[] b, int off, int len):跟上一个方法一样,只不过加了一个偏移量,返回实际读取的字节数,读完返回-1。

    • void close()

  • 字节输出流:OutputStream

    • void write(int b):每次写一个字节

    • void write(byte[] b):一个字节一个字节写效率太低,每次写一整组的字节数据

    • void write(byte[] b, int off, int len)

    • void flush()

    • void close()

  • 字符输入流:Reader

    • int read()

    • int read(char[] cbuf)

    • int read(char[] cbuf, int off, int len)

    • void close()

  • 字符输出流:Writer

    • 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 flush()

    • void close()

InputStream、OutputStream、Reader、Writer 都是抽象类,都实现了 Closeable 接口,输出流额外实现了 Flushable 接口。

字符流拥有一个长度为 8192 的字节数组缓冲区,充当了内存的作用,Java 程序先将数据读入缓冲区之后每次再到缓冲区中读,写数据的时候先将数据写到缓冲区中,缓冲区写满了就刷盘。输出流的 flush 方法可以主动将缓冲区的数据刷盘。

拷贝文件的示例代码如下,InputStream、OutputStream、Reader、Writer 都是抽象类,需要用到实现类 FileInputStream、FileOutputStream、FileReader、FileWriter。

public void test() throws IOException { File source = new File("C:\\Users\\admin\\Downloads\\python.md"); File dest = new File("C:\\Users\\admin\\Documents\\python.md"); FileInputStream fis = new FileInputStream(source); // 输出流的append参数表示是追加写还是覆盖写,默认是false也就是覆盖写 FileOutputStream fos = new FileOutputStream(dest, true); int res; while (true) { res = fis.read(); if (res == -1) break; fos.write(res); } fos.close(); fis.close(); }

不基础 IO 流

1.缓冲流

BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter,需要传入基础 IO 流对象。

字节缓冲流新增了长度为 8192 的字节数组;而字符缓冲流的缓冲区从长度为 8192 的字节数组升级成了字符数据,长度不变。

字符缓冲流新增了两个方法:

  • String readLine():一次读取一行,遇到换行符结束,读完返回 null
  • void newLine():换行

这两个方法可以区分不同操作系统的换行符。

2.序列化流

将 Java 对象转成字节数组,可以在不同设备之间进行传输。

  • 只有字节流,没有字符流
  • Java 对象所属的类必须实现 Serializable 接口,这是一个标记性空接口,里面没有抽象方法
  • 固定 private static final long serialVersionUID 属性
    • private,外部不可见
    • static,版本号是跟类相关的属性,跟对象没关系
    • final,常量不可二次修改
    • long serialVersionUID,按英语的说法是固定搭配

如果某个属性不想被序列化,可以用 transient 瞬态关键字修饰,反序列化后得到的值是 0 或 null。

public void test() throws IOException, ClassNotFoundException { File file = new File("C:\\Users\\admin\\Documents\\1.txt"); String str = "1234"; // 序列化:将Java对象转成字节数据 FileOutputStream fos = new FileOutputStream(file); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(str); oos.close(); // 反序列化:将字节数据转成Java对象 FileInputStream fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis); String s = (String) ois.readObject(); ois.close(); // 只关序列化流就可以了,像这些需要传入IO流对象的实例对象在调用close方法时会自动将传入的IO流对象一起关闭 System.out.println(s); }

在我们之前学习的 IO 流中,会返回 -1,返回 null 表示读完了。

但是序列化流不会进行提醒,如果写入了 10 个对象,但是进行了 11 次读取操作就会直接报错,非常粗暴。

比较好的做法是将实例对象存入集合中,然后将集合对象序列化。

3.打印流

打印流可以做到原样输出,在方法中传递什么参数,就直接输出到文件中。如果传入的是一个对象,将这个对象的 toString 方法的返回值输出到文件中。

打印流的特点是只支持输出流:PrintStream、PrintWriter。

  • void print()
  • void println()
  • void printf(String format, Object... args),跟 C 语言的 printf 用法差不多

4.转换流

InputStreamReader:字节输入流 -> 字符输入流,传入 InputStream,但是能调用字符流的方法

  • InputStreamReader(InputStream in)

  • InputStreamReader(InputStream in, String charsetName)

OutputStreamWriter:字节输出流 -> 字符输出流,传入 OutputStream,但是能调用字符流的方法

  • OutputStreamWriter(OutputStream in)

  • OutputStreamWriter(OutputStream in, String charsetName)

将 UTF8 编码的文件读取到程序中,用 GBK 编码写入到新文件中。

public static void main(String[] args) throws IOException { InputStreamReader isr = new InputStreamReader(new FileInputStream("C:\\Users\\admin\\Downloads\\1.txt"), "UTF8"); OutputStreamWriter isw = new OutputStreamWriter(new FileOutputStream("C:\\Users\\admin\\Downloads\\2.txt"), "GBK"); char[] arr = new char[256]; int len = 0; while ((len = isr.read(arr)) != -1) { System.out.println(new String(arr, 0, len)); isw.write(arr, 0, len); } isw.close(); isr.close(); }

Unicode 码点

ASCII 码:英文标点符号,一个字节就可以表示。

GBK:1 英2 中,兼容 ASCII 码,英文用一个字节表示,中文用两个字节表示。

Unicode:Unicode 是一个字符集,它为世界上所有字符分配了唯一的编号,这个编号就叫码点。但是,Unicode 并未规定这些字符如何保存和传输,需要具体的编码方式来实现。

UTF-8:Unicode 的一种变长编码方式,可以用 1 到 4 个字节来保存字符,1 英 3 中。

这个时候我想到了 Java 里面的 char 类型,char 可以用来表示中文,但是 char 类型只占用两个字节,这是怎么做到的呢?

其实 char 类型保存的是字符的码点这个唯一编号,并不是保存字符实际的编码,如果一个字符的码点无法用 16bit 表示,就无法用 char 类型存储。

平时我们可以用 char 来表示中文,是因为这些字符的码点可以用两个字节表示,但是有些字符不能,如 emoji 表情。

𠮷 是一个生僻字,就无法用一个 char 表示,需要用 String 表示。

因为 𠮷 要用两个 char 表示,所以 String 的 length 方法返回的是 2,也就是 String 中 char 的个数。

如果想真正统计字符串中有多少个字符,需要用 String 提供的 codePointCount 方法。

http://www.gsyq.cn/news/1610815.html

相关文章:

  • 与你的 Elasticsearch 数据对话:使用 Google ADK 和 MCP 构建一个实时语音 agent ,分为 3 个组件
  • C#工业视觉实战:集成工业相机与YOLOv8实现缺陷检测系统
  • Dify平台大模型接入实战:从云端API到本地部署全流程指南
  • 探索兴趣爱好的内涵
  • Postman便携版终极指南:Windows用户的免安装API开发解决方案
  • 48.可直接落地!IEC61131-3 ST 完整源码|PLC 物料分拣 + PID 调速 + Modbus 通信
  • SH9递归对抗驱动的活系统:九层架构理论体系深度研究报告(世毫九实验室原创研究)
  • 零基础入门MySQL数据分析:从SQL语法到电商实战项目
  • 洛谷 P2024:[NOI2001] 食物链 ← 扩展域并查集
  • 35款自动脱壳工具合集:逆向工程中的“开罐器”与“手术刀”
  • 只会写业务 UI 走不远!吃透这套 Framework 体系,跳槽大厂拉开薪资差距
  • 什么!翻译论文还要消耗token? 关于如何提升marker转英文文档速度,并使用skill批量翻译论文
  • openEuler-portal-mcp智能推荐系统:如何实现100%工具推荐覆盖率
  • Apache Commons Text RCE漏洞CVE-2022-42889:原理、复现与安全修复
  • Kali Linux 渗透测试环境搭建:VMware 虚拟机安装配置全流程指南
  • YOLOv8知识蒸馏实战:从37%到42%mAP,无损提升轻量模型精度
  • C语言指针详解3
  • 工作原理:其核心是一个两步过程。
  • Mineradio音乐播放器下载安装地址
  • 机顶盒B860AV2.1-M刷机攻略
  • 从 ABAP 后端到 AEX,Local Integration Engine 下的 Business System 配置全景
  • AI渐进编程之四:状态机如何约束 AI 的动作?
  • 【SI_GMSL2】深入了解示波器测试GMSL2眼图
  • openclaw 0512版本部署(ubuntu 26.04)
  • 怎么用一张图做产品视频?用 seedance2.0 快速生成 360 度动态视频实战教程
  • DAY 2 TIM定时器
  • 对称加密算法的扩散层(P盒)密码学指标详细介绍
  • 深入解析Hermes Agent:从Skill驱动架构到实战部署的AI Agent框架指南
  • 嵌入式音频开发实战:AU-60 全功能 DSP 语音模组一站式开发指南
  • 3个突破性技巧:如何用SRWE实现Windows窗口的实时魔法编辑