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

Java的IO流(一)

目录

Java的IO流(一)

前置小知识

分隔符

父路径

File类

File类介绍

File类中的静态成员

File类的构造方法

File类对象相关获取方法

File类创建文件的方法

File类删除文件方法

File类的判断方法

File类的遍历方法

File类练习

IO流分类

字节流

字节输出流

字节输入流

字节流与文件的复制

字符流

字节流读取中文问题

字符流介绍

字符输出流

字符输入流

IO异常处理方式


Java的IO流(一)

前置小知识

分隔符

分隔符一共分为两种:

  1. 路径名称分隔符:在路径中用于分隔文件或者文件夹,在Windows下使用\表示,在Linux下使用/表示
  2. 路径分隔符:多个路径之间的分隔,一般使用;表示
在Windows下也可以使用 /表示路径名称分隔符,但是系统默认的路径名称分隔符为 \

父路径

例如,在路径中:E:\Test\test\test.jpg

test.jpg的父路径即为E:\Test\test,对于test文件夹来说,其父路径为E:\Test,以此类推

File

File类介绍

File类在官方文档中的描述是:文件和目录(文件夹)路径名的抽象表示

本意是:File类的对象存储着文件或者目录的路径

File类中的静态成员

对于文件/文件夹的操作经常会使用到路径,其中避免不了出现分隔符,而对于「分隔符」来说,不同的系统有不同的分隔符,所以Java为了确保代码的通用性,提供了两个针对分隔符的静态变量,如下:

  1. static String pathSeparator:与系统有关的默认路径名称分隔符,在Windows下值为\,在Linux下值为/
  2. static String separator:与系统有关的默认路径分隔符,在Windows下值为;

File类的构造方法

File类中常用有三种构造方法:

  1. File(String parent, String child):根据子路径和父路径一起确定一个完整的路径,使用此构造方法后,实例化的对象中存储的是一个结合父路径和子路径一体的完整路径
  2. File(File parent, String child):与第一个构造方法作用相同,不同的是,此构造方法的父路径是File对象引用
  3. File(String pathname):参数直接填入文件的完整路径
File类对象不会检查路径是否是真实存在的路径,所以理论上上面三个构造方法中的路径可以随便写,但是没有意义

如果在路径中不使用Java提供的分隔符常量,注意 \需要使用 \\进行转义

基本实例代码如下:

public class Test {public static void main(String[] args) {// 1. File(String parent, String child)File file1 = new File("D:\\", "a.txt");System.out.println(file1);// 2. File(File parent, String child)File file2 = new File("D:\\");File file3 = new File(file2, "a.txt");System.out.println(file3);// 3. File(String pathname)File file4 = new File("D:\\a.txt");System.out.println(file4);}
}输出结果:
D:\a.txt
D:\a.txt
D:\a.txt

File类对象相关获取方法

File类创建完对象后,如果想获取到该对象中的一些内容,可以使用下面File类的常用方法获取指定的内容:

  1. String getAbsolutePath():获取File类对象中文件路径的绝对路径(从根目录开始的路径)
  2. String getPath():获取File类对象中的值
  3. String getName():获取到File类对象中文件路径对应的文件/文件夹
  4. long length():获取到File对象中文件路径对应的文件大小,以字节为单位

基本使用如下:

public class Test01 {public static void main(String[] args) {File file = new File("D:\\", "a.txt");// 1. String getAbsolutePath()System.out.println(file.getAbsoluteFile());// 2. String getPath()File file1 = new File("D:\\a.txt");System.out.println(file1.getPath());new File("./a.txt");System.out.println(file1.getPath());// 3. String getName()File file2 = new File("D:\\test");System.out.println(file2.getName());File file3 = new File("D:\\test\\a.txt");System.out.println(file3.getName());// 4. long length()File file4 = new File(".\\a.txt");System.out.println(file4.length());}
}

在上面的代码中,需要注意最后一个方法,因为当前a.txt文件中没有任何内容,所以输出file4对象对应文件的大小为0,此处一般获取到的length与文件属性中的文件大小保持一致

如果指定的文件不存在,则计算文件大小的方法也会返回0
在IDEA中,使用 ./代表的当前路径为模块所在路径,即「项目文件夹」中

File类创建文件的方法

当需要使用File类对象在对象路径位置创建文件/文件夹时,可以使用下面的两个方法:

  1. boolean createNewFile():在File对象路径下创建一个文件,如果文件已经存在,则创建失败,否则创建成功
  2. boolean mkdirs():在File对象路径下创建一个文件夹,如果文件夹已经存在,则创建失败,否则创建成功;本方法可以一次创建多级文件夹
上面两个方法在使用时必须要在路径中指定创建的文件/文件夹名

需要注意,上面两个方法都会抛出异常

基本使用如下:

public class Test02 {public static void main(String[] args) throws IOException {File file = new File(".\\b.txt");// 1. boolean createNewFile()System.out.println(file.createNewFile());// 2. boolean mkdirs()File file1 = new File(".\\test\\test1");System.out.println(file1.mkdirs());}
}

在上面的代码中,对于createNewFile来说,会在项目文件夹中创建一个名为b.txt的文件;对于mkdirs方法来说,会在项目文件夹中创建一个名为test的文件夹,并且因为test后面依旧还有文件夹,所以会在test文件夹中继续创建新的名为test1的文件夹

File类删除文件方法

在Java中,如果想要删除文件/文件夹时,可以使用:boolean delete(),如果删除成功,返回true,否则返回false

需要注意,删除文件夹时必须确保文件夹为空,否则删除失败
使用该方法删除的文件/文件夹不会存在于系统回收站中

基本使用如下:

public class Test03 {public static void main(String[] args) {File file = new File("./b.txt");System.out.println(file.delete());File file1 = new File("./test/test1");System.out.println(file1.delete());}
}

File类的判断方法

在Java中,判断文件类型或者文件是否存在可以使用下面的方法:

  1. boolean isDirectory():判断File对象中的路径的文件是否是文件夹,如果不是返回false,否则返回true
  2. boolean isFile():判断File对象中的路径的文件是否是文件,如果不是返回false,否则返回true
  3. boolean exists():判断File对象中的路径的文件是否存在,如果不存在返回false,否则返回true

基本使用如下:

public class Test04 {public static void main(String[] args) {File file = new File("./b.txt");System.out.println(file.exists());System.out.println(file.isDirectory());System.out.println(file.isFile());}
}

File类的遍历方法

当需要一次拿到多个文件的名称时,可以使用下面的方法:

  1. String[] list():遍历指定的文件夹,将读取到的文件名称存储到String数组中
  2. File[] listFiles():遍历指定的文件夹,将读取到的文件名称存储到File数组中
list方法遍历结果只会显示 File类对象路径下文件的文件名,但是 listFiles会显示 File类对象路径+内部文件的文件名

需要注意,两个方法在遍历到 File类对象路径下的文件夹时不会进入对应的文件夹

基本使用如下:

public class Test05 {public static void main(String[] args) {File file = new File("./test/test1");// 1. String[] list()String[] list = file.list();for (String s : list) {System.out.println(s);}// 2. File[] listFiles()File[] files = file.listFiles();for (File f : files) {System.out.println(f);}}
}

一般推荐使用listFiles方法,因为返回的是File类对象,之后的操作会更加方便

File类练习

遍历当前项目文件夹下的test文件夹中所有txt文件,如果存在子文件夹,遍历子文件夹中所有txt文件,以此类推,直到不存在txt文件

思路:

  1. 创建File类对象指定路径
  2. 调用listFiles方法获取到当前路径下的所有文件
  3. 判断是否是文件,其次判断其文件名称是否以.txt结尾,如果是,打印出文件名,如果不是,判断是否是文件夹,时文件夹继续遍历,重复第三步
对于第三步来说,可以考虑使用递归的方式,因为文件目录本质还是树结构

参考代码:

public class Test06 {public static void main(String[] args) {File file = new File("./test/test1");File[] files = file.listFiles();isTxt(files);}private static void isTxt(File[] file) {for (File file1 : file) {if (file1.isFile()) {if (file1.getName().endsWith(".txt")) {System.out.println(file1);}} else {isTxt(file1.listFiles());}}}
}

IO流分类

在Java中,IO流有两种分类:

  1. 字节流:可以理解为「万用流」,因为一切均文件
  2. 字符流:针对于文本文件

字节流有两个对应的流:

  1. 字节输出流:对应OutputStream抽象类
  2. 字节输入流:对应InputStream抽象类

字符流有两个对应的流:

  1. 字符输出流:对应Writer抽象类
  2. 字符输入流:对应Reader抽象类

字节流

在Java中,字节流两个抽象流:

  1. 字节输出流:对应OutputStream抽象类
  2. 字节输入流:对应InputStream抽象类

字节输出流

OutputStream抽象类的子类是FileOutputStream

构造方法如下:

  1. FileOutputStream(File file) :通过File类对象创建FileOutputStream对象
  2. FileOutputStream(String name):通过文件路径字符串创建FileOutputStream对象
需要注意,上面两个构造方法都会抛出异常

基本使用如下:

public class Test {public static void main(String[] args) throws FileNotFoundException {File file = new File("./a.txt");// 1. FileOutputStream(File file) :通过File类对象创建FileOutputStream对象FileOutputStream outputStream = new FileOutputStream(file);// 2. FileOutputStream(String name):通过文件路径字符串创建FileOutputStream对象FileOutputStream outputStream1 = new FileOutputStream("./b.txt");}
}

字节输出流的特点:

  1. 如果指定的文件不存在就会创建新文件,否则就在指定的文件中写
  2. 默认覆盖写,如果原来文件中有内容,再次写就会覆盖原始的内容

字节输出流常用方法:

  1. void write(int b):每一次写一个字节的数据,参数为写入内容的码值
  2. void write(byte[] b):每一次写一个字节数组中的数据,参数为写入内容的码值数组
  3. void write(byte[] b, int off, int len):每一次写一个字节数组中的部分数据,第一个参数为写入内容的码值数组,第二个参数为第一个写入的内容对应的下标,第三个参数为指定数组的元素个数
  4. void close():关闭输出流

基本使用如下:

public class Test01 {public static void main(String[] args) throws IOException {FileOutputStream outputStream = new FileOutputStream("./a.txt");outputStream.write(97);byte[] bytes = {98, 99, 100, 101, 102};outputStream.write(bytes);outputStream.write(bytes, 1, 3);outputStream.close();}
}
需要注意,如果使用了 close方法关闭了当前输出流,就不可以再调用当前输出流对象,否则编译报错

如果需要追加写,则可以使用:FileOutputStream(String name, boolean append)创建字节输出流对象,其中第二个参数此时需要为true

如果写的内容需要换行,则可以在写的内容中添加换行符:

public class Test03 {public static void main(String[] args) throws IOException {File file = new File("./a.txt");FileOutputStream outputStream = new FileOutputStream(file, true);outputStream.write("Hello\n".getBytes());outputStream.write("World\n".getBytes());outputStream.close();}
}

字节输入流

InputStream抽象类的子类是FileInputStream

构造方法如下:

  1. FileInputStream(File file) :通过File类对象创建FileInputStream对象
  2. FileINputStream(String name):通过文件路径字符串创建FileINputStream对象
需要注意,上面两个构造方法都会抛出异常

使用方法同字节输出流

字节输入流的特点:如果指定的文件不存在就会打开失败抛出异常,否则就在指定的文件中读取

字节输入流的常见方法:

  1. int read():从指定文件中一次读取一个字节的数据,返回读取到的字节
  2. int read(byte[] b):从指定文件中一次读取n个字节的数据,n由参数数组大小决定,返回读取到的字节个数
  3. int read(byte[] b, int off, int len):从指定文件中一次读取n个字节中的部分数据,n由数组大小决定,第一个参数代表存储读取内容的数组,第二个参数为第一个读取的内容,第三个参数为字节个数。方法返回读取到的字节个数
  4. void close():关闭字节输入流
需要注意:

如果读取文件内容的过程中,一个流在读取的过程中会按照文件内容顺序读取,每一次读取的位置为上一次读取的结束位置,已经读到文件内容的结尾,此时三个 read方法都会返回-1。

如果使用了 close方法关闭了当前输出流,就不可以再调用当前输出流对象,否则编译报错
  • 一次读取一个字节
public class Test04 {public static void main(String[] args) throws IOException {File file = new File("./a.txt");FileInputStream fileInputStream = new FileInputStream(file);int read = fileInputStream.read();System.out.println((char)read);int read1 = fileInputStream.read();System.out.println((char)read1);int read2 = fileInputStream.read();System.out.println((char)read2);fileInputStream.close();}
}
  • 一次读取n个字节
public class Test04 {public static void main(String[] args) throws IOException {File file = new File("./a.txt");FileInputStream fileInputStream = new FileInputStream(file);byte[] bytes = new byte[2];while (fileInputStream.read(bytes) != -1) {System.out.println(new String(bytes));}}
}

上面的代码需要注意,如果文件中的内容只有5个字节,则在最后一次读取的过程中因为只读取到一个字节的数据,所以只会覆盖字节数组中第一个元素的位置,此时会出现打印结果与文件实际内容不一致的情况,可以考虑修改方法:因为read方法会返回读取到的字节个数,所以可以通过该字节个数控制bytes数组每次转换为字符串的个数

public class Test04 {public static void main(String[] args) throws IOException {File file = new File("./a.txt");FileInputStream fileInputStream = new FileInputStream(file);byte[] bytes = new byte[2];int len = 0;while ((len = fileInputStream.read(bytes)) != -1) {System.out.println(new String(bytes,0, len));}fileInputStream.close();}
}

对于「一次读取n个字节中的部分数据」方法来说,在实际开发中并不常用,因为读取部分数据可能导致数据读取不全造成的问题,所以不做演示

字节流与文件的复制

文件的复制本质是将文件输入到内存中,再从内存输出到硬盘中,并且因为文件都是字节组成的,所以可以考虑字节流,步骤如下:

  1. 通过字节输入流打开指定文件
  2. 依次读取文件内容写到指定位置
整个过程中需要注意:

输出位置必须指明文件保存的名字,否则会导致无法找到文件
为了确保写入的都是有效数据,可以使用写入部分数据的 write方法
因为创建了字节输入流和字节输出流对象,所以需要关闭两个流,但是需要满足先开流后关

示例代码:

public class Test05 {public static void main(String[] args) throws IOException {File file_in = new File("./1.mp3");FileInputStream fileInputStream = new FileInputStream(file_in);File file_out = new File("./1-copy.mp3");FileOutputStream outputStream = new FileOutputStream(file_out);byte[] bytes = new byte[1024];int len = 0;while ((len = fileInputStream.read(bytes)) != -1) {outputStream.write(bytes, 0, len);}outputStream.close();fileInputStream.close();}
}

字符流

字节流读取中文问题

使用字节流读取文本内容需要确保读取的字节个数是对应编码中的一个字符占用的字节个数

在UTF-8中,中文占3个字节,在GBK中,中文占2个字节,如果数组的长度为2,一次读取两个字节的数据,在GBK编码下就不会发生问题,但是如果是UTF-8就会出现读取的字节不全导致解码出现问题,从而乱码

下面的代码不论是GBK还是UTF-8都会出现读取中文乱码问题

public class Test {public static void main(String[] args) throws IOException {File file = new File("./b.txt");FileInputStream fileInputStream = new FileInputStream(file);byte[] bytes = new byte[1];int len = 0;while ((len = fileInputStream.read(bytes)) != -1) {System.out.println(new String(bytes, 0, len));}}
}

字符流介绍

字符流有两个对应的流:

  1. 字符输出流:对应Writer抽象类
  2. 字符输入流:对应Reader抽象类

字符输出流

Writer抽象类的子类是FileWriter

构造方法如下:

  1. FileWriter(File file):使用File对象构造FileWriter对象
  2. FileWriter(String fileName):使用文件路径构造FileWriter对象
  3. FileWriter(String fileName, boolean append):通过文件路径和是否追加构造FileWriter对象

基本使用:

public class Test01 {public static void main(String[] args) throws IOException {File file = new File("./a.txt");// 1. FileWriter(File file):使用File对象构造FileWriter对象FileWriter fileWriter = new FileWriter(file);// 2. FileWriter(String fileName):使用文件路径构造FileWriter对象FileWriter fileWriter1 = new FileWriter("./a.txt");// 3. FileWriter(String fileName, boolean append):通过文件路径和是否追加构造FileWriter对象FileWriter fileWriter2 = new FileWriter("./a.txt", true);}
}

字符输出流的特点(与字节输出流一样):

  1. 如果指定的文件不存在就会创建新文件,否则就在指定的文件中写
  2. 默认覆盖写,如果原来文件中有内容,再次写就会覆盖原始的内容

常用方法如下:

  1. void write(int c):向文本文件中写入一个字符
  2. void write(char[] cbuf):向文本文件写一串字符
  3. void write(char[] cbuf, int off, int len):向文本文件写一串字符的一部分,第一个参数代表待写入的字符数组,第二个参数为第一个写入的字符对应的下标,第三个参数为数组的元素个数
  4. void write(String str):向文本文件写一个字符串
  5. void flush():刷新输出流缓冲区
  6. void close():关闭字符输出流
需要注意第五个方法和第六个方法:使用 flush方法和 close都可以将字符输出缓冲区的内容输出到文本文件中,但是 flush刷新后,当前输出流对象依旧可以使用,但是 close执行后,对应的输出流对象不可以再使用

基本使用如下:

public class Test02 {public static void main(String[] args) throws IOException {File file = new File("./b.txt");FileWriter fileWriter = new FileWriter(file);fileWriter.write(97);fileWriter.write("你好".toCharArray());fileWriter.write("Hello World");// fileWriter.flush();fileWriter.close();}
}

字符输入流

Reader抽象类的子类是FileReader

构造方法:

  1. FileReader(File file):使用File对象构造FileReader对象
  2. FileReader(String path):使用文件路径构造FileReader对象

使用方式与字符输出流基本一致,不做演示

常用方法如下:

  1. int read():每次从文本文件中读取一个字符,返回读取字符对应的int
  2. int read(char[] cbuf):每次从文本文件中读取一串字符存储到字符数组中,返回读取字符的个数
  3. int read(char[] cbuf, int off, int len):每次从文本文件中读取一串字符的一部分存储到字符数组中,返回读取字符的个数,第一个参数代表存储读取字符的数组,第二个参数为第一个写入的字符,第三个参数为字符个数
  4. void close():关闭字符输入流

使用方式与字节输出流类似,不再演示

IO异常处理方式

前面在遇到异常时直接使用了throws向上抛出异常,但是这种处理方式只是为了代码简洁

在实际开发中,需要使用try...catch...finally语句块处理异常,例如下面的代码:

public class Test {public static void main(String[] args) {File file = new File("./a.txt");// 确保在finally的作用域中可以调用close方法FileOutputStream outputStream = null;try {outputStream = new FileOutputStream(file);} catch (IOException e) {e.printStackTrace();} finally {try {// 文件未打开时不需要关闭if (outputStream != null) {outputStream.close();}} catch (IOException e) {e.printStackTrace();}}}
}

上面是传统的处理IOException的方式,需要手动关闭流

在JDK7之后,可以使用try(IO对象1;IO对象2;...)...catch处理IOException,这种处理方式的特点是会自动关闭流

当存在多个IO对象时,在 try()中使用 ;隔开
public class Test {public static void main(String[] args) {File file = new File("./a.txt");try(FileOutputStream outputStream = new FileOutputStream(file)) {} catch (IOException e) {e.printStackTrace();}}
}

http://www.mrgr.cn/news/31703.html

相关文章:

  • 常见排序(C语言版)
  • Windows系统使用PHPStudy搭建Cloudreve私有云盘公网环境远程访问
  • 【后端】【nginx】nginx常用命令
  • 影刀RPA实战:网页爬虫之药品数据
  • 2024 “华为杯” 中国研究生数学建模竞赛(E题)深度剖析|高速公路应急车道启用建模|数学建模完整代码+建模过程全解全析
  • 高校心理辅导系统:Spring Boot技术实现指南
  • linux----进程地址空间
  • 2024华为杯C题详细完整思路和视频讲解
  • 数据飞轮崛起:数据中台真的过时了吗?
  • 树莓派配置Qt+OpenCV
  • 数据结构|二叉搜索树
  • 【模板进阶】完美转发
  • 【CPU】CPU的物理核、逻辑核、超线程判断及L1、L2、L3缓存、CacheLine和CPU的TBL说明
  • Rust 运算符快速了解
  • 2024华为杯数学建模研赛F题建模代码思路文章研究生数学建模
  • thinkphp8 从入门到放弃(后面会完善用到哪里写到哪)
  • 【图文详解】什么是微服务?什么是SpringCloud?
  • Web_php_include 攻防世界
  • 6. Python 输出长方形,直角三角形,等腰三角形
  • 【编底层原理】打开百度,输入搜索关键字,点击搜索,会发生什么,底层是如何实现的