IO流专题
前景
File是java.io.包下的类,File类的对象,用于代表当前操作系统的文件(可以是文件、或文件夹)
注意:File类只能对文件本身进行操作,不能读写文件里面存储的数据
IO流
用于读写数据(可以读写文件,或网络中的数据)
File:代表文本
IO流:读写数据
File
package src.com.baijing;import java.io.File;/*** 目标:掌握File创建对象,代表具体文件的方案*/public class FileTest01 {public static void main(String[] args) {//1、创建一个File对象,指代某个具体的文件File file = new File("E:/word保存/全栈技术开发/File-demo/ab.txt");System.out.println(file.exists()); //先判断存在System.out.println(file.length());//相对路径File file1 = new File("src/com/baijing/baijing.txt");System.out.println(file1.exists());}}
常用方法1:判断文件类型、获取文件信息
方法名称 | 说明 |
---|---|
public boolean exists( ) | 判断当前文件对象,对应的文件路径是否存在,存在返回true |
public boolean isFile() | 判断当前文件对象指代的是否是文件,是文件返回true,反之。 |
public boolean isDirectory( ) | 判断当前文件对象指代的是否是文件夹,是文件夹返回true,反之。 |
public String getName() | 获取文件的名称(包含后缀) |
public long length() | 心获取文件的大小,返回字节个数 |
public long lastModified() | 获取文件的最后修改时间。 |
public String getPath() | 获取创建文件对象时,使用的路径 |
public String getAbsolutePath() | 获取绝对路径 |
获取文件后缀的方法
import java.io.File;public class FileExtensionExample {public static void main(String[] args) {File file = new File("example.txt");String fileName = file.getName();String extension = "";int lastDotIndex = fileName.lastIndexOf('.');if (lastDotIndex > 0) {extension = fileName.substring(lastDotIndex + 1);}System.out.println("文件扩展名: " + extension);}
}
import java.io.File;public class FileExtensionExample {public static void main(String[] args) {File file = new File("document.pdf");String fileName = file.getName();String extension = fileName.substring(fileName.lastIndexOf(".") + 1);System.out.println("文件扩展名: " + extension);}
}
import org.apache.commons.io.FilenameUtils;
import java.io.File;public class FileExtensionExample {public static void main(String[] args) {File file = new File("image.png");String extension = FilenameUtils.getExtension(file.getName());System.out.println("文件扩展名: " + extension);}
}
- 上述方法对于没有扩展名的文件会返回空字符串
- 对于隐藏文件(如".gitignore"),方法1和方法2会正确返回空字符串
- 对于文件名中包含多个点的情况(如"archive.tar.gz"),这些方法会返回最后一个点之后的部分(“gz”)
import java.io.File;
import java.util.Optional;public class FileExtensionExample {public static Optional<String> getExtension(File file) {String fileName = file.getName();int lastDotIndex = fileName.lastIndexOf('.');if (lastDotIndex == -1 || lastDotIndex == 0 || lastDotIndex == fileName.length() - 1) {return Optional.empty();}return Optional.of(fileName.substring(lastDotIndex + 1));}public static void main(String[] args) {File file = new File("config.backup.json");Optional<String> extension = getExtension(file);extension.ifPresent(ext -> System.out.println("文件扩展名: " + ext));}
}
常用方法2:创建文件、删除文件
方法名称 | 说明 |
---|---|
public boolean createNewFile() | 创建一个新文件(文件内容为空),创建成功返回true,反之 |
public boolean mkdir() | 用于创建文件夹,注意:只能创建一级文件夹 |
public boolean mkdirs() | 用于创建文件夹,注意:可以创建多级文件夹 |
public boolean delete() | 删除文件,或者空文件,注意:不能删除非空文件夹(注意:删除后的文件不会进入回收站) |
package src.com.baijing;import java.io.File;
import java.io.IOException;/*** 目标:掌握File创建和删除文件相关的操作*/public class FileTest02 {public static void main(String[] args) throws IOException {File file = new File("E:\\test01.txt");System.out.println(file.createNewFile());File file1 = new File("E:\\baijing\\heijing\\aaa");System.out.println(file1.mkdirs());System.out.println(file.delete());System.out.println(file1.delete());}}
常用方法3:遍历文件夹
方法名称 | 说明 |
---|---|
public String[ ] list() | 获取当前目录下所有的“一级文件名称”到一个字符串数组中去返回 |
public File[ ] listFiles() | 获取当前目录下所有的“一级文件对象”到一个文件对象数组中去返回(重点) |
使用listFiles方法时的注意事项:
●当主调是文件, 或者路径不存在时,返回null
●当主调是空文件夹时, 返回一个长度为0的数组
●当主调是一个有内容的文件夹时,将里面所有一级文件和文件夹的路径放在File数组中返回
●当主调是一个文件夹, 且里面有隐藏文件时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
●当主调是一个文件夹, 但是没有权限访问该文件夹时,返回null
前置知识:方法递归
认识递归的形式
方法调用自身的形式称为方法递归
应用、执行流程、算法思想
略
其他应用:文件搜索
需求:从E盘中,搜索“队列.docx”这个文件,找到后直接输出其位置。
分析:
- 先找出E盘下的所有一级文件对象
- 遍历全部一级文件对象,判断是否是文件
- 如果是文件,判断是否是自己想要的
- 如果是文件夹,需要继续进入到该文件夹,重复上述过程
package src.com.baijing;import java.io.File;public class FileTest03 {public static void main(String[] args) {findDir(new File("E:/"),"队列.docx");}public static void findDir(File file,String obj){if(file == null || !file.exists() || file.isFile()){return;}File[] files = file.listFiles();if(files != null && files.length > 0){for(File f : files){if(f.isDirectory()){findDir(f,obj);}else{if(f.getName().equals(obj)){System.out.println("找到了文件:" + f.getAbsolutePath());}}}}}
}
前置知识:字符集
常见的字符集介绍
GBK(汉字内码扩展规范,国标)
- 汉字编码字符集,包含了2万多个汉字等字符,GBK中一个中文字符编码成两个字节的形式存储,英文和数字只占一个字节。
- GBK兼容了字符集
- GBK规定:汉字的第一个字节的第一位必须是1
- ASCII一个字符编码以一个字节的形式存储
Unicode字符集(统一码,也叫万国码)
- Unicode是国际组织制定,可以容纳世界上所有文字、符号的字符集
- UTF-32——4个字节表示一个字符——奢侈,占存储空间,通信效率低下!
UTF-8
-
是Unicode字符集的一种编码方式,采取可变长编码方案,共分四个长度区:1个字节、2个字节、3个字节、4个字节
-
英文字符、数字等只占一个字节(兼容标准ASCII编码),汉字字符占3个字节
-
-
技术人员在开发时都应该使用UTF-8编码!
字符编码时使用的字符集,和解码时使用的字符集必须一致,否则会出现乱码
英文、数字一般不会乱码,因为很多字符集都兼容了ASCII编码
字符集的编码、解码操作
编码:把字符按照指定字符集编码成字节
解码:把字节按照指定字符集解码成字符
Java代码完成对字符的编码
String提供了如下方法 | 说明 |
---|---|
byte[ ] getBytes( ) | 使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中 |
byte[ ] getBytes(String charsetName) | 使用指定的字符集将String编码为一系列字节,将结果存储到新的字节数组中 |
Java代码完成对字符的解码
String提供了如下方法 | 说明 |
---|---|
String(byte[ ] bytes) | 通过使用平台的默认字符集解码指定的字节数组来构造新的String |
String(byte[ ] bytes,String charsetName) | 通过指定的字符集解码指定的字节数组来构造新的String |
package src.com.baijing;import java.io.UnsupportedEncodingException;
import java.util.Arrays;public class ByteTest01 {public static void main(String[] args) throws UnsupportedEncodingException {//编码String data = "a我b";byte[] bytes = data.getBytes(); //默认是按照平台字符集(UTF-8)进行编码的。System.out.println(Arrays.toString(bytes));//按照指定字符集编码byte[] bytes2 = data.getBytes("GBK"); //指定GBK字符集进行编码。System.out.println(Arrays.toString(bytes2));//解码String str = new String(bytes2, "GBK");System.out.println(str);String str2 = new String(bytes);System.out.println(str2);}}
[97, -26, -120, -111, 98]
[97, -50, -46, 98]
a我b
a我b
IO流概述
- 先搞清楚IO流的分类、体系
- 再挨个学习每个IO流的作用、用法
总结流的四大类:
- 字节输入流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流
- 字节输出流:以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中去的流。
- 字符输入流:以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入到内存中去的流。
- 字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中去的流。
文件字节输入流
构造器 | 说明 |
---|---|
public FileInputStream( File file ) | 创建字节输入流管道与源文件接通 |
public FileInputStream( String pathname ) | 创建字节输入流管道与源文件接通 |
方法名称 | 说明 |
---|---|
public int read( ) | 每次读取一个字节返回,如果发现没有数据可读取会返回 -1. |
public int read( byte[ ] buffer ) | 每次用一个字节数组去读取数据,返回字节数组读取了多少个字节,如果发现没有数据可读取,会返回-1. |
每次读取一个字节
package src.com.baijing;import java.io.*;public class FileInputStreamTest {public static void main(String[] args) throws IOException {//1、创建文件字节输入流管道,与源文件接通InputStream fis = new FileInputStream(new File("src/com/baijing/baijing.txt"));//简化写法InputStream is = new FileInputStream(("src/com/baijing/baijing.txt"));//2、开始读取文件的字节数据int read = is.read();System.out.print((char) read);int read2 = is.read();System.out.print((char) read2);int read3 = is.read();System.out.print(read3);}
}
ab-1
package src.com.baijing;import java.io.*;public class FileInputStreamTest {public static void main(String[] args) throws IOException {//1、创建文件字节输入流管道,与源文件接通
// InputStream fis = new FileInputStream(new File("src/com/baijing/baijing.txt"));//简化写法InputStream is = new FileInputStream(("src/com/baijing/baijing.txt"));//2、开始读取文件的字节数据
// int read = is.read();
// System.out.print((char) read);
// int read2 = is.read();
// System.out.print((char) read2);
// int read3 = is.read();
// System.out.print(read3);//3、使用循环改造上述代码int b = 0;//用于记住读取的字节while((b = is.read())!=-1){System.out.print((char)b);}//上述代码,读取数据源的性能很差!//读取数字,会出现乱码!且无法避免!//流使用完毕后,必须关闭!is.close();}}
每次读取多个字节
package src.com.baijing;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;public class FileInputStreamTest02 {public static void main(String[] args) throws IOException {//1、创建一个字节输入流对象代表字节输入流管道与源文件接通InputStream is = new FileInputStream(("src/com/baijing/baijing.txt"));//2、开始读取文件中的字节数据,每次读取多个字节byte[] buffer = new byte[11];int len = 0;len = is.read(buffer);String rs = new String(buffer);System.out.println(rs);System.out.println("读取的字节数:" + len);//注意:读取多少,倒出多少int len2 = is.read(buffer);System.out.println(new String(buffer));System.out.println("读取的字节数:" + len2);int len3 = is.read(buffer);System.out.println(new String(buffer));System.out.println("读取的字节数:" + len3);is.close();}}
abasddddddd
读取的字节数:11
dddsaffffff
读取的字节数:11
dddsaffffff
读取的字节数:-1
package src.com.baijing;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;public class FileInputStreamTest02 {public static void main(String[] args) throws IOException {//1、创建一个字节输入流对象代表字节输入流管道与源文件接通InputStream is = new FileInputStream(("src/com/baijing/baijing.txt"));//2、开始读取文件中的字节数据,每次读取多个字节
// byte[] buffer = new byte[11];
// int len = 0;
// len = is.read(buffer);
// String rs = new String(buffer);
// System.out.println(rs);
// System.out.println("读取的字节数:" + len);
//
// //注意:读取多少,倒出多少
// int len2 = is.read(buffer);
// System.out.println(new String(buffer));
// System.out.println("读取的字节数:" + len2);
//
// int len3 = is.read(buffer);
// System.out.println(new String(buffer));
// System.out.println("读取的字节数:" + len3);//3、使用循环改造byte[] b = new byte[11];int len;while ((len = is.read(b)) != -1) {System.out.println(new String(b, 0, len));}//性能得到了明显提升!!//这种方案也不能避免出现中文乱码!!(巧合除外,汉字占据三个字节,英文占据一个字节)is.close();}}
abasddddddd
dddsaffffff
一次读取完全部字节
可以解决字节流读取中文输出乱码的问题!
方式一:自己定义一个字节数组与被读取的文件大小一样大,然后使用该字节数组,一次读完文件的全部字节
方法名称 | 说明 |
---|---|
public int read( byte[ ] buffer ) | 每次用一个字节数组去读取,返回字节数组读取了多少个字节,如果发现没有数据可读,会返回-1. |
package src.com.baijing;import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;public class FileInputStreamTest03 {public static void main(String[] args) throws IOException {FileInputStream fs = new FileInputStream("src/com/baijing/baijing.txt");File file = new File("src/com/baijing/baijing.txt");long size = file.length();System.out.println("size: " + size);byte[] buffer = new byte[(int)size];int len = fs.read(buffer);System.out.println("len: " + len);System.out.println(new String(buffer));fs.close();}}
size: 22
len: 22
abasddddddddddsaffffff
方式二:Java官方为InputStream提供了如下方法,可以直接把文件的全部字节读取到一个字节数组中去
方法名称 | 说明 |
---|---|
public byte[ ] readAllBytes( ) throws IOException | 直接将当前字节输入流对应的文件对象的字节数据装到一个字节数组返回 |
package src.com.baijing;import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;public class FileInputStreamTest03 {public static void main(String[] args) throws IOException {//1、一次性读取完文件的全部字节到一个字节数组中去FileInputStream fs = new FileInputStream("src/com/baijing/baijing.txt");//2、准备一个字节数组,大小为文件大小正好一致!
// File file = new File("src/com/baijing/baijing.txt");
// long size = file.length();
// System.out.println("size: " + size);
// byte[] buffer = new byte[(int)size];
// int len = fs.read(buffer);
// System.out.println("len: " + len);
// System.out.println(new String(buffer));byte[] buffer = fs.readAllBytes();System.out.println(new String(buffer));fs.close();}}
abasddddddddddsaffffff
隐患:
- 如果文件过大,创建的字节数组也会过大,可能引起内存溢出
- 读写文本内容更适合用字符流
- 字节流适合做数据的转移,如文件复制等
文件字节输出流
写字节出去(FileOutputStream)
构造器 | 说明 |
---|---|
public FileOutputStream( File file ) | 创建字节输出流管道与源文件对象接通 |
public FileOutputStream( String filepath ) | 创建字节输出流管道与源文件路径接通 |
public FileOutputStream( File file, boolean append ) | 创建字节输出流管道与源文件对象接通,可追加数据 |
public FileOutputStream( String filepath, boolean append ) | 创建字节输出流管道与源文件路径接通,可追加数据 |
方法名称 | 说明 |
---|---|
public void write( int a ) | 写一个字节出去 |
public void write( byte[ ] buffer ) | 写一个字节数组出去 |
public void write( byte[ ] buffer, int pos, int len ) | 写一个字节数组的一部分出去 |
public void close( ) throws IOException | 关闭流 |
package src.com.baijing;import java.io.FileOutputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;/*** 掌握文件字节输出流FileOutputStream的使用*/public class FileOutputStreamTest04 {public static void main(String[] args) throws Exception {//1、创建一个字节输出流管道与目标文件接通。//true表示追加写入OutputStream fileOutputStream = new FileOutputStream("src/com/baijing/baijing.txt",true);//2、开始写字节数据出去了fileOutputStream.write(97);//97就是一个字节,代表afileOutputStream.write('b');//'b'也是一个字节
// fileOutputStream.write('井');//,默认只能写出一个字节,汉字是三个字节byte[] bytes = "我是白井".getBytes();fileOutputStream.write(bytes);System.out.println(bytes.length);fileOutputStream.write(bytes,0,bytes.length);//换行符fileOutputStream.write("\r\n".getBytes());fileOutputStream.close();}}
案例:文件复制(字节流最优)
package src.com.baijing;import java.io.*;/*** 目标:使用字节流玩成对文件的复制操作*/public class CopyTest {public static void main(String[] args) throws Exception {//需求:复制照片(其他后缀类型也可,比如.txt,不止针对图片)//1、创建一个字节输入流管道与源文件接通InputStream is = new FileInputStream("D:/resource/meinv.png");//2、创建一个字节输出流管道与目标文件接通OutputStream os = new FileOutputStream("C:/data/meinv.png");//3、创建一个字节数组,负责转移字节数据byte[] buffer = new byte[1024];//1KB//4、从字节输入流中读取字节数据,写出去到字节输出流中,读多少,写出去多少int len; //记住每次读取了多少个字节while((len = is.read(buffer)) != -1){os.write(buffer, 0, len);}os.close();is.close();System.out.println("Done");}}
字节流非常适合做一切文件的复制操作
任何文件的底层都是字节,字节流做复制,是一字不漏的转移完全部字节,只要复制后的文件格式一致就没问题!
释放资源的方式
try-catch-finally
finally代码区的特点:无论try中的程序是正常执行了,还是出现异常,最后都一定执行finally区,除非JVM终止。
千万不要在finally中返回数据!
finally的作用:一般用于在程序执行完成之后进行资源的释放操作(专业级做法)。
优化上述文件复制案例
package src.com.baijing;import java.io.*;public class Finally {public static void main(String[] args) throws IOException {//需求:复制照片InputStream is = null;OutputStream os = null;try{System.out.println(2/0);//1、创建一个字节输入流管道与源文件接通is = new FileInputStream("D:/resource/meinv.png");//2、创建一个字节输出流管道与目标文件接通os = new FileOutputStream("C:/data/meinv.png");System.out.println(2/0);//3、创建一个字节数组,负责转移字节数据byte[] buffer = new byte[1024];//1KB//4、从字节输入流中读取字节数据,写出去到字节输出流中,读多少,写出去多少int len; //记住每次读取了多少个字节while((len = is.read(buffer)) != -1){os.write(buffer, 0, len);}System.out.println("Done");}catch(Exception e){e.printStackTrace();}finally {//释放资源的操作try{if(os != null) os.close();}catch(Exception e){e.printStackTrace();}try{if(is != null) is.close();}catch(Exception e){e.printStackTrace();}}}
}
try-with-resource
JDK7开始提供更简单的资源释放方式:try-with-resource
该资源使用完毕后,会自动调用其close( )方法,完成对资源的释放!
package src.com.baijing;import java.io.*;public class Finally {public static void main(String[] args) throws IOException {//需求:复制照片try(//1、创建一个字节输入流管道与源文件接通InputStream is = new FileInputStream("D:/resource/meinv.png");//2、创建一个字节输出流管道与目标文件接通OutputStream os = new FileOutputStream("C:/data/meinv.png");//注意:这里只能防止资源对象。(流对象)//什么是资源?资源都是会实现AutoCloseable接口。资源都会有一个close方法,并且资源放到这里后//用完之后,会被自动调用其close方法,以完成对资源的释放!){//3、创建一个字节数组,负责转移字节数据byte[] buffer = new byte[1024];//1KB//4、从字节输入流中读取字节数据,写出去到字节输出流中,读多少,写出去多少int len; //记住每次读取了多少个字节while((len = is.read(buffer)) != -1){os.write(buffer, 0, len);}System.out.println("Done");}catch(Exception e){e.printStackTrace();}}
}
IO流-字符流
字节流:适合复制文件等,不适合读写文本文件
字符流:适合读写文本文件内容
FileReader(文件字符输入流)
作用:以内存为基准,可以把文件中的数据以字符的形式读入到内存中去。
构造器 | 说明 |
---|---|
public FileReader(File file) | 创建字符输入流与源文件接通 |
public FileReader(String pathname) | 创建字符输入流管道与源文件接通 |
方法名称 | 说明 |
---|---|
public int read() | 每次读取一个字符返回,如果发现没有数据可读会返回-1 |
public int read(char[ ] buffer) | 每次用一个字符数组去读取数据,返回字符数组读取了多少个字符,如果发现没有数据可读取会返回-1 |
package src.com.baijing;import java.io.FileReader;/*** 目标:掌握文件字符输入流每次读取一个字符*/public class FileReaderTest01 {public static void main(String[] args) {try(//1、创建一个文件字符输入流管道与源文件接通FileReader fileReader = new FileReader("src/com/baijing/baijingFile.txt")){//2、读取文件文件内容int c;while((c = fileReader.read())!= -1){System.out.print((char)c);}}catch(Exception e){e.printStackTrace();}}
}
每次读取一个字符的形式,性能肯定是比较差的。
每次读取多个字符
package src.com.baijing;import java.io.FileReader;/*** 目标:掌握文件字符输入流每次读取一个字符*/public class FileReaderTest01 {public static void main(String[] args) {try(//1、创建一个文件字符输入流管道与源文件接通FileReader fileReader = new FileReader("src/com/baijing/baijingFile.txt")){//2、读取文件文件内容
// int c;
// while((c = fileReader.read())!= -1){
// System.out.print((char)c);
// }//3、每次读取多个字符char[] chars = new char[1024];int len;while((len = fileReader.read(chars)) != -1){System.out.print(new String(chars,0,len));}}catch(Exception e){e.printStackTrace();}}
}
每次 fileReader.read(chars)
都会从文件的当前位置继续读取,不会覆盖之前已经读取的内容。这是因为 FileReader
内部维护了一个 文件指针(file pointer),它会自动记录当前读取的位置,确保每次 read()
都是接着上次的位置继续读取,而不会重复读取或覆盖已读取的数据。
FileWriter(文件字符输出流)
作用:以内存为基准,把内存中的数据以字符的形式写出到文件中去。
构造器 | 说明 |
---|---|
public FileWriter(File file) | 创建字节输出流管道与源文件对象接通 |
public FileWriter(String filepath) | 创建字节输出流管道与源文件路径接通 |
public FileWriter(File file,boolean append) | 创建字节输出流管道与源文件对象接通,可追加数据 |
public FileWriter(String filepath,boolean append) | 创建字节输出流管道与源文件路径接通,可追加数据 |
方法名称 | 说明 |
---|---|
void write(int c) | 写一个字符 |
void write(String str) | 写一个字符串 |
void write(String str,int off,int len) | 写一个字符串的一部分 |
void write(char[] cbuf) | 写入一个字符数组 |
void write(char[] cbuf,int off,int len) | 写入字符数组的一部分 |
ctrl + alt + T:选中一块代码,可以快速生成try-catch块
package src.com.baijing;import java.io.FileWriter;
import java.io.IOException;/*** 目标:掌握文件字符输出流:写字符数据出去。*/public class FileWriterTest02 {public static void main(String[] args) throws IOException {try (//0、创建一个文件字符输出流管道与目标文件接通FileWriter fileWriter = new FileWriter("src/com/baijing/baijingFile.txt",true);)//这里的true表示追加数据{fileWriter.write("我是黑井\n");;fileWriter.write("我是黑井abc\n",0,4);//写字符数组char[] chars = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};fileWriter.write(chars);//换行fileWriter.write("\n");//写字符数组的某一部分fileWriter.write(chars,3,5);} catch (IOException e) {throw new RuntimeException(e);}}
}
注意事项
字符输出流写出数据后,必须刷新流,或者关闭流,写出去的数据才能生效
fw.close()
IO流-缓冲流
作用:对原始流进行包装,以提高原始流读写数据的性能
包装流、处理流
原理:字节缓冲输入流自带了8KB缓冲池;字节缓冲输出流也自带了8KB缓冲池
构造器 | 说明 |
---|---|
public BufferedInputStream(InputStream is) | 把低级的字节输入流包装到一个高级的缓冲字节输入流,从而提高读数据的性能 |
public BufferedOutputStream(OutputStream os) | 把低级的字节输出流包装到一个高级的缓冲字节输出流,从而提高写数据的性能 |
package src.com.baijing;import java.io.*;public class BufferInputStreamTest01 {public static void main(String[] args) throws FileNotFoundException {try(InputStream fileReader = new FileInputStream("src/com/baijing/baijing.txt");InputStream bufferedReader = new BufferedInputStream(fileReader);OutputStream fileOutputStream = new FileOutputStream("src/com/baijing/baijing_copy.txt");OutputStream bufferedWriter = new BufferedOutputStream(fileOutputStream);){byte[] chars = new byte[1024];int len;while((len = bufferedReader.read(chars)) != -1){bufferedWriter.write(chars, 0, len);}}catch(Exception e){e.printStackTrace();}}
}
package src.com.baijing;import java.io.*;public class BufferInputStreamTest01 {public static void main(String[] args) throws FileNotFoundException {try(InputStream fileReader = new FileInputStream("src/com/baijing/baijing.txt");InputStream bufferedReader = new BufferedInputStream(fileReader,8192 * 2);//这里可以设置缓冲区大小为8192*2,默认是8192,即8KBOutputStream fileOutputStream = new FileOutputStream("src/com/baijing/baijing_copy.txt");OutputStream bufferedWriter = new BufferedOutputStream(fileOutputStream);){byte[] chars = new byte[1024];int len;while((len = bufferedReader.read(chars)) != -1){bufferedWriter.write(chars, 0, len);}}catch(Exception e){e.printStackTrace();}}
}
字符缓冲输入流
BufferedReader
作用:自带8K(8192)的字符缓冲池,可以提高字符输入流读取字符数据的性能
构造器 | 说明 |
---|---|
public BufferedReader(Reader r) | 把低级的字符输入流包装成字符缓冲输入流管道,从而提高字符输入流读字符数据的性能 |
字符缓冲输入流新增的功能:按照行读取字符
方法 | 说明 |
---|---|
public String readLine() | 读取一行数据返回,如果没有数据可读了,会返回null |
package src.com.baijing;import java.io.*;public class BufferReaderTest01 {public static void main(String[] args) throws FileNotFoundException {try(Reader fileReader = new FileReader("src/com/baijing/baijingFile.txt");BufferedReader bufferedReader = new BufferedReader(fileReader)) {//读取
// char[] buf = new char[1024];
// int len = 0;
// while ((len = bufferedReader.read(buf))!= -1) {
// System.out.println(new String(buf, 0, len));
// }//读取一行String line = bufferedReader.readLine();while (line!= null) {System.out.println(line);line = bufferedReader.readLine();}}catch (IOException e) {throw new RuntimeException(e);}}
}
字符缓冲输出流
BufferedWriter
作用:自带8K的字符缓冲池,可以提高字符输出流写字符数据的性能
构造器 | 说明 |
---|---|
public BufferedWriter(Writer r) | 把低级的字符输出流包装成字符缓冲输出流管道,从而提高字符输出流写字符数据的性能 |
字符缓冲输出流新增的功能:换行
方法 | 说明 |
---|---|
public void newLine() | 换行 |
原始流、缓冲流的性能分析【重点】
测试用例:
分别使用原始的字节流,以及字节缓冲流复制一个很大的视频
IO流-转换流
不同编码读取时,会出现乱码
如果代码编码和被读取的文本文件的编码是一致的,使用字符流读取文本文件时不会出现乱码!
如果代码编码和被读取的文本文件的编码是不一致的,使用字符流读取文本文件时就会出现乱码!
解决以上问题
字符输入转换流
解决思路:先获取文件的原始字节流,再将其按真实的字符集编码转成字符输入流,这样字符输入流中的字符救不乱码了。
构造器 | 说明 |
---|---|
public InputStreamReader(InputStream is) | 把原始的字节输入流,按照代码默认编码转成字符输入流(与直接用FileReader的效果一样) |
public InputStreamReader(InputStream is,String charset) | 把原始的字节输入流,按照指定字符集编码转成字符输入流(重点) |
字符输出转换流
控制写出去的字符使用什么字符集编码
解决思路:先获取字节输出流,再将其按真实的字符集编码转成字符输出流,以后写出去的字符就会用该字符集编码了。
除了使用字符输出转换流,还可以调用String提供的getBytes方法解决:
String data = "我爱你中国abc";
byte[] bytes = data.getBytes("GBK");
构造器 | 说明 |
---|---|
public OutputStreamWriter(OutputStream os) | 把原始的字节输出流,按照代码默认编码转换成字符输出流 |
public OutputStreamWriter(OutputStream os,String charset) | 把原始的字节输出流,按照指定字符集编码转成字符输出流(重点) |
IO流-打印流
作用:打印流可以实现更方便、更高效的打印数据出去,能实现打印啥出去就是啥出去
构造器 | 说明 |
---|---|
public PrintStream(OutputStream/File/String) | 打印流直接通向字节输出流/文件/文件路径 |
public PrintStream(String fileName,Charset charset) | 可以指定写出去的字符编码 |
public PrintStream(OutputStream out,boolean autoFlush) | 可以指定实现自动刷新 |
public PrintStream(OutputStream out,boolean autoFlush,String encoding) | 可以指定实现自动刷新,并可指定字符的编码 |
方法 | 说明 |
---|---|
public void println(Xxx xxx) | 打印任意类型的数据出去 |
public void write(int/byte[ ]/byte[ ]一部分) | 可以支持写字节数据出去 |
package src.com.baijing;
import java.io.PrintStream;
public class PrintStreams {public static void main(String[] args) {try (PrintStream ps = new PrintStream("src/com/baijing/baijingFiles.txt")){ps.println("纳米好评");ps.println("aaa");ps.println(97);ps.println("纳米好评");ps.println("纳米好评");ps.write(97);} catch (Exception e) {throw new RuntimeException(e);}}
}
文本文件中将显示:
纳米好评
aaa
97
纳米好评
纳米好评
a
构造器 | 说明 |
---|---|
public PrintWriter(OutputStream/Writer/File/String) | 打印流直接通向字节输出流/文件/文件路径 |
public PrintWriter(String fileName,Charset charset) | 可以指定写出去的字符编码 |
public PrintWriter(OutputStream out/Writer,boolean autoFlush) | 可以指定实现自动刷新 |
public PrintWriter(OutputStream out,boolean autoFlush,String encoding) | 可以指定实现自动刷新,并可指定字符的编码 |
方法 | 说明 |
---|---|
public void println(Xxx xxx) | 打印任意类型的数据出去 |
public void write(int/String/char[ ]/…) | 可以支持写字符数据出去 |
package src.com.baijing;
import java.io.PrintStream;
import java.io.PrintWriter;public class PrintStreams {public static void main(String[] args) {try (PrintWriter ps = new PrintWriter("src/com/baijing/baijingFiles.txt")){ps.println("纳米好评");ps.println("aaa");ps.println(97);ps.println("纳米好评");ps.println("纳米好评");ps.write(97);} catch (Exception e) {throw new RuntimeException(e);}}
}
纳米好评
aaa
97
纳米好评
纳米好评
a
打印流无法实现追加数据!
打印流都是使用方便,性能高效!(核心优势)
打印流的应用
输出语句的重定向:可以把输出语句的打印位置改到某个文件中去
package src.com.baijing;import java.io.FileNotFoundException;
import java.io.PrintStream;public class PrintTest02 {public static void main(String[] args) throws FileNotFoundException {System.out.println("我是白井");System.out.println("我是黑井");try(PrintStream printStream = new PrintStream("src/com/baijing/baijingFiles.txt");) {//把系统默认的打印流对象改成自己创建的PrintStream对象System.setOut(printStream);System.out.println("纳米好评");System.out.println("纳米好评加一");} catch (FileNotFoundException e) {throw new RuntimeException(e);}}
}
IO流-数据流
数据输出流
允许把数据和其他类型一并写出去。
构造器 | 说明 |
---|---|
public DataOutStream(OutputStream out) | 创建新数据输出流包装基础的字节输出流 |
方法 | 说明 |
---|---|
public final void writeByte(int v) throws IOException | 将byte类型的数据写入基础的字节输出流(几乎不用) |
public final void writeInt(int v) throws IOException | 将int类型的数据写入基础的字节输出流 |
public final void writeDouble(Double v) throws IOException | 将double类型的数据写入基础的字节输出流 |
public final void writeUTF(String str) throws IOException | 将字符串数据以UTF-8编码成字节写入基础的字节输出流 |
public void write(int/byte[ ]/byte[ ]一部分) | 支持写字节数据出去 |
package src.com.baijing;import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;public class DataOutputStreams {public static void main(String[] args) {try (DataOutputStream dos = new DataOutputStream(new FileOutputStream("src/com/baijing/baijingFiles.txt"))){dos.writeUTF("白井");dos.writeInt(18);dos.writeDouble(3.1415926);dos.writeBoolean(true);} catch (Exception e) {throw new RuntimeException(e);}}
}
打印(正常现象):
数据输入流
用于读取数据输出流写出去的数据
构造器 | 说明 |
---|---|
public DataInputStream(InputStream is) | 创建新数据输入流包装基础的字节输入流 |
方法 | 说明 |
---|---|
public final void readByte(int v) throws IOException | 读取字节数据返回 |
public final void readInt(int v) throws IOException | 读取int类型的数据返回 |
public final void readDouble(Double v) throws IOException | 读取double类型的数据返回 |
public final void readUTF(String str) throws IOException | 读取字符串数(UTF-8)据返回 |
public void readInt / read(byte[ ]) | 支持读字节数据出去 |
代码测试同上做修改
IO流-序列化流
对象序列化:把Java对象写入到文件中去(Out)
对象反序列化:把文件里的Java对象读出来( In )
构造器 | 说明 |
---|---|
public ObjectOutputStream(OutputStream out) | 创建对象字节输出流,包装基础的字节输出流 |
方法 | 说明 |
---|---|
public final void writeObject(Object o) throws IOException | 把对象写出去 |
构造器 | 说明 |
---|---|
public ObjectInputStream(InputStream is) | 创建对象字节输入流,包装基础的字节输入流 |
方法 | 说明 |
---|---|
public final void readObject( ) | 把存储在文件中的Java对象读出来 |
被transient修饰符修饰对象的成员变量,将不参与序列化
如果要一次序列化多个对象呢?
答:用一个ArrayList集合存储多个对象,然后直接对集合进行序列化即可
注意:ArrayList集合已经实现了序列化接口!