JAVA中的File类,文件流,字节流和字符流超级详解(1.8万字干货 )

1.File类

在Java中,File 类是 java.io 包中的一个重要类,它提供了与文件或目录路径名相关的一系列操作。File 类可以用来创建、删除、重命名文件和目录,也可以用来获取文件或目录的属性,比如大小、最后修改时间等。

File类的常用方法方法

方法名称功能描述
getName()获取文件名字
getParent()获取文件的父路径字符串
getPath()获取文件的相对路径的字符串
getAbsolutePath()获取文件的绝对路径字符串
exists()判断文件或文件夹是否存在
canRead()判断文件是否可读
isFile()判断文件是否是一个正常的文件,而不是目录
canWrite()判断文件是否可以被写入
idDirectory()判断是不是文件夹类型

 2.创建File对象的几种方式

(1)File(String pathname):

该构造方法通过指定的文件路径字符串创建一个新File实例对象

语法格式如下:

pathname:文件路径字符串,包括文件名称,就是将一个代表路径的字符串转换为抽象的路径。 

绝对路径:一个完整的路径,以盘符为开头

相对路径:一个简化的路径,不以盘符为开头

  1. 路径是不区分大小写的
  2. 路径中的文件名称分隔符windows使用反斜杠,反斜杠是转义字符,两个反斜杠代表一个普通的反斜杠

import java.io.File;
public class MyFile {public static void main(String[] args) {File file1 = new File("a.txt");            // 相对路径  File file2 = new File("E:\\image\\1.jpg"); // 绝对路径File file3 = new File("E:\\image");// getPath():获取构造方法的参数System.out.println(file1.getPath());System.out.println(file2.getPath());System.out.println(file3.getPath());}

运行结果:

a.txt
E:\image\1.jpg
E:\image

 (2)File(String path,String filename):

该构造方法根据指定的父路径字符串和子路径字符串(包括文件名称)创建File类的实例对象

  • path:父路径字符串
  • filename:子路径字符串,不能为空
public class MyFile {public static void main(String[] args) {String parentDir = "E:\\image";             // 父目录String childFile = "1.jpg";                 // 子文件File file = new File(parentDir, childFile); // 根据父目录和子文件创建File对象String childDir = "aaa";                    // 子目录File dir = new File(parentDir, childDir);   // 根据父目录和子目录创建File对象System.out.println(file.getName());         // getName()获取文件名System.out.println(dir.getName());          // getName()获取目录名}
}

 运行结果:

1.jpg
aaa

(3)mkdir()和mkdirs()以及creatNewFile

1、mkdir()
  • mkdir()方法用于创建一个新目录
  • 如果指定的目录已经存在,并且是一个目录,则此方法将返回false
  • 如果父目录不存在,将会抛出java.io.IOException异常
2、mkdirs()
  • mkdirs()方法用于创建一个新的目录,并创建所有必须的父目录
  • 如果目录已经存在,midirs()将会返回true,而不会抛出异常。
  • 与mkdir()不同,mkdirs()会递归创建所有不存在的父目录,直到村建了指定的目录

 虽然两个方法类似,但是mkdir()只能创建一级目录,而mkdirs()可以创建多级目录,而且mkdir()能干的mkdirs()也能干,所以开发中都是用mkdirs()。

3、createNewFile()
  • 文件不存在,创建一个新的空文件并返回,文件存在,不创建文件返回false
4、delete() 
  • delete方法,如果此File表示目录,则目录必须为空才能被删除
  • 如果文件不存在,则返回false
public class FileGet{public static void main(String[] args) throws IOException {File f =new File("aaa.txt");System.out.println("是否存在:"+f.exists());//falseSystem.out.println("是否创建:"+f.createNewFile());//trueSystem.out.println("是否创建:"+f.createNewFile());//falseSystem.out.println("是否存在:"+f.exists());//true//目录的创建File f2 =new File("newDir");System.out.println("是否创建:"+f2.mkdir());//falseSystem.out.println("是否存在:"+f2.mkdir());//trueSystem.out.println("是否存在:"+f2.exists());//true//创建多级项目File f3 =new File("newDira\\newDirb");System.out.println(f3.mkdir());//falseFile f4 =new File("newDira\\newDirb");System.out.println(f4.mkdirs());//true//文件的删除System.out.println(f.delete());//true//目录的删除System.out.println(f2.delete());//trueSystem.out.println(f4.delete());//false}
}

(4)目录的遍历

  •  public String[] list():返回一个String数组,表示该file目录中所有子文件或者目录
  •  public File[] listFiles():返回一个file数组,表示该file目录中所有子文件或者目录
  • listFiles在获取指定目录下的文件或者文件夹时必须满足下面两个条件
  1. 指定的必须是目录。否则容易引发返回数组为null,出现NullPointerException异常
  2. 指定的目录必须存在
public class FileGet{public static void main(String[] args) throws IOException {File f =new File("aaa.txt");//获取当前目录下的文件以及文件夹名称String[] names =f.list();for (String name:names){System.out.println(name);}//获取当下目录下的文件以及文件夹对象,只要拿到了文件对象那么就可以获取更多信息File[] files =f.listFiles();for (File file:files){System.out.println(file);}}
}

 (5)递归目录

import java.io.File;
import java.io.IOException;public class FileGet{public static void main(String[] args){File f=new File("D:\\java专属io测试");Recursion(f);}private static void Recursion(File f) {//判断传入是否是目录if (!f.isDirectory()){//不是目录直接退出return;}//已经确保了传入的file是目录File[] files =f.listFiles();//遍历filesfor(File file:files){//如果该目录下文件还是文件夹就再进行递归遍历其子目录if (f.isDirectory()){//递归Recursion(f);}else{//如果该目录在文件是个文件,则打印对应的名字System.out.println(f.getName());}}}}

 2.IO流

2.1 IO流的基本概念

  1. Java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。
  2. Java.io 包中的流支持很多种格式,比如:基本类型、对象、本地化字符集等等。
  3. 一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。
  4. Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。

流(Steam)是一组有序的数据序列。根据操作的类型,分为输入流和输出流两种。输入流的指向称为源,程序从指向原的输入流中读取源中的数据。当程序需要读取数据是,就会开启一个数据源的流,这个数据源可以是文件,可以是,内存或网络连接。输出流的指向是字节要去的目的地,程序通过输出流中写入数据把信息传递到目的地。当程序需要写入数据时,就会开启一个通向目的地的流

 

 java中的io操作主要是指使用java.io包下的内容,进行输入,输出操作。输入也就读取数据,输出也叫做写出数据。

可能有点抽象,我们这里举个例子就明白了,我们可以将IO流想象成一个水管中的管道和水龙头。

  1. 水管(io流):水管是用于连接水源和用水点的通道,就像JAVA中的IO流是连接数据源(如文件,网络等)和程序的通道。
  2. 水龙头(流的类):水龙头控制水流,可以打开或者关闭水流,调节水流的大小。在java中。各种流的类(如FileInputStream,BufferedReader等)就相当于水龙头,它们控制数据的读取和写入

2.2 io的分类

  1. 输入流(InputStream):用于数据源读取数据
  2. 输出流(OutputStream):用于向数据目标写入数据
  3. 字节流(Byte Stream):处理字节数据,如果InputStream和OutStream
  4. 字符流(Character Stream):处理字符数据,如reader和writer。字符流通常用于处理文本数据,它会自动处理字符编码的转换

 以下是分类后的超类,就是4大基类,其他都是子类。

输入流输出流
字节流字节输入流InputStream字节输出流OutputStream
字符流字符输入流Reader字节输出流Writer

各自的子类名称都是以其父类名作为子类名的后缀。

比如:

  • InputStream的子类FileInputStream。
  • Reader的子类FileReader。

 

2.3 文件的世界都为字节

一切的文件数据(文本,图片,视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,在传输的过程也是这样。所以字节流可以传输任意的文件数据。在操作流的时候,我们需要记住,无论使用什么样的流对象,底层都是二进制的数据。

2.4 InputStream类

InputStream抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。

public void close()关闭输入流并释放与此流相关联的任何系统资源
public abstract int read()从输入流读取数据的下一个字节
public int read(byte[] b)该方法返回的int值代表的是读取了多少个字节,读到几个返回几个,读取不到返回-1

 在InputStream类的方法中,read()方法被定义成抽象方法,目的是为了让继承InputStream类的子类可以针对不同的外部设备实现不同的read()方法。

  • 该流用于从文件读取数据,它的对象可以用关键字 new 来创建。
  • 有多种构造方法可用来创建对象。
  • 可以使用字符串类型的文件名来创建一个输入流对象来读取文件:

FileOutputStream类是OutputStream的子类,它实现了文件的写入,能够以字节的形式写入文件中,该类的所有方法都是OutputStream类继承并重写。 

FileInputStream的构造方法

FileInputStream(File file):通过打开与实际文件的联建来创建一个FileInputStream,该文件由文件系统中的File对象file命名

File f = new File("C:/java/hello");
InputStream in = new FileInputStream(f);

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

InputStream f = new FileInputStream("C:/java/hello");

 推荐使用第二种构造方法,当你创建一个流对象时。该路径在,如果没有该文件,会抛出FIleNotFoundException。

FileInputStream读取字节数据

1.读取字节:read()方法可以读取一个字节的数据,提升为int类型时,读取到文件末尾,返回-1

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;public class Main {public static void main(String[] args) throws IOException {try(FileInputStream fis =new FileInputStream("C:\\Users\\86130\\helloworld\\idea202303825\\src\\Text\\fos.txt");){int content;while ((content=fis.read())!=-1){System.out.println((char)content);}}catch (IOException e){e.printStackTrace();}//运行结果://a//b//c//d//e}
}

 2.使用字节数组读取:read(byte[] b),每次读取b的长度个字节到数组当中,返回读取到的有效字节个数,读取到末尾时,返回-1,代码演示:


public class Main {public static void main(String[] args) throws IOException {FileInputStream fis =new FileInputStream("C:\\Users\\86130\\helloworld\\idea202303825\\src\\Text\\fos.txt");int len;//定义字节数组,作为装字节数据的容器byte[] b =new byte[2];//循环读取while ((len=fis.read(b))!=-1){//每次读取完之后,把数组变成字符串打印System.out.println(new String(b));}fis.close();}
}
//输出结果
//ab
//cd
//ed

有没有发现最后一个读取到的时候ed?而这个d是怎么读取到的,因为在读取字节中只有一个e,数组中,上一个数据没有被完全替换掉,所以通过len,获取有效字节。

 我们需要改进一下:

public class Main {public static void main(String[] args) throws IOException {FileInputStream fis =new FileInputStream("C:\\Users\\86130\\helloworld\\idea202303825\\src\\Text\\fos.txt");int len;//定义字节数组,作为装字节数据的容器byte[] b =new byte[2];//循环读取while ((len=fis.read(b))!=-1){//每次读取完之后,把数组变成字符串打印System.out.println(new String(b,0,len));}fis.close();}
}
//输出结果
//ab
//cd
//e

 在开发中一般强烈推荐使用数组读取文件,代码如下:

public class Main {public static void main(String[] args) throws IOException {FileInputStream inputStream = null;try{inputStream =new FileInputStream("a.txt");byte[] bys =new byte[1024];int len ;while ((len=inputStream.read(bys))!=-1){System.out.println(new String(bys,0,len));}}catch (IOException e){e.printStackTrace();}finally {try{inputStream.close();}catch (IOException e){e.printStackTrace();}}}
}

字节流FileInputStream复制图片

复制图片的原理 


import java.io.*;public class Main {public static void main(String[] args) throws IOException {//创建流对象//1、1指定数据源FileInputStream fis =new FileInputStream("C:\\Users\\86130\\helloworld\\idea202303825\\src\\Text\\fos.txt");//1、2指定目的地FileOutputStream fos =new FileOutputStream("C:\\Users\\86130\\helloworld\\idea202303825\\src\\PTui\\images\\公孙离_11.jpg");//读写数据//定义数组byte[] b =new byte[1024];int len;while ((len=fis.read(b))!=-1){fos.write(b,0,len);}//关闭资源fos.close();fis.close();}
}

 注:复制文本,图片,MP3,视频等方式一样

2.5 OutputStream类

OutputStream抽象类是表示字节输出流的所有列的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。

public void close()关闭此输出流并释放于此流相关的任何系统资源
public void flush()刷新此输出流并强制任何缓冲的输出字节被写出
public void write(byte[] b)将b.length个字节从指定的字节数组写入此输出流
public abstract void write(int b)将指定字节输出流

 FileOutputStream构造方法

public FileOutputStream(File file):根据File对象参数创建对象

File f = new File("C:/java/hello");
OutputStream fOut = new FileOutputStream(f);

pulbic FileOutputStream(String name):根据名称字符串来创建对象

OutputStream f = new FileOutputStream("C:/java/hello")

 下面是使用write的三个方法

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

写出字节:write(int b)方法,每次可以写出一个字节数据,代码如下:

package Text;import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;public class Main {public static void main(String[] args) throws IOException {FileOutputStream fos =new FileOutputStream("C:\\Users\\86130\\helloworld\\idea202303825\\src\\Text\\fos.txt");fos.write(97);//写出第一个字节fos.write(98);fos.write(99);//关闭资源fos.close();}//输出结果“abc”
}
  1. 虽然参数为int类型四个字节,但是只会保留一个字节的信息写出。
  2. 流操作完毕之后,必须释放系统资源,因为如果不释放资源,可能会导致资源的泄露,即应用程序占用的资源没有被正确释放,可能会导致系统资源耗尽。

写出字节数组:write(byte[] b),每次写入数组中的数据

import java.io.FileOutputStream;
import java.io.IOException;public class Main {public static void main(String[] args) throws IOException {FileOutputStream fos =new FileOutputStream("C:\\Users\\86130\\helloworld\\idea202303825\\src\\Text\\fos.txt");byte[] b ="你好,我叫大帅比".getBytes();fos.write(b);//关闭资源fos.close();}
}

写出指定长度字节数组:write(byte[] b,int off,int len),每次写出从off索引开始,len个字节,代码如下:

import java.io.FileOutputStream;
import java.io.IOException;public class Main {public static void main(String[] args) throws IOException {FileOutputStream fos =new FileOutputStream("C:\\Users\\86130\\helloworld\\idea202303825\\src\\Text\\fos.txt");byte[] b ="abcdef".getBytes();fos.write(b,2,2);//关闭资源fos.close();//输出结果为cd}
}

 FileOutputStream实现数据追加续写,换行

经过上面的代码测试,每次测序运行时, 每次创建输出流对象,都会清空目标文件中的数据。那么我们该如果保留目标文件中的数据,还能继续追加新的数据呢,并且实现换行,其实很简单,这时候就需要另外两个构造方法了。

  1. public FileOutputStream(File file,boolean appead)
  2. public FileOutputStream(String name,boolean appead)

 这两个构造方法,第二个参数中都需要传入一个boolean类型的值,true表示追加数据,false表示不追加也就是清空原有的数据。这样创建的输出流对象,就可以指定是否追加续写了,至于Windows换行则是\n\r。

实现数据追加续写代码如下:

import java.io.FileOutputStream;
import java.io.IOException;public class Main {public static void main(String[] args) throws IOException {FileOutputStream fos =new FileOutputStream("C:\\Users\\86130\\helloworld\\idea202303825\\src\\Text\\fos.txt",true);//将字符串转换为字节byte[] b ="abcdef".getBytes();fos.write(b);fos.close();//输出结果为cdabcde}
}

在Windows系统里,换行符号是\r\n,具体代码如下:

import java.io.FileOutputStream;
import java.io.IOException;public class Main {public static void main(String[] args) throws IOException {FileOutputStream fos =new FileOutputStream("C:\\Users\\86130\\helloworld\\idea202303825\\src\\Text\\fos.txt",true);//定义字节数组byte[] words={97,98,99,100,101};//遍历数组for (int i =0;i<words.length;i++){fos.write(words[i]);fos.write("\r\n".getBytes());}fos.close();}
}

3 FileReader类和FileWriter类

3.1FileReader类

字符流的由来:因为数据编码的不同,因而有了对象字符进行高效操作的流对象,字符流本质其实就是基于字节流读取时,去查看了指定的编码,而字节流直接读取数据会有编码的问题(读中文会乱码)

public class Main {public static void main(String[] args) throws IOException {//创建流对象//1、1指定数据源FileInputStream fis =new FileInputStream("C:\\Users\\86130\\helloworld\\idea202303825\\src\\Text\\fos.txt");FileOutputStream fos =new FileOutputStream("C:\\Users\\86130\\helloworld\\idea202303825\\src\\Text\\fos.txt");//先将这几句话转化为字节byte[] b ="你好,我叫大帅比".getBytes();fos.write(b);//定义数组byte[] c =new byte[1024];int len;while ((len=fis.read(c))!=-1){System.out.println((char) len);}//运行结果是乱码的}
}

字节流读取中文字符时,可能不会显示完整的字符,因为一个中文字符占用了多个字节存储。

当我们使用默认的字符编码(见上例)读取一个包含中文字符的文本文件时,就会出现乱码。因为默认的字符编码通常是 ASCII 编码,它只能表示英文字符,而不能正确地解析中文字符。

那使用字节流该如何正确地读出中文呢?见下例。

try (FileInputStream inputStream = new FileInputStream("a.txt")) {byte[] bytes = new byte[1024];int len;while ((len = inputStream.read(bytes)) != -1) {System.out.print(new String(bytes, 0, len));}
}

因为我们拿 String 类进行了解码,查看new String(byte bytes[], int offset, int length)的源码就可以发现,该构造方法有解码功能:

public String(byte bytes[], int offset, int length) {checkBounds(bytes, offset, length);this.value = StringCoding.decode(bytes, offset, length);
}
public static Charset defaultCharset() {if (defaultCharset == null) {synchronized (Charset.class) {if (cs != null)defaultCharset = cs;elsedefaultCharset = forName("UTF-8");}}return defaultCharset;
}
static char[] decode(byte[] ba, int off, int len) {String csn = Charset.defaultCharset().name();try {// use charset name decode() variant which provides caching.return decode(csn, ba, off, len);} catch (UnsupportedEncodingException x) {warnUnsupportedCharset(csn);}
}

在 Java 中,常用的字符编码有 ASCII、ISO-8859-1、UTF-8、UTF-16 等。其中,ASCII 和 ISO-8859-1 只能表示部分字符,而 UTF-8 和 UTF-16 可以表示所有的 Unicode 字符,包括中文字符。

当我们使用 new String(byte bytes[], int offset, int length) 将字节流转换为字符串时,Java 会根据 UTF-8 的规则将每 3 个字节解码为一个中文字符,从而正确地解码出中文。

尽管字节流也有办法解决乱码问题,但不够直接,于是就有了字符流,专门用于处理文本文件(音频、图片、视频等为非文本文件)。

从另一角度来说:字符流 = 字节流 + 编码表

3.2 字符输入流

java.io.Reader 抽象类是字符输入流的所有类的超类(父类),可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。

  • public void close():关闭此流并释放与此相关联的任何系统资源
  • public int read():从输入流读取一个字符。
  • pulbic int read(char[] cbuf):从输入流中读取一些字符,并将他们存储到字符数组cbuf中

FileReader类

java.io.FileReader类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区  

// 使用File对象创建流对象
File file = new File("a.txt");
FileReader fr = new FileReader(file);// 使用文件名称创建流对象
FileReader fr = new FileReader("b.txt");

FileReader读取字符数据

读取字符:read()方法,每次可以读取一个字符的数据,提升为int类型,读取到文件末尾时,返回-1,循环读取。      

// 使用文件名称创建流对象
FileReader fr = new FileReader("abc.txt");
// 定义变量,保存数据
int b;
// 循环读取
while ((b = fr.read())!=-1) {System.out.println((char)b);
}
// 关闭资源
fr.close();

读取指定长度的字符read(char[] cbuf, int off, int len),并将其存储到字符数组中。其中,cbuf 表示存储读取结果的字符数组,off 表示存储结果的起始位置,len 表示要读取的字符数。代码示例如下:

File textFile = new File("docs/约定.md");
// 给一个 FileReader 的示例
// try-with-resources FileReader
try(FileReader reader = new FileReader(textFile);) {// read(char[] cbuf)char[] buffer = new char[1024];int len;while ((len = reader.read(buffer, 0, buffer.length)) != -1) {System.out.print(new String(buffer, 0, len));}
}

在这个例子中,使用 FileReader 从文件中读取字符数据,并将其存储到一个大小为 1024 的字符数组中。每次读取 len 个字符,然后使用 String 构造方法将其转换为字符串并输出。

FileReader 实现了 AutoCloseable 接口,因此可以使用 try-with-resourcesopen in new window 语句自动关闭资源,避免了手动关闭资源的繁琐操作。

记住FileInputStream和FileReader两者的区别,虽然他们都用于文件的读取,但是他们各自处理的不同类型的数据,并且有着各自使用的场景。

  • FileInputStream主要直接处理字节数据,这对于读取图片,视频,音频等二进制文件非常有用,因为他们不需要进行字节编码的转换
  • FileReader可以自动处理字符编码,这对于读取文件非常有用,因为它可以正确的将字节转换为字符

 3.3 字符输出流(Writer)

java.io.Writer 抽象类是字符输出流的所有类的超类,将指定的字符信息写出到目的地。

下面是字符输出流的基本共性功能方法:

  • 1、write(int c) 写入单个字符。
  • 2、write(char[] cbuf) 写入字符数组。
  • 3、write(char[] cbuf, int off, int len) 写入字符数组的一部分,off为开始索引,len为字符个数。
  • 4、write(String str) 写入字符串。
  • 5、write(String str, int off, int len) 写入字符串的某一部分,off 指定要写入的子串在 str 中的起始位置,len 指定要写入的子串的长度。
  • 6、flush() 刷新该流的缓冲。
  • 7、close() 关闭此流,但要先刷新它。 
FileWriter 构造方法
  • FileWriter(File file): 创建一个新的 FileWriter,参数为要读取的File对象。
  • FileWriter(String fileName): 创建一个新的 FileWriter,参数为要读取的文件的名称
// 第一种:使用File对象创建流对象
File file = new File("a.txt");
FileWriter fw = new FileWriter(file);// 第二种:使用文件名称创建流对象
FileWriter fw = new FileWriter("b.txt");

 FileWriter写入字符

写入字符write(int b) 方法,每次可以写出一个字符,代码示例如下:

FileWriter fw = null;
try {fw = new FileWriter("output.txt");fw.write(72); // 写入字符'H'的ASCII码fw.write(101); // 写入字符'e'的ASCII码fw.write(108); // 写入字符'l'的ASCII码fw.write(108); // 写入字符'l'的ASCII码fw.write(111); // 写入字符'o'的ASCII码
} catch (IOException e) {e.printStackTrace();
} finally {try {if (fw != null) {fw.close();}} catch (IOException e) {e.printStackTrace();}
}

在这个示例代码中,首先创建一个 FileWriter 对象 fw,并指定要写入的文件路径 "output.txt"。然后使用 fw.write() 方法将字节写入文件中,这里分别写入字符'H'、'e'、'l'、'l'、'o'的 ASCII 码。最后在 finally 块中关闭 FileWriter 对象,释放资源。

需要注意的是,使用 write(int b) 方法写入的是一个字节,而不是一个字符。如果需要写入字符,可以使用 write(char cbuf[]) 或 write(String str) 方法。 

FileWriter fw = null;
try {fw = new FileWriter("output.txt");char[] chars = {'H', 'e', 'l', 'l', 'o'};fw.write(chars); // 将字符数组写入文件
} catch (IOException e) {e.printStackTrace();
} finally {try {if (fw != null) {fw.close();}} catch (IOException e) {e.printStackTrace();}
}

关闭资源时,与FileOutputStream不同。如果不关闭,数据只能保存在缓冲区中,并未保存到文件中

关闭close和刷新flush

因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中

但是关闭了流对象,就无法继续写数据了。如果我们既想写入数据,又想继续使用流,就需要 flush 方法了。

flush:刷新缓冲区,流对象可以继续使用

close:先刷新缓冲区,然后通知系统释放资源,流对象不可以再被使用了 

import java.io.*;public class Main {public static void main(String[] args) throws IOException {//源 也就是输入流,读取a.txt文件FileReader fr =new FileReader("fos.txt");//必须要存在a.txt文件,否则报FileNotFoundException异常//目的流 也就是输出流FileWriter fw =new FileWriter("b.txt");//系统会自动创建b.text,因为他是输出流int len;while((len=fr.read())!=-1){fw.write(len);}}
}

但是b.text文件依旧为空,因为如果不关闭,数据只会被写入缓冲区,没有被保存到文件中。

在以上的代码中再添加下面三句代码,b.txt文件就能复制到源文件的数据了!

fr.close();
fw.flush();
fw.close();

flush()表示这个函数清空的意思,用于清空缓冲区的数据流,进行流的操作,数据先被读到内存中,然后用数据写到文件中,那么当你数据读完后,我们如果这个时候调用close()方法关闭读写流,这个时候可能会造成数据的丢失。


public class Main {public static void main(String[] args) throws IOException {FileWriter fw =new FileWriter("b.txt");//系统会自动创建b.text,因为他是输出流//写出数据,通过flushfw.write('刷');fw.flush();fw.write('新');fw.flush();//写出数据,通过closefw.write('关');fw.close();//写出第二个字符fw.write('闭');//这里会报错了,因为Stream已经被关闭了fw.close();}
}

即使flush方法写出了数据,操作的最后还是要调用close方法,释放资源。

FileReader和FileWriter类完成文本文件复制

import java.io.*;public class Main {public static void main(String[] args) throws IOException {FileReader fr =new FileReader("b.txt");//此文件不存在会抛出java.io.FileNotFoundException//创建输出流对象FileWriter fw=new FileWriter("fos.txt");//创建输出流做的工作//1,调用系统资源创建一个文件//2.创建输出流对象//3.把输出流对象指向文件//文本文件复制,一次读一个字符copyMethod1(fr,fw);//文本文件复制,一次读一个字符数组copyMethod2(fr,fw);fr.close();fw.close();}private static void copyMethod2(FileReader fr, FileWriter fw) throws IOException {int ch;while((ch=fr.read())!=-1){//读取数据fw.write(ch);}fw.flush();}private static void copyMethod1(FileReader fr, FileWriter fw) throws IOException {char chs[]=new char[1024];int len ;while((len =fr.read(chs))!=-1){fw.write(chs,0,len);}fw.flush();}
}

最后来详细讲解一下IO异常处理

 1.使用finally块

确保在finally块中关闭资源,无论发生异常与否,这都可以防止资源泄露


import java.io.*;public class Main {public static void main(String[] args) throws IOException {FileReader fr =new FileReader("b.txt");//此文件不存在会抛出java.io.FileNotFoundException//创建输出流对象FileWriter fw=new FileWriter("fos.txt");try{int data;while ((data= fr.read())!=-1){fw.write(data);}}catch (FileNotFoundException e){System.out.println("文件未找到:"+e.getMessage());}catch (IOException e){System.out.println("读取或者写入文件时发生的错误"+e.getMessage());}finally {try {if (fr!=null){fr.close();}if (fw!=null){fw.close();}}catch (IOException e){System.out.println("关闭文件时发生的错误"+e.getMessage());}}}
}

 2.使用try-with-resources语句

自从java7开始,就可以使用try-with-resources语句自动管理资源,这使得代码更简洁,减少了资源泄露的风险。

try (FileWriter fw = new FileWriter("fw.txt")) {// 写出数据fw.write("二哥真的帅"); //哥敢摸si
} catch (IOException e) {e.printStackTrace();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/47668.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mac Electron 应用如何进行签名(signature)和公证(notarization)?

最近很多客户反映&#xff0c;从官网下载的Mac Electron应用打不开&#xff0c;直接报病毒&#xff0c;类似于这种&#xff1a; 这是因为在MacOS 10.14.5之后&#xff0c;如果应用没有在苹果官方平台进行公证notarization(我们可以理解为安装包需要审核&#xff0c;来判断是否存…

第6章 单片机的定时器/计数器

6.1 定时/计数器的结构与工作原理 6.2 定时器的控制 6.3 定时/计数器的工作方式 6.4 定时/计数器的编程和应用 6.1 定时/计数器的结构与工作原理 6.1.1 定时/计数器的基本原理 纯软件定时/计数方法&#xff1a; 定时——空循环预定周次&#xff0c;等待预定时间 计数—…

【Qt】之【Bug】error:C1083 无法打开包括文件

背景 a.cpp引用b.h正常&#xff0c;但是a.h引用b.h就报 “无法打开包括文件”的错误 分析 查看“编译输出”&#xff0c;显示不是a.h引起的错误&#xff0c;而是C插件&#xff0c; 查看后发现&#xff0c;C插件引用了a所在插件pro&#xff0c;但是没有引用a依赖的b所在的插件…

Axure中继器进阶指南:打造专业级交互

中继器进阶篇 前言 经过了基础篇的学习,我们已经掌握了中继器的基本操作,接下来来解锁中继器的进阶操作。 1. 修改删除指定行 首先拖入中继器,加上【修改】 【删除】的按钮,然后给修改按钮添加单击事件选择【更新行】。 这里可以看到我们在中继器内部添加的事件,在编…

IDEA关联数据库

《IDEA破解、配置、使用技巧与实战教程》系列文章目录 第一章 IDEA破解与HelloWorld的实战编写 第二章 IDEA的详细设置 第三章 IDEA的工程与模块管理 第四章 IDEA的常见代码模板的使用 第五章 IDEA中常用的快捷键 第六章 IDEA的断点调试&#xff08;Debug&#xff09; 第七章 …

2024-07-16 Unity插件 Odin Inspector7 —— Number Attributes

文章目录 1 说明2 Number 特性2.1 MaxValue / MinValue2.2 MinMaxSlider2.3 ProgressBar2.4 PropertyRange2.5 Unit2.6 Wrap 1 说明 ​ 本文介绍 Odin Inspector 插件中有关 Number 特性的使用方法。 2 Number 特性 2.1 MaxValue / MinValue 在 Inspector 窗口中对象能够被设…

LLM 构建Data Multi-Agents 赋能数据分析平台的实践之④:数据分析之三(数据展示)

概述 在先前探讨的文章中&#xff0c;我们构建了一个全面的数据测试体系&#xff0c;该体系遵循“数据获取—数据治理—数据分析”的流程。如何高效地构建数据可视化看板&#xff0c;以直观展现分析结果&#xff0c;正逐渐成为利用新兴技术提升效能的关键领域。伴随业务拓展、数…

《驾驭AI浪潮:伦理挑战与应对策略》

AI发展下的伦理挑战&#xff0c;应当如何应对&#xff1f; 人工智能飞速发展的同时&#xff0c;也逐渐暴露出侵犯数据隐私、制造“信息茧房”等种种伦理风险。随着AI技术在社会各个领域的广泛应用&#xff0c;关于AI伦理和隐私保护问题日趋凸显。尽管国外已出台系列法规来规范…

YOLOv7网络结构学习

YOLOV7详细解读&#xff08;一&#xff09;网络架构解读 YOLOV7学习记录之原理代码介绍 【Make YOLO Great Again】YOLOv1-v7全系列大解析&#xff08;Backbone篇&#xff09; yolov7 图解 深入浅出 Yolo 系列之 Yolov7 基础网络结构详解 我觉得Head、Neck和Head的划分不太…

从产品手册用户心理学分析到程序可用性与易用性的重要区别

注&#xff1a;机翻&#xff0c;未校对。 Designing for People Who Have Better Things To Do With Their Lives 为那些生活中有更重要事情要做的人设计 When you design user interfaces, it’s a good idea to keep two principles in mind: 在设计用户界面时&#xff0c;…

三大ip代理服务商PK,IPFoxy黑马逆袭成首选?

最近亚马逊的Prime Day ,小编我呀忙得不可开交。因为小编负责的店铺数量多且需要稳定的长期连接&#xff0c;我用某一海外ip代理竟然不稳定&#xff0c;这还是号称老牌的ip代理服务商&#xff0c;因为它的漏洞&#xff0c;让我加班了好久处理工作上的问题。 吃一堑&#xff0c…

RPA鼠标按键使用技巧

RPA鼠标按键使用技巧 Mouse.MouseAuto.Action命令出错&#xff0c;调用的目标发生了异常&#xff0c;Exception in Mouse.Action元素不可用怎么解决 出现问题 1.想要实现的效果鼠标移动到录屏工具的小球上2.点击开始按钮开始录屏现象&#xff0c;鼠标没有移动痕迹&#xff0c…

【C++】C++ 职工信息管理系统(源码)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

C++系列-Vector模拟实现(补充)

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 迭代器失效 这篇文章是基于上一篇的Vector的模拟实现的补充知识点&#xff0c;首先我们需要重点关注的便是迭代器失效的问题。 void test_vector3(){std::vector<int> v…

【C++】类与对象的学习(中)

目录 一、默认成员函数&#xff1a; 二、构造函数&#xff1a; 1、定义&#xff1a; 2、理解&#xff1a; 三、析构函数&#xff1a; 1、定义&#xff1a; 2、理解&#xff1a; 四、拷贝构造&#xff1a; 1、定义&#xff1a; 2、理解&#xff1a; 五、运算符的重载&…

抖音视频素材是哪里找的?热门的抖音素材网站分享

抖音视频创作高手们&#xff0c;你们是否在寻找下一个爆款视频的完美素材&#xff1f;今天&#xff0c;我将为你们介绍几个优质的视频素材网站&#xff0c;确保你们能在素材的海洋中轻松找到那最耀眼的“珍珠”&#xff01; 蛙学网 首先&#xff0c;我们要推荐的是蛙学网。这个…

Go语言并发编程-同步和锁

同步和锁 概述 同步是并发编程的基本要素之一&#xff0c;我们通过channel可以完成多个goroutine间数据和信号的同步。 除了channel外&#xff0c;我们还可以使用go的官方同步包sync&#xff0c;sync/atomic 完成一些基础的同步功能。主要包含同步数据、锁、原子操作等。 一…

13. C++继承 | 详解 | 虚拟继承及底层实现

目录 1.定义 1.1继承的概念 1.2 继承的定义 2. 对象赋值转换 3. 继承中的作用域 a. 隐藏/重定义 (Hiding/Redefinition) b. 重载 (Overloading) c. 重写/覆盖 (Overriding) d. 编译报错 (Compilation Error) 4. 派生类的默认成员函数 构造 拷贝构造 运算符重载 析…

win11将bat文件固定到“开始“屏幕

一、为bat文件创建快捷方式 (假设bat文件的全名为运行脚本.bat) 右键bat文件&#xff0c;点击显示更多选项 右键菜单选择发送到(N)-桌面快捷方式 二、获取快捷方式的路径 返回桌面&#xff0c;选中创建好的快捷方式&#xff0c;按AltEnter&#xff0c;切换到安全选项卡 鼠…

JCR一区级 | Matlab实现PSO-Transformer-LSTM多变量回归预测

JCR一区级 | Matlab实现PSO-Transformer-LSTM多变量回归预测 目录 JCR一区级 | Matlab实现PSO-Transformer-LSTM多变量回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现PSO-Transformer-LSTM多变量回归预测&#xff0c;粒子群优化Transformer结合LST…