时间:2023-02-21 13:45:23 | 栏目:JAVA代码 | 点击:次
在学习IO流之前,我们首先需要学习的概念就是Stream流
为了方便理解,我们可以把数据的读写操作抽象成数据在"管道"中流动,但需注意:
1.流只能单方向流动
2.输入流用来读取 → in
3.输出流用来写出 → out
4.数据只能从头到尾顺序的读写一次
所以以程序的角度来思考,In/out 相对于程序而言的输入(读取)/输出(写出)的过程.
在java中,根据处理的数据单位不同,可以把流分为字节流和字符流
字节流 : 针对二进制文件
字符流 : 针对文本文件,读写容易出现乱码的现象,在读写时,最好指定编码集为UTF-8
在结合对应类型的输入和输出方向,常用的流有:
File
字节流:针对二进制文件
InputStream
FileInputStream
BufferedInputStream
ObjectInputStream
OutputStream
FileOutputStream
BufferedOutputStream
ObjectOutputStream
字符流:针对文本文件
Reader
FileReader
BufferedReader
InputStreamReader
Writer
FileWriter
BufferedWriter
OutputStreamWriter
PrintWriter一行行写出
封装一个磁盘路径字符串,对这个路径可以执行一次操作
可以封装文件路径、文件夹路径、不存在的路径
File(String pathname)通过将给定路径名字符串转换为抽象路径名来创建一个新的File实例
new File(“d:/abc/a.txt”);
new File(“d:/abc”,”a.txt”);
创建包: cn.tedu.file
创建类: TestFile.java
package cn.tedu.file; import java.io.File; import java.io.IOException; import java.util.Arrays; /*本类用来测试文件类 File*/ public class TestFile { public static void main(String[] args) throws IOException { //1.创建File文件对象 /*1.构造函数的参数是String类型的pathname(路径名) * 这个路径可以是文件路径,也可以是文件夹路径*/ /*2.\在代码中有特殊的意义,所以想要真正表示这是一个\,需要用\进行转义*/ //注意:此处需要自己手动在D盘创建对应目录下的1.txt,并添加内容 //注意:创建1.txt时,需要设置系统显示文件后缀名,如果没设置,文件名应该是1 //注意:File需要导包:import java.io.File; File file = new File("D:\\ready\\1.txt"); //2.测试常用方法 //2.1文件与文件夹属性测试 System.out.println(file.length());//12,获取指定文件的字节量大小 System.out.println(file.exists());//true,判断指定文件是否存在 System.out.println(file.isFile());//true,判断指定内容是否为文件 System.out.println(file.isDirectory());//false,判断指定内容是否为文件夹 System.out.println(file.getName());//1.txt,获取指定内容的名字 System.out.println(file.getParent());//D:\ready,获取指定内容的上级 System.out.println(file.getAbsolutePath());//D:\ready\1.txt,获取指定内容的绝对路径 //2.2创建与删除 file = new File("D:\\ready\\2.txt"); /*如果指定创建文件的文件夹不存在,会报错:java.io.IOException * 系统找不到指定的路径,由于可能会发生异常,所以调用时需要抛出异常 */ //在windows中创建不存在的文件2.txt,成功返回true System.out.println(file.createNewFile());//true file = new File("D:\\ready\\m"); System.out.println(file.mkdir());//true,创建不存在的单层文件夹m file = new File("D:\\ready\\a\\b\\c"); System.out.println(file.mkdirs());//true,创建不存在的多层文件夹a/b/c System.out.println(file.delete());//c被删除,删除文件或者空文件夹 file = new File("D:\\ready\\a"); System.out.println(file.delete());//false,因为a目录里还有b目录 file = new File("D:\\ready\\2.txt"); System.out.println(file.delete());//true,删除2.txt文件成功 //2.3 文件列表测试 file = new File("D:\\ready"); String[] listName = file.list(); System.out.println(Arrays.toString(listName)); File[] fs = file.listFiles(); System.out.println(Arrays.toString(fs)); System.out.println(fs[0].length()); } }
字节流是由字节组成的,字符流是由字符组成的.
Java里字符由两个字节组成.字节流是基本流,主要用在处理二进制数据。
所以字节流是比较常用的,可以可以处理多种不同种类的文件,比如文本文档/音频/视频等等
此抽象类是表示字节输入流的所有类的超类/抽象类,不可创建对象哦
常用方法:
abstract int read() 从输入流中读取数据的下一个字节
int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中
int read(byte[] b, int off, int len) 将输入流中最多 len 个数据字节读入 byte 数组,off表示存时的偏移量
void close() 关闭此输入流并释放与该流关联的所有系统资源
直接插在文件上,直接读取文件数据
创建对象
FileInputStream(File file)―直接传文件对象
通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定FileInputStream(String pathname)―传路径
通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定
BufferedInputStream 为另一个输入流添加一些功能,在创建BufferedInputStream 时,会创建一个内部缓冲区数组(默认8k大小)。在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。
创建对象
BufferedInputStream(InputStream in)
创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
创建包: cn.tedu.file
创建类: TestIn.java
package cn.tedu.file; import java.io.*; /*本类用于练习字节输入流*/ public class TestIn { public static void main(String[] args) { //method();//字节流的读取 method2();//高效字节流的读取 } //本方法用于测试高效字节流的读取 private static void method2() { //定义一个在本方法中都生效的局部变量in,注意手动初始化,值为null InputStream in = null; try { //1.创建高效字节输入流对象 // InputStream in = new BufferedInputStream( // new FileInputStream(new File("E:\\ready\\1.txt"))); in = new BufferedInputStream (new FileInputStream("E:\\ready\\1.txt")); //2.使用流进行读取 int b; while ((b= in.read())!= -1){ System.out.println(b); } } catch (Exception e) { e.printStackTrace(); }finally {//关流操作写在finally{}中 //3.流用完以后一定要关闭!!! try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } //本方法用于测试字节流的读取 private static void method() { //创建一个在本方法都生效的局部变量注意手动初始化 InputStream in = null; try { //1.创建字节输入流对象用于读取 //InputStream in = new InputStream();//报错原因:抽象类不可实例化 //InputStream in = new FileInputStream(new File("E:\\ready\\1.txt")); in = new FileInputStream("E:\\ready\\1.txt"); //2.开始读取 /*read()每次调用都会读取一个字节,如果读到了数据的末尾,返回-1*/ // System.out.println(in.read()); // System.out.println(in.read()); // System.out.println(in.read()); // System.out.println(in.read()); //需求:需要循环读取文件中的所有内容,直至读完 //定义变量,记录读到的数据 int b; while((b=in.read())!= -1){ System.out.println(b); } } catch (Exception e) { e.printStackTrace();//打印错误信息 /*try-catch结构中的第三个部分:finally{} * 这部分不论是否捕获到异常,是一定会被执行到的代码,常用于关流*/ }finally { try { //3.释放资源,流资源用完必须释放!!! in.close(); } catch (IOException e) { e.printStackTrace(); } } } }
常用于处理纯文本数据
用于读取字符流的抽象类。
常用方法:
int read() 读取单个字符
int read(char[] cbuf) 将字符读入数组
abstract int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分
int read(CharBuffer target) 试图将字符读入指定的字符缓冲区
abstract void close() 关闭该流并释放与之关联的所有资源
用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要自己指定这些值,可以先在 FileInputStream 上构造一个 InputStreamReader。
创建对象
FileReader(String fileName) 在给定从中读取数据的文件名的情况下创建一个新 FileReader
FileReader(File file) 在给定从中读取数据的 File 的情况下创建一个新 FileReader
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
创建对象
BufferedReader(Reader in) 创建一个使用默认大小输入缓冲区的缓冲字符输入流
创建包: cn.tedu.file
创建类: TestIn2.java
package cn.tedu.file; import java.io.*; /*本类用于测试字符流的读取*/ public class TestIn2 { public static void main(String[] args) { //method();//测试普通字符输入流 method2();//测试高效字符输入流 } //创建一个用于测试高效字符输入流的方法 private static void method2() { //1.定义一个在本方法都生效的局部变量,手动初始化值null Reader in=null; try{ //1.创建高效字符读取流对象 //in = new BufferedReader(new FileReader(new File("E:\\ready\\1.txt"))); in = new BufferedReader(new FileReader("E:\\ready\\1.txt")); //2.使用流对象 int b; while((b=in.read())!=-1){ System.out.println(b); } }catch (Exception e){ e.printStackTrace(); }finally { //3.关闭流对象 try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } //创建一个用于测试普通字符输入流的方法 private static void method() { //1.1创建一个在本方法中都生效的局部变量,注意初始化值null Reader in = null; try { //1.2创建字符输入流对象,注意需要捕获异常 //Reader in = new Reader();//报错原因:抽象父级不可实例化 //in = new FileReader(new File("E:\\ready\\1.txt")); in = new FileReader("E:\\ready\\1.txt"); //2.使用流对象 //System.out.println(in.read()); //需求:循环读取文件中的所有内容,只要不是-1,就说明还有数据,继续读取 //3.1定义变量,记录读取到的数据 int b; while((b = in.read())!= -1){ System.out.println(b); } } catch (Exception e) { e.printStackTrace(); } finally {//3.关流 try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } }
此抽象类是表示输出字节流的所有类的超类.输出流接受输出字节并将这些字节发送到某个接收器.
常用方法:
Void close() 关闭此输出流并释放与此流相关的所有系统资源
Void flush() 刷新此输出流并强制写出所有缓冲的输出字节
Void write(byte[ ] b) 将b.length个字节从指定的byte数组写入此输出流
Void write(byte[ ] b,int off ,int len) 将指定byte数组中从偏移量off开始的len个字节写入输出流
Abstract void write(int b) 将指定的字节写入此输出流
直接插在文件上,直接写出文件数据
构造方法(创建对象):
FileOutputStream(String name)
创建一个向具有指定名称的文件中写入数据的文件输出流
FileOutStream(File file)
创建一个向指定File对象表示的文件中写入数据的文件输出流
FileOutStream(File file,boolean append)―如果第二个参数为true,表示追加,不覆盖
创建一个向指定File对象表示的文件中写入数据的文件输出流,后面的参数是指是否覆盖原文件内容
该类实现缓冲的输出流,通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必每次针对字节写出调用底层系统
构造方法(创建对象):
BufferedOutputStream(OutputStream out)
创建一个新的缓冲输出流,用以将数据写入指定的底层输出流
创建包: cn.tedu.file
创建类: TestOut.java
package cn.tedu.file; import java.io.*; /*本类用于测试字节输出流*/ public class TestOut { public static void main(String[] args) { method();//用于测试普通字节输出流 //method2();//用于测试高效字节输出流 } //创建一个用于测试高效字节输出流的方法 private static void method2() { //1.创建一个在本方法都生效的局部变量,注意手动初始化 OutputStream out = null; try{ //2.创建高效字节输出流对象 // out = new BufferedOutputStream(new FileOutputStream(new File("E:\\ready\\2.txt"))); out = new BufferedOutputStream(new FileOutputStream("E:\\ready\\2.txt")); //3.使用流对象--进行写出操作 out.write(97); out.write(97); out.write(97); }catch (Exception e){ e.printStackTrace(); }finally {//关流操作要放在finally{}中 try { //4.关流 out.close(); } catch (IOException e) { e.printStackTrace(); } } } //创建一个用于测试普通字节输出流的方法 private static void method() { //1.创建一个在本方法中都生效的局部变量,注意手动初始化null OutputStream out = null; //2.创建try-catch-finally结构,因为IO操作可能会产生异常 try{ //3.创建普通字节输出流对象 //out = new FileOutputStream(new File("E:\\ready\\2.txt")); //out = new FileOutputStream("E:\\ready\\2.txt"); out = new FileOutputStream("E:\\ready\\2.txt",true); //4.使用流对象--进行写出操作 out.write(99);//对应ASCII码表中的a out.write(99);//对应ASCII码表中的b out.write(99);//对应ASCII码表中的c }catch (Exception e){ e.printStackTrace(); }finally {//如果想要代码一定会执行,需要写在finally中 try { //5.关流操作 out.close(); } catch (IOException e) { e.printStackTrace(); } } } }
写入字符流的抽象类
常用方法:
Abstract void close() 关闭此流,但要先刷新它
Void write(char[ ] cbuf) 写入字符数组
Void write(int c) 写入单个字符
Void write(String str) 写入字符串
Void write(String str,int off,int len) 写入字符串的某一部分
Abstract void write(char[] cbuf,int off,int len)写入字符数组的某一部分
用来写入字符文件的便捷类,此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的.如果需要自己自定义这些值,可以先在FileOutputStream上构造一个OutputStreamWriter.
构造方法(创建对象):
FileWriter(String filename)
根据给定的文件名构造一个FileWriter对象
FileWriter(String filename,boolean append)
根据给定的文件名以及指示是否附加写入数据的boolean值来构造FileWriter
将文本写入字符输出流,缓冲各个字符,从而提供单个字符,数组和字符串的高效写入.可以指定缓冲区的大小,或者接受默认的大小,在大多数情况下,默认值就足够大了
构造方法(创建对象):
BufferedWriter(Writer out)
创建一个使用默认大小输出缓冲区的缓冲字符输出流
创建包: cn.tedu.file
创建类: TestOut2.java
package cn.tedu.file; import java.io.*; /*本类用于测试字符输出流*/ public class TestOut2 { public static void main(String[] args) { //method();//用于测试普通字符输出流 method2();//用于测试高效字符输出流 } //创建一个用于测试高效字符输出流的方法 private static void method2() { //1.创建一个在本方法都生效的局部变量,值为null,注意手动初始化!!! Writer out = null; //2.由于程序可能会抛出异常,所以需要写一个try-catch-finally结构 try{//存放可能会抛出异常的代码 //3.创建普通字符输出流对象 //out = new BufferedWriter(new FileWriter(new File("E:\\ready\\2.txt"))); //out = new BufferedWriter(new FileWriter("E:\\ready\\2.txt")); out = new BufferedWriter(new FileWriter("E:\\ready\\2.txt",true)); //4.使用流对象 out.write(100); out.write(100); out.write(100); out.write(100); out.write(100); }catch (Exception e){//匹配并捕获异常 e.printStackTrace();//如果捕获到异常就打印错误信息 }finally {//一定会被执行到的代码块,常用于关流 try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } //创建一个用于测试普通字符输出流的方法 private static void method() { //1.创建一个在本方法都生效的局部变量,值为null,注意手动初始化!!! Writer out = null; //2.由于程序可能会抛出异常,所以需要写一个try-catch-finally结构 try{//存放可能会抛出异常的代码 //3.创建普通字符输出流对象 //out = new FileWriter(new File("E:\\ready\\2.txt")); //out = new FileWriter("E:\\ready\\2.txt"); out = new FileWriter("E:\\ready\\2.txt",true); //4.使用流对象 out.write(98); out.write(98); out.write(98); out.write(98); }catch (Exception e){//匹配并捕获异常 e.printStackTrace();//如果捕获到异常就打印错误信息 }finally {//一定会被执行到的代码块,常用于关流 try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } }
通过学习以上的几种流,我们也可以拓展尝试做下文件的复制:
创建包: cn.tedu.file
创建类: TestCopyFile.java
package cn.tedu.file; import java.io.*; import java.util.Scanner; /*本类用于练习文件复制综合案例*/ public class TestCopyFile { public static void main(String[] args) { //1.提示并接收用户输入的源文件路径和目标位置 System.out.println("请您输入源文件路径:"); String f = new Scanner(System.in).nextLine(); System.out.println("请您输入目标位置:"); String t = new Scanner(System.in).nextLine(); //2.调用方法完成文件的复制 //ZFCopy(f,t);//用字符流完成复制案例 ZJCopy(f,t);//用字节流完成复制案例 } private static void ZJCopy(String f,String t) { //1.定义在整个方法中都生效的局部变量,手动初始化值为null InputStream in = null; OutputStream out = null; //2.由于代码可能会发生异常,所以需要try-catch-finally结构 try{ //3.1创建高效/缓冲字节输入流,参数是f in = new BufferedInputStream(new FileInputStream(f)); //3.2创建高效/缓冲字节输出流,参数是t out = new BufferedOutputStream(new FileOutputStream(t)); //4.创建好流对象以后就可以通过流对象完成业务了 //4.1定义变量保存读到的数据 int b; //4.2使用循环完成复制操作 while((b=in.read())!=-1){ out.write(b); } System.out.println("恭喜您~文件复制成功~"); }catch(Exception e){ System.out.println("很抱歉~文件复制失败~"); e.printStackTrace(); }finally { //5.关流 try { out.close(); } catch (IOException e) { e.printStackTrace(); } try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } private static void ZFCopy(String f,String t) { //1.定义在整个方法中都生效的局部变量,手动初始化值为null Reader in = null; Writer out = null; //2.由于代码可能会发生异常,所以需要try-catch-finally结构 try{ //3.1创建高效/缓冲字符输入流,传入的参数是源文件的路径 in = new BufferedReader(new FileReader(f)); //3.2创建高效/缓冲字符输出流,传入的参数是目标文件的路径 out = new BufferedWriter(new FileWriter(t)); //4.拿到流对象以后,就可以使用流对象来完成业务了 //4.1定义变量用来记录读到的数据 int b; //4.2循环读取目标文件,直到返回值为-1,没有数据时结束循环 while((b=in.read())!=-1){ out.write(b);/*将本次循环从源文件读到的内容写出到目标文件中*/ } System.out.println("恭喜您!文件复制成功!"); }catch (Exception e){ System.out.println("很抱歉!文件复制失败!"); e.printStackTrace(); }finally { /*关流是有顺序的:如果有多个流,最后创建的流最先关闭 * 多条关流语句需要各自try-catch*/ try { out.close(); } catch (IOException e) { e.printStackTrace(); } try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } }
1.按照方向进行分类:输入流 输出流(相对于程序而言,从程序写数据到文件中是输出)
2.按照传输类型进行分类:字节流 字符流
3.组合: 字节输入流 字节输出流 字符输入流 字符输出流
InputStream 抽象类,不能new,可以作为超类,学习其所提供的共性方法
--FileInputStream 子类,操作文件的字节输入流,普通类 --BufferedInputStream 子类,缓冲字节输入流,普通类
Reader 抽象类,不能new,可以作为超类,学习其所提供的共性方法
--FileReader,子类,操作文件的字符输入流,普通类 --BufferedReader,子类,缓冲字符输入流,普通类
OutputStream 抽象类,不能new,可以作为超类,学习其所提供的共性方法
--FileOutputStream 子类,操作文件的字节输出流,普通类 --BufferedOutputStream 子类,缓冲字节输出流,普通类
Writer 抽象类,不能new,可以作为超类,学习其所提供的共性方法
--FileWriter,子类,操作文件的字符输出流,普通类 --BufferedWriter,子类,缓冲字符输出流,普通类