第一节 File类
java.io.File类
文件和目录路径名的抽象表示形式
java把电脑中的文件和文件夹(目录)封装为一个File类,我们可以使用File类对文件和文件夹进行操作
我们可以使用File类的方法
创建/删除/获取一个文件/文件夹,判断文件/文件夹是否存在,对文件夹进行遍历,获取文件的大小
File类是一个与系统无关的类,任何的操作系统都可以使用这个类中的方法
重点:记住三个单词
file:文件
directory:文件夹/目录
path:路径
1.1 静态成员变量
static String pathSeparator 与系统有关的路径分隔符,为了方便,它被表示为一个字符串
static char pathSeparatorChar 与系统有关的路径分隔符
static String pathSeparator 与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串
static char pathSeparatorChar 与系统有关的默认名称分隔符
操作路径:路径不能写死了
C:\develop\a\a.txt Windows
C:/develop/a/a.txt Linux
应该写为:“C:“+File.separator+”develop“+File.separator+”a“+File.separator+”a.txt”
public class DemoFile {
public static void main(String[] args) {
String pathSeparator = File.pathSeparator;
System.out.println(pathSeparator);//路径分隔符,Windows:分号; Linux:冒号:
String separator = File.separator;
System.out.println(separator);//文件名称分隔符,Windows:反斜杠\ Linux:正斜杠/
}
}
绝对路径:是一个完整的路径,以盘符(c:,D:)开始的路径
c:\a.txt
d:\b.txt
相对路径:是一个简化的路径,相对指的是相对于当前项目的根目录
D:\Test\src\Day17\Demo01
如果使用当前项目的根目录,路径可以简化书写为Demo01
注意:
1、路径不区分大小写
2、路径中的文件名称分隔符Windows使用反斜杠,反斜杠是转义字符,两个反斜杠代表一个普通的反斜杠
1.2 构造方法
File(String pathname)通过将给定路径名字符串转换为抽象路径名来创建一个新File实例
参数:
String pathname:字符串的路径名称
路径可以是以文件结尾,也可以是以文件夹结尾
路径可以是相对路径,也可以是绝对路径
路径可以是存在,也可以是不存在
创建File对象,只是把字符串路径封装为File对象,不考虑路径的真假情况
File(String parent, String child)根据parent路径名字符串和child路径名字符串创建一个新File实例
参数:把路径分为了两部分
String parent:父路径
String child:子路径
好处:父路径和子路径可以单独书写,使用起来非常灵活;父路径和子路径都可以变化
File(File parent, String child)根据parent抽象路径名和child路径名字符串创建一个新File实例
参数:把路径分为了两部分
File parent:父路径
String child:子路径
好处:父路径和子路径可以单独书写,使用起来非常灵活;父路径和子路径都可以变化
父路径是File类型,可以使用File类的方法对路径进行一些操作,再使用路径创建对象
public class Demo01File {
public static void main(String[] args) {
demo01();
demo02("c:\\","demo01");
demo03();
}
private static void demo03() {
File file = new File("c:\\");
File file1 = new File(file,"hello.java");
System.out.println(file1);
}
private static void demo02(String parent, String child) {
File file = new File(parent, child);
System.out.println(file);
}
private static void demo01() {
File file = new File("D:\\Test\\src\\Day17\\Demo01");
System.out.println(file);
File file1 = new File("Demo01");
System.out.println(file1);
}
}
1.3 File类获取功能的方法
File类获取功能的方法
public String getAbsolutePath():返回此File的绝对路径名字符串
无论路径是绝对的还是相对的,getAbsolutePath方法返回的都是绝对路径
public String getPath():将此File转换为路径名字符串
public String getName():返回由此File表示的文件或目录的名称
获取的就是构造方法传递路径的结尾部分(文件/文件夹)
public long length():返回由此File表示的文件的长度
获取的是构造方法指向的文件的大小,以字节为单位
注意:文件夹是没有大小概念的,不能获取文件夹的大小
如果构造方法中给出的路径不存在,那么length方法返回0
public class Demo02File {
public static void main(String[] args) {
demo01();
demo02();
demo03();
demo04();
}
private static void demo04() {
File file = new File("D:\\PSR\\参数计算\\1.txt");
System.out.println(file.length());//5893
File file1 = new File("D:\\PSR\\matlab");
System.out.println(file1.length());//0,文件夹没有大小概念
}
private static void demo03() {
File file = new File("D:\\PSR\\matlab\\1.txt");
System.out.println(file.getName());//1.txt
File file1 = new File("D:\\PSR\\matlab");
System.out.println(file1.getName());//matlab
}
private static void demo02() {
File file = new File("D:\\PSR\\matlab\\1.txt");
System.out.println(file.getPath());//D:\PSR\matlab\1.txt
File file1 = new File("1.txt");
System.out.println(file1.getPath());//1.txt
}
private static void demo01() {
File file = new File("D:\\PSR\\matlab\\1.txt");
System.out.println(file.getAbsolutePath());//D:\PSR\matlab\1.txt
File file1 = new File("1.txt");
System.out.println(file1.getAbsolutePath());//D:\Test\1.txt
}
}
1.4 File类判断功能的方法
File判断功能的方法
public boolean exists():此File表示的文件或目录是否实际存在
public boolean isDirectory():此File表示的是否为目录
public boolean isFile():此File表示的是否为文件
注意:
电脑的硬盘中只有文件/文件夹,两个方法是互斥
后两个方法使用前提,路径必须是存在的,否则都返回false
public class Demo03File {
public static void main(String[] args) {
demo01();
demo02();
}
private static void demo02() {
File file = new File("D:\\PSR\\参数计算\\1.txt");
System.out.println(file.isDirectory());//fasle
File file1 = new File("D:\\PSR\\参数计算\\1.txt");
System.out.println(file1.isFile());//true
File file2 = new File("D:\\PSR\\参数计算\\2.txt");
System.out.println(file2.isDirectory());//false
File file3 = new File("D:\\PSR\\参数计算\\2.txt");
System.out.println(file3.isFile());//false
}
private static void demo01() {
File file = new File("D:\\PSR\\参数计算\\1.txt");
System.out.println(file.exists());//true
File file1 = new File("D:\\PSR\\参数计算\\2.txt");
System.out.println(file1.exists());//false
}
}
1.5 File类创建删除功能的方法
File类创建删除功能的方法
public boolean createNewFile():当且仅当具有该名称的文件尚不存在时,创建一个新的空文件
创建文件的路径和名称在构造方法中给出(构造方法的参数)
返回值:布尔值
true:文件不存在,创建文件,返回true
false:文件存在,不会创建,返回false
注意:
1、此方法只能创建文件,不能创建文件夹
2、创建文件的路径必须存在,否则会抛出异常
public boolean createNewFile() throws IOException
creatNewFile声明抛出了IOException,我们调用这个方法,就必须处理这个异常,要么throws,要么try…catch
public boolean delete():删除由此File表示的文件或目录
此方法,可以删除构造方法路径中给出的文件/文件夹
返回值:布尔值 true:文件/文件夹删除成功,返回true
false:文件夹中有内容,不会删除返回false;构造方法中路径不存在false
注意:delete方法是直接在硬盘删除文件/文件夹,不走回收站,删除要谨慎
public boolean mkdir():创建由此File表示的目录
只能创建单级空文件夹
public boolean mkdirs():创建由此File表示的目录,包括任何必需但不存在的父目录
既可以创建单级空文件夹,也可以创建多级空文件夹
创建文件夹的路径和名称在构造方法中给出(构造方法的参数)
返回值:布尔值
true:文件夹不存在,创建文件夹,返回true
false:文件夹存在,不会创建,返回false,构造方法中给出的路径不存在返回flase
注意:此方法只能创建文件夹,不能创建文件
public class Demo04File {
public static void main(String[] args) throws IOException {
demo01();
demo02();
demo03();
}
private static void demo03() {
File file = new File("D:\\PSR\\matlab\\111");
System.out.println(file.delete());
File file1 = new File("D:\\PSR\\matlab\\222");
System.out.println(file1.delete());
File file2 = new File("D:\\PSR\\matlab\\222.txt");
System.out.println(file2.delete());
File file3 = new File("D:\\PSR\\matlab\\1.txt");
System.out.println(file3.delete());
}
private static void demo02() {
File file = new File("D:\\PSR\\matlab\\111");
System.out.println(file.mkdir());
File file1 = new File("D:\\PSR\\matlab\\222\\333");
System.out.println(file1.mkdirs());
File file2 = new File("D:\\PSR\\matlab\\222.txt");
System.out.println(file2.mkdirs());//看类型,也是一个文件夹,不是文件
File file3 = new File("D:\\PSR\\matl\\222");
System.out.println(file3.mkdirs());//true
}
private static void demo01() throws IOException {
File file = new File("D:\\PSR\\matlab\\1.txt");
System.out.println(file.createNewFile());
File file1 = new File("2.txt");
System.out.println(file1.createNewFile());
//File file2 = new File("D:\\PSR\\matl\\1.txt");//错误!
//System.out.println(file2.createNewFile());//路径不对,抛出IOException
}
}
1.5 File类遍历(文件夹)目录的方法
File类遍历(文件夹)目录功能
public String[] list():返回一个String数组,表示该File目录中的所有子文件或目录
public File[] listFiles():返回一个File数组,表示该File目录中的所有的子文件或目录
注意:
list方法和listFiles方法遍历的是构造方法中给出的目录 如果构造方法中给出的目录的路径不存在,会抛出空指针异常
如果构造方法中给出的路径不是一个目录,也会抛出空指针异常引用
public class Demo05File {
public static void main(String[] args) {
demo01();
demo02();
}
/*
public File[] listFiles()
遍历构造方法中给出的目录,会获取目录中所有的文件/文件夹,把文件/文件夹封装为File对象,多个File对象存储到File数组中
*/
private static void demo02() {
File file = new File("D:\\PSR\\matlab");
File[] files = file.listFiles();
//遍历文件夹
for (File name : files) {
System.out.println(name);
}
}
/*
public String[] list()
遍历构造方法中给出的目录,会获取目录中所有文件/文件夹的名称,把获取到的多个名称存储到一个String类型的数组中
*/
private static void demo01() {
File file = new File("D:\\PSR\\matlab");
//File file1 = new File("D:\\PSR\\matla");//路径不存在,抛出NullPointerException
//File file1 = new File("D:\\PSR\\matlab\\333");//路径不是目录,抛出NullPointerException
String[] list = file.list();
//遍历文件夹
for (String name : list) {
System.out.println(name);
}
}
}
第二节 递归
2.1 递归的概念
递归:方法自己调用自己
递归的分类:直接递归和间接递归
直接递归称为方法自身调用自己
间接递归可以A方法调用B方法,B方法调用C方法,C方法调用A方法
注意事项:
1、递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出
2、在递归中虽然有限定条件,但是递归次数不能太多,否则也会发生栈内存溢出
3、构造方法,禁止递归 ,构造方法是创建对象使用的,一直递归会导致内存中有无数多个对象,直接编译报错
递归的使用前提:
当调用方法的时候,方法的主体不变,每次调用方法的参数不同,可以使用递归
public class Demo01Recurison {
public static void main(String[] args) {
demo01();
demo02(1);
}
private static void demo02(int i) {
System.out.println(i);
if (i == 10000){//递归次数不能太多
return;
}
demo02(++i);
}
private static void demo01() {
System.out.println("demo01方法");
//demo01();//抛出StackOverflowError
}
public Demo01Recurison(){
//Demo01Recurison(); 编译报错
}
}
2.2 练习1
练习:使用递归计算1-n之间的和
/*
分析:
定义一个方法,使用递归计算1-n之间的和
1+2+3+...+n
n+(n-1)+(n-2)+...+1
已知:最大值n。最小值1
使用递归必须明确:
1、递归的结束条件:获取到1的时候结束
2、递归的目的:获取下一个被加的的数字(n-1)
*/
public class Demo02Recurison {
public static void main(String[] args) {
int s = sum(3);
System.out.println(s);
}
public static int sum(int n){
if (n == 1){
return 1;
}
return n + sum(n - 1);
}
}
使用递归求和,main方法调用sum方法,sum方法会一直调用sum方法
导致在内存中有多个sum方法(频繁的创建方法,调用方法,销毁方法)效率低下
所有如果仅仅是计算1-n之间的和,不推荐使用递归,使用for循环即可
2.3 练习2
练习:使用递归计算阶乘
/*
定义方法使用递归计算阶乘
递归结束的条件:获取到1的时候结束
递归的目的:获取下一个被乘的数字(n-1)
方法的参数发生变化
*/
public class Demo03Recurison {
public static void main(String[] args) {
int jiecheng = jc(5);
System.out.println(jiecheng);
}
public static int jc(int n){
if (n == 1){
return 1;
}
return n * jc(n - 1);
}
}
2.4 练习3
练习:递归打印多级目录
/*
定义一个方法,参数传递File类型的目录
方法中对目录进行遍历
*/
public class Demo04Recurison {
public static void main(String[] args) {
File file = new File("D:\\exp");
getAllFile(file);
}
public static void getAllFile(File dir){
System.out.println(dir);
File[] files = dir.listFiles();
for (File f : files) {
//对遍历得到的File对象f进行判断,判断是否是文件夹
if (f.isDirectory()){
//f是一个文件夹,则继续遍历这个文件夹
//getAllFile方法就是传递文件夹,遍历文件夹的方法
//所以直接调用此方法即可:递归(自己调用自己)
getAllFile(f);
}else {
System.out.println(f);
}
}
}
}
2.4 文件搜索案例
搜索目录中.docx结尾的文件
public class Demo05Recurison {
public static void main(String[] args) {
File file = new File("D:\\exp");
getAllFile(file);
}
public static void getAllFile(File dir){
//System.out.println(dir);
File[] files = dir.listFiles();
for (File f : files) {
//对遍历得到的File对象f进行判断,判断是否是文件夹
if (f.isDirectory()){
//f是一个文件夹,则继续遍历这个文件夹
//getAllFile方法就是传递文件夹,遍历文件夹的方法
//所以直接调用此方法即可:递归(自己调用自己)
getAllFile(f);
}else {
/* String name = f.getName();//获取目录名称
String s = name.toLowerCase();//目录转换为小写字母
boolean b = s.endsWith(".docx");//后缀是否以.docx结尾
if (b){
System.out.println(f);
}*/
//链式编程
if (f.toString().toLowerCase().endsWith(".docx")){
System.out.println(f);
}
}
}
}
}
第三节 过滤器
过滤器的原理和使用
在File类中有两个和listFiles重载的方法,方法的参数传递的就是过滤器
File[] listFiles(FileFilter filter)
java.io.FileFilter接口:用于抽象路径名(File对象)的过滤器
作用:用来过滤文件(File对象)
抽象方法:用来过滤文件的方法
boolean accept(File pathname)测试指定抽象路径名是否应该包含在某个路径名列表中
参数:File pathname,使用listFiles方法遍历目录,得到的每一个文件对象
File[] listFiles(FilenameFilter filter)
java.io.FilenameFilter接口:实现此接口的类实例可用于过滤器文件名
作用:用于过滤文件名称
抽象方法:用来过滤文件的方法
boolean accept(File dir, String name)测试指定文件是否应该包含在某一文件列表中
参数:
File dir:构造方法中传递的被遍历的目录
String name:使用listFiles方法遍历目录,获取的每一个文件/文件夹的名称
注意:
两个过滤器接口是没有实现类的,需要我们自己写实现类,重写过滤的方法accept,在方法中自己定义过滤的规则
accept方法返回值是一个布尔值
true:就会把传递过去的File对象保存到File数组中
false:就不会把传递过去的File对象保存到File数组中
import java.io.File;
import java.io.FileFilter;
public class FileFilterImpl implements FileFilter {
@Override
public boolean accept(File pathname) {
//如果pathname是一个文件夹,返回true,继续遍历这个文件夹
if (pathname.isDirectory()){
return true;
}
//过滤的规则:
//在accept方法中,判断File对象是否是以.java结尾
//是就返回true
//不是就返回false
return pathname.toString().toLowerCase().endsWith(".docx");
}
}
public class Demo01Filter {
public static void main(String[] args) {
File file = new File("D:\\exp");
getAllFile(file);
}
public static void getAllFile(File dir){
//listFiles方法一共做了3件事情:
//1、会对构造方法中传递的目录进行遍历,获取目录中的每一个文件/文件夹-->封装为File对象
//2、会调用参数传递的过滤器中的方法accept
//3、会把遍历得到的每一个File对象,传递给accept方法的参数pathname
File[] files = dir.listFiles(new FileFilterImpl());//传递过滤器对象
for (File f : files) {
if (f.isDirectory()){
getAllFile(f);
}else {
System.out.println(f);
}
}
}
}
public class Demo02Filter {
public static void main(String[] args) {
File file = new File("D:\\exp");
getAllFile(file);
}
public static void getAllFile(File dir){
//传递过滤器对象,使用匿名内部类
/* File[] files = dir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory() || pathname.toString().toLowerCase().endsWith(".docx");
}
});*/
/*File[] files = dir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File d, String name) {
return new File(d, name).isDirectory() || name.toString().toLowerCase().endsWith(".docx");
}
});*/
//使用Lambda表达式
//File[] files = dir.listFiles((d, name) -> new File(d, name).isDirectory() || name.toString().toLowerCase().endsWith(".docx"));
//使用Lambda表达式
File[] files = dir.listFiles(pathname -> pathname.isDirectory() || pathname.toString().toLowerCase().endsWith(".docx"));
for (File f : files) {
if (f.isDirectory()){
getAllFile(f);
}else {
System.out.println(f);
}
}
}
}
第四节 IO字节流
4.1 IO概述
i:input 输入(读取),把硬盘中的数据读取到内存中使用
o:output 输出(写入),把内存中的数据写入到硬盘中保存
流:数据(字符、字节)
4.2 字节输出流
java.io.OutputStream:字节输出流此抽象类是表示输出字节流的所有类的超类
定义了一些子类共性的成员方法
public void close():关闭此输出流并释放与此流相关联的任何系统资源
public void flush():刷新此输出流并强制任何缓冲的输出字节被写出
public void write(byte[] b):将b.length字节从指定的字节数组写入此输出流
public void write(byte[] b, int off, int len):从指定的字节数组写入len字节,从偏移量off开始输出到此输出流
public abstract void write(int b):将指定的字节写入此输出流
4.3 FileOutputStream类
java.io.FileOutputStream extends OutputStream
FileOutputStream:文件字节输出流
作用:把内存中的数据写入到硬盘的文件中
构造方法:
FileOutputStream(String name)创建一个向具有指定名称的文件中写入数据的输出文件流
FileOutputStream(File file)创建一个向指定File对象表示的文件中写入数据的文件输出流
参数:写入数据的目的
String name:目的地是一个文件的路径
File file:目的地是一个文件
构造方法的作用:
1、创建一个FileOutputStream对象
2、会根据构造方法中传递的文件/文件路径,创建一个空的文件
3、会把FileOutputStream对象指向创建好的文件
写入数据的原理(内存–>硬盘)
java程序–>JVM(java虚拟机)–>OS(操作系统)–>OS调用写数据的方法–>把数据写入到文件中
字节输出流的使用步骤:
1、创建一个FileOutputStream对象,构造方法中传递写入数据的目的地
2、调用FileOutputStream对象中的方法write,把数据写入到文件中
3、释放资源(流使用会占用一定的内存,使用完毕要把内存清空,提高程序的效率)
public class Demo01OutputStream {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("D:\\Test\\src\\Day17\\Demo04\\a.txt");
fos.write(97);
fos.close();
}
}
一次写多个字节的方法:
public void write(byte[] b):将b.length字节从指定的字节数组写入此输出流
public void write(byte[] b, int off, int len):从指定的字节数组写入len字节,从偏移量off开始输出到此输出流
如果写的第一个字节是正数(0-127),那么显示的时候会查询ASCII表
如果写的第一个字节是负数,那第一个字节会和第二个字节,两个字节组成一个中文显示,查询系统默认码表(GBK)
写入字符串的方法:可以使用String类中的方法把字符串转换为字节数组
byte[] getBytes()
public class Demo02OutputStream {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("D:\\Test\\src\\Day17\\Demo04\\b.txt");
fos.write(65);
fos.write(67);
fos.write(89);
//一次写多个字节
byte[] bytes = {65, 67, 68};
fos.write(bytes);
byte[] bytesA = {-65, -67, -68};
fos.write(bytesA);
byte[] bytesB = {-65, -67, -68};
fos.write(bytesB,1,2);
byte[] byteC = "小松狮".getBytes();
System.out.println(Arrays.toString(byteC));//[-27, -80, -113, -26, -99, -66, -25, -117, -82]
fos.write(byteC);
fos.close();
}
}
追加写/续写:使用两个参数的构造方法
FileOutputStream(String name, boolean append)创建一个向具有指定name的文件夹中写入数据的输出文件流
FileOutputStream(File file, boolean append)创建一个向指定File对象表示的文件中写入数据的文件输出流
参数:
String name,File file:写入数据的目的地
boolean append:追加写开关
true:创建对象不会覆盖源文件,继续在文件的末尾追加写数据
false:创建一个新文件,覆盖源文件
写换行:写换行符号
windows:\r\n
Linux:/n
max:/r
public class Demo03OutputStream {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("D:\\Test\\src\\Day17\\Demo04\\c.txt",true);
for (int i = 0; i < 10; i++) {
fos.write("你好小松狮".getBytes(StandardCharsets.UTF_8));
fos.write("\r\n".getBytes(StandardCharsets.UTF_8));
}
fos.close();
}
}
4.4 字节输入流
java.io.InputStream:字节输入流
此抽象类是表示字节输入流的所有类的超类
定义了所有子类共性的方法:
int read()从输入流中读取数据的下一个字节
int read(byte[] b)从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中
void close()关闭此输入流并释放与该流关联的所有系统资源
4.5 FileInputStream类
java.io.FileInputStream extends InputStream
FileInputStream:文件字节输入流
作用:把硬盘文件中的数据,读取到内存中使用
构造方法:
FileInputStream(String name)
FileInputStream(File file)
参数:读取文件的数据源
String name:文件的路径
File file:文件
构造方法的作用:
1、会创建一个FileInputStream对象
2、会把FileInputStream对象指定构造方法中要读取的文件
读取数据的原理(硬盘–>内存)
java程序–>JVM–>OS–>OS读取数据的方法–>读取文件
字节输入流的使用步骤:
1、创建FileInputStream对象,构造方法中绑定要读取的数据源
2、使用FileInputStream对象中的方法read,读取文件
3、释放资源
public class Demo04InputStream {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("D:\\Test\\src\\Day17\\Demo04\\b.txt");
//int read()读取文件中的一个字节并返回,读取到文件的末尾返回-1
/*int read = fis.read();
System.out.println(read);
int read1 = fis.read();
System.out.println(read1);*/
/*
发现以上读取文件是一个重复的过程,所以可以使用循环优化
不知道文件中有多少字节,使用while循环
while循环结束条件,读取到-1的时候结束
布尔表达式(len = fis.read()) != -1
1、fis.read():读取一个字节
2、len = fis.read():把读取到的字节赋值给变量len
3、(len = fis.read()) != -1:判断变量len是否不等于-1
*/
int len = 0;
while ((len = fis.read()) != -1){
System.out.println((char)len);
}
fis.close();
}
}
字节输入流一次读取多个字节的方法:
int read(byte[] b)从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中
明确两件事情:
1、方法的参数byte[]的作用?
起到缓冲作用,存储每次读取到的多个字节
数组的长度一般定义为1024(1kb)或者1024的整数倍
2、方法的返回值int是什么?
每次读取的有效字节个数
String类的构造方法
String(byte[] bytes):把字节数组转换为字符串
String(byte[] bytes, int offset, int length):把字节数组的一部分转换为字符串
public class Demo05InputStream {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("D:\\Test\\src\\Day17\\Demo04\\c.txt");
/*byte[] bytes = new byte[2];
int len = fis.read(bytes);
System.out.println(len);//2
//System.out.println(Arrays.toString(bytes));//[65, 66]
System.out.println(new String(bytes));//AB
int len1 = fis.read(bytes);
System.out.println(len1);//2
System.out.println(new String(bytes));//CD
int len2 = fis.read(bytes);
System.out.println(len2);//2
System.out.println(new String(bytes));//E
int len3 = fis.read(bytes);
System.out.println(len3);//1
System.out.println(new String(bytes));
int len4 = fis.read(bytes);
System.out.println(len4);//-1
System.out.println(new String(bytes));*/
/*
使用循环优化,不知道文件中有多少字节,使用while循环
while循环结束的条件,读取到-1结束
*/
byte[] bytes = new byte[1024];//存储读取到的多个字节
int len = 0;//记录每次读取的有效字节个数
while ((len = fis.read(bytes)) != -1 ){
System.out.println(new String(bytes,0, len));//ABCDE
}
fis.close();
}
}
4.6 练习
文件复制练习:一读一写
文件复制步骤:
1、创建一个字节输入流对象,构造方法中绑定要读取的数据源
2、创建一个字节输出流对象,构造方法中绑定要写入的目的地
3、使用字节输入流对象中的方法read读取文件
4、使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
5、释放资源(先关写的,后关读的;如果写完了,肯定读取完毕了)
public class CopyFile {
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
FileInputStream fis = new FileInputStream("D:\\Test\\src\\Day17\\Demo04\\IL.jpg");
FileOutputStream fos = new FileOutputStream("D:\\Test\\src\\Day17\\Demo03\\IL.jpg");
//一次读取一个字节写入一个字节的方法
/*int len = 0;
while ((len = fis.read()) != -1){
fos.write(len);
}*/
//使用数组缓冲读取多个字节,写入多个字节
byte[] bytes = new byte[10240];
int len = 0;//每次读取的有效字节个数
while ((len = fis.read(bytes)) != -1){
fos.write(bytes,0,len);
}
fos.close();
fis.close();
long end = System.currentTimeMillis();
System.out.println("复制粘贴共耗时:" + (end - start) + "毫秒");
}
}
第五节 IO字符流
5.1 字符输入流(Reader)
java.io.Reader:字符输入流,是字符输入流的最顶层父类,定义了一些共性的成员方法,是一个抽象类
共性的成员方法:
int read():读取单个字符并返回
int read(char[] cbuf):一次读取多个字符,将字符读入数组
void close():关闭该流并释放与之关联的所有资源
5.2 FileReader类
java.io.FileReader extends InputStreamReader extends Reader
FileReader:文件字符输入流
作用:把硬盘文件中的数据以字符的方式读取到内存中
构造方法:
FileReader(String fileName)
FileReader(File file)
参数:读取文件的数据源
String fileName:文件的路径
File file:一个文件
FileReader构造方法的作用:
1、创建一个FileReader对象
2、会把FileReader对象指向要读取的文件
字符输入流的使用步骤:
1、创建FileReader对象,构造方法中绑定要读取的数据源
2、使用FileReader对象中的方法read读取文件
3、释放资源
public class Demo01Reader {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("D:\\Test\\src\\Day17\\Demo04\\b.txt");
//int read():读取单个字符并返回
/*int len = 0;
while ((len = fr.read()) != -1) {
System.out.print((char)len);
}*/
//int read(char[] cbuf):一次读取多个字符,将字符读入数组
char[] chars = new char[1024];
int len = 0;
while ((len = fr.read(chars)) != -1){
System.out.print(new String(chars,0,len));
}
fr.close();
}
}
5.3 字符输出流(Writer)
java.io.Writer:字符输出流,是所有字符输出流的最顶层父类,是一个抽象类
共性的成员方法:
void write(int c)
void write(char[] cbuf)
abstract void write(char[] cbuf, int off, int len)
void write(String str)
void write(String str, int off, int len)
void flush()
void close()
5.4 FileWriter类
java.io.FileWriter extends OutputStreamWriter extends Writer
FileWriter:文件字符输出流
作用:把内存中字符数据写入到文件中
构造方法:
FileWriter(File file)根据给定的File对象构造一个FileWriter对象
FileWriter(String fileName)根据给定的文件名构造一个FileName对象
参数:写入数据的目的地
String fileName:文件的路径
File file:是一个文件
构造方法的作用:
1、会创建一个FileWriter对象
2、会根据构造方法中传递的文件/文件的路径,创建文件
3、会把FileWriter对象指向创建好的文件
字符输出流的使用步骤:
1、创建一个FileWriter对象,构造方法中绑定要写入数据的目的地
2、使用FileWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)
3、使用FileWriter中的方法flush,把内存缓冲区中的数据刷新到文件中
4、释放资源(会先把内存缓冲区中的数据刷新到文件中)
public class Demo02Writer {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("D:\\Test\\src\\Day17\\Demo05\\a.txt");
fw.write("小松狮");
//fw.flush();
fw.close();
}
}
flush方法和close方法的区别:
flush:刷新缓冲区,流对象可以继续使用
close:先刷新缓冲区,然后通知系统释放资源,流对象不可以再使用了
public class Demo03FlushAndClose {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("D:\\Test\\src\\Day17\\Demo05\\b.txt");
fw.write("小松狮");
fw.flush();
fw.write("小锦鲤");
fw.close();
//fw.write("123");//IOException错误!
}
}
//字符数据流写数据的其他方法
public class Demo04Writer {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("D:\\Test\\src\\Day17\\Demo05\\c.txt");
char[] chars = {'A','b','e'};
fw.write(chars);
fw.write(chars,1,2);
fw.write("小松狮");
fw.write("小松狮小锦鲤",3,3);
fw.close();
}
}
续写和换行
续写,追加写:使用两个参数的构造方法
FileWriter(String fileName, boolean append)
FileWriter(File file, boolean append)
参数:
String fileName, File file:写入数据的目的地
boolean append:续写开关
true:不会创建新的文件覆盖源文件,可以续写
false:创建新的文件覆盖源文件
换行:换行符号
windows:\r\n
linux:/n
max:/r
public class Demo05Writer {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("D:\\Test\\src\\Day17\\Demo05\\d.txt", true);
for (int i = 0; i < 5; i++) {
fw.write("小松狮" + i + "\r\n");
}
fw.close();
}
}
5.5 IO异常的处理
在JDK1.7之前使用try catch finally处理流中的异常
格式:
try{
可能会产生异常的代码
}catch(异常类变量 变量名){
异常的处理逻辑
}finally{
一定会实现的代码
资源释放
}
public class Demo05TryCatch {
public static void main(String[] args) {
//提高变量fw的作用域,让Finally可以使用
//变量在定义的时候,可以没有值,但是使用的时候必须有值
//fw = new FileWriter("D:\\\\Test\\\\src\\\\Day17\\\\Demo05\\\\e.txt", true);执行失败,fw没有值,fw.close会报错
FileWriter fw = null;
try{
//可能会产生异常的代码
fw = new FileWriter("G:\\\\Test\\\\src\\\\Day17\\\\Demo05\\\\e.txt", true);
for (int i = 0; i < 5; i++) {
fw.write("小松狮" + i + "\r\n");
}
}catch (IOException e){
//异常的处理逻辑
System.out.println(e);
}finally {
//一定会执行的代码
//创建对象失败了,fw的默认值就是null,null是不能调用方法的
//会抛出NullPointException,需要增加一个判断,不是null再释放资源
if (fw != null){
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
JDK7的新特性
在try的后边可以增加一个(),在括号中可以定义流对象
那么这个流对象的作用域就在try中有效
try中的代码执行完毕,会自动把流对象释放,不用写finally
格式:
try(定义流对象;定义流对象…){
可能会产生异常的代码
}catch(异常类变量 变量名){
异常的处理逻辑
}
public class Demo06JDK7 {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("D:\\Test\\src\\Day17\\Demo04\\IL.jpg");
FileOutputStream fos = new FileOutputStream("D:\\Test\\src\\Day17\\Demo05\\IL.jpg");) {
byte[] bytes = new byte[10240];
int len = 0;//每次读取的有效字节个数
while ((len = fis.read(bytes)) != -1){
fos.write(bytes,0,len);
}
}catch (IOException e){
System.out.println(e);
}
}
}
JDK9新特性
try的前边可以定义流对象
在try后边的()中可以直接引入流对象的名称(变量名)
在try代码执行完毕之后,流对象也可以释放掉,不用写finally
格式:
A a = new A();
B b = new B();
try(a;b){
可能会产生异常的代码
}catch(异常类变量 变量名){
异常的处理逻辑
}
public class Demo07JDK9 {
public static void main(String[] args) throws FileNotFoundException {
FileInputStream fis = new FileInputStream("D:\\Test\\src\\Day17\\Demo04\\IL.jpg");
FileOutputStream fos = new FileOutputStream("D:\\Test\\src\\Day17\\Demo05\\IL1.jpg");
try (fis;fos){
byte[] bytes = new byte[10240];
int len = 0;//每次读取的有效字节个数
while ((len = fis.read(bytes)) != -1){
fos.write(bytes,0,len);
}
}catch (IOException e){
System.out.println(e);
}
//fos.write(1);//Stream Closed,IOException
}
}
第六节 Properties集合
java.util.Properties集合 extends Hashtable<k,v> implements Map<k,v>
Properties类表示了一个持久的属性集,Properties可保存在流中或从流中加载
Properties集合是一个唯一和IO流相结合的集合
可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用
属性列表中每个键及其对应值都是一个字符串
Properties集合是一个双列集合,key和value默认都是字符串
使用Properties集合存储数据,遍历取出Properties集合中的数据
Properties集合有一些操作字符串的特有方法
Object setProperty(String key, String value)调用Hashtable的方法put
String getProperty(String key)通过key找到value值,此方法相当于Map集合中的get(key)方法
Set stringPropertyNames()返回此属性列表中的键集,其中该键及其对应值是字符串,此方法相当于Map集合中的keySet方法
public class Demo01Properties {
public static void main(String[] args) {
demo01();
}
private static void demo01() {
Properties prop = new Properties();
prop.setProperty("小松狮","16");
prop.setProperty("小松狮1","17");
prop.setProperty("小松狮2","18");
Set<String> set = prop.stringPropertyNames();
for (String key : set) {
String value = prop.getProperty(key);
System.out.println(key + value);
}
}
}
6.1 store方法
store,把集合中的临时数据,持久化写入到硬盘中存储
void store(OutputStream out, String comments)
void store(Writer writer, String comments)
参数:
OutputStream out:字节输出流,不能写入中文
Writer writer:字符输出流,可以写中文
String comments:注释,用来解释说明保存的文件是做什么用的
不能使用中文,会产生乱码,默认是Unicode编码,一般使用“”空字符串
使用步骤:
1、创建Properties集合,添加数据
2、创建字节输出流/字符输出流对象,构造方法中绑定要输出的目的地
3、使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
4、释放资源
public class Demo02Store {
public static void main(String[] args) throws IOException {
demo01();
}
private static void demo01() throws IOException {
Properties prop = new Properties();
prop.setProperty("小松狮","16");
prop.setProperty("小松狮1","17");
prop.setProperty("小松狮2","18");
FileWriter fw = new FileWriter("D:\\Test\\src\\Day17\\Demo06\\a.txt");
prop.store(fw,"");
fw.close();
}
}
6.2 load方法
load,把硬盘中保存的文件(键值对),读取到集合中使用
void load(InputStream inStream)
void load(Reader reader)
参数:
InputStream inStream:字节输入流,不能读取含有中文的键值对
Reader reader:字符输入流,能读取含有中文的键值对
使用步骤:
1、创建Properties集合对象
2、使用Properties集合对象中的方法load读取保存键值对的文件
3、遍历Properties集合
注意:
1、存储键值对的文件中,键与值默认的连接符号可以使用=,空格(其他符号)
2、存储键值对的文件中,可以使用#进行注释,被注释的键值对不会再被读取
3、存储键值对的文件中,键与值默认都是字符串,不用再加引号
public class Demo03load {
public static void main(String[] args) throws IOException {
demo01();
}
private static void demo01() throws IOException {
Properties prop = new Properties();
prop.load(new FileReader("D:\\Test\\src\\Day17\\Demo06\\a.txt"));
Set<String> set = prop.stringPropertyNames();
for (String key : set) {
String value = prop.getProperty(key);
System.out.println(key + "=" + value);
}
}
}
第七节 缓冲流
7.1 概念
缓冲流,也叫高效流,是对四个基本的FileXxx流的增强,根据数据类型分为:
字节缓冲流:BufferedInputStream,BufferedOutputStream
字符缓冲流:BufferedReader,BufferedWriter
7.2 BufferedOutputStream
java.io.BufferedOutputStream extends OutputStream
BufferedOutputStream:字节缓冲输出流
继承自父类的共性成员方法
构造方法:
BufferedOutputStream(OutputStream out)
创建一个新的缓冲输出流,以将数据写入指定的底层输出流
BufferedOutputStream(OutputStream out, int size)
创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流
参数:
OutputStream out:字节输出流
我们可以传递FileOutputStream,缓冲流会给FileOutputStream增加一个缓冲区,提高FileOutputStream的写入效率
int size:指定缓冲流内部缓冲区的大小,不指定默认
使用步骤:
1、创建FileOutputStream对象,构造方法中绑定要输出的目的地
2、创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象,提高FileOutputStream对象效率
3、使用BufferedOutputStream对象中的方法write,把数据写入到内部缓冲区中
4、使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据,刷新到文件中
5、释放资源(会先调用flush方法刷新数据,第四步可以省略)
public class Demo01BufferedInput {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("D:\\Test\\src\\Day17\\Demo07\\a.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write("小松狮小锦鲤".getBytes(StandardCharsets.UTF_8));
bos.flush();
bos.close();
}
}
7.3 BufferedInputStream
java.io.BufferedInputStream extends InputStream
BufferedInputStream:字节缓冲输入流
继承自父类的成员方法
构造方法:
BufferedInputStream(InputStream in)
创建一个BufferedInputStream并保存其参数,即输入流in,以便将来使用
BufferedInputStream(InputStream in, int size)
创建具有指定缓冲区大小的BufferedInputStream并保存其参数,即输入流in,以便将来使用
参数:
InputStream in:字节输入流
我们可以传递FileInputStream,缓冲流会给FileInputStream增加一个缓冲区,提高FileInputStream的读取效率
int size:指定缓冲流内部缓冲区的大小,不指定默认
使用步骤:
1、创建FileInputStream对象,构造方法中绑定要读取的数据源
2、创建BufferedInputStream对象,构造方法中传递FileInputStream对象,提高FileInputStream对象的读取效率
3、使用BufferedInputStream对象中的方法read,读取文件
4、释放资源
public class Demo02BufferedInputStream {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("D:\\Test\\src\\Day17\\Demo07\\a.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
/* int len = 0;//记录每次读取到的字节
while ((len = bis.read()) != -1){
System.out.println(len);
}*/
int len = 0;
byte[] bytes = new byte[1024];
while ((len = bis.read(bytes)) != -1){
System.out.println(new String(bytes, 0, len));
}
bis.close();
}
}
7.4 缓冲流测试复制文件效率
import java.io.*;
/*
文件复制练习:一读一写
文件复制的步骤:
1、创建字节缓冲输入流对象,构造方法中传递字节输入流
2、创建字节缓冲输出流对象,构造方法中传递字节输出流
3、使用字节缓冲输入流对象中的方法read,读取文件
4、使用字节缓冲输出流中的方法write,把读取的数据写入到内部缓冲区中
4、释放资源(会先把缓冲区中的数据,刷新到文件中)
*/
public class Copy {
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\Test\\src\\Day17\\Demo04\\IL.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\Test\\src\\Day17\\Demo07\\IL.jpg"));
/*int len = 0;
while ((len = bis.read()) != -1){
bos.write(len);
}//80毫秒*/
int len = 0;
byte[] bytes = new byte[1024];
while ((len = bis.read(bytes)) != -1){
bos.write(bytes, 0, len);
}//10毫秒
bos.close();
bis.close();
long end = System.currentTimeMillis();
System.out.println("复制粘贴文件共用时:" + (end - start) + "毫秒");
}
}
7.5 BufferedWriter
java.io.BufferedWriter extends Writer
BufferedWriter:字符缓冲输出流
继承自父类的共性成员方法
构造方法:
BufferedWriter(Writer out):创建一个使用默认大小输出缓冲区的缓冲字符输出流
BufferedWriter(Writer out, int sz):创建一个使用给定大小输出缓冲区的新缓冲字符输出流
参数:
Writer out:字符输出流
我们可以传递FileWriter,缓冲流会给FileWriter增加一个缓冲区,提高FileWriter的写入效率
int sz:指定缓冲区的大小,不写默认大小
特有的成员方法:
void newLine()写入一个行分隔符,会根据不同的操作系统,获取不同的行分隔符
换行:换行符号
windows:\r\n
linux:/n
mac:/r
使用步骤:
1、创建字符缓冲输出流对象,构造方法中传递字符输出流
2、调用字符缓冲输出流中的方法write,把数据写入到内存缓冲区中
3、调用字符缓冲输出流中的方法flush,把内存缓冲区中的数据,刷新到文件中
4、释放资源
public class Demo03BufferedWriter {
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\Test\\src\\Day17\\Demo07\\b.txt"));
for (int i = 0; i < 5; i++) {
bw.write("小松狮");
bw.newLine();
}
bw.close();
}
}
7.6 BufferedReader
java.io.BufferedReader extends Reader
继承自父类的共性成员方法
构造方法:
BufferedReader(Reader in):创建一个使用默认大小输入缓冲区的缓冲字符输入流
BufferedReader(Reader in, int sz):创建一个使用指定大小输入缓冲区的缓冲字符输入流
参数:
Reader in:字符输入流
我们可以传递FileReader,缓冲流会给FileReader增加一个缓冲区,提高FileReader的读取效率
int sz:指定缓冲区的大小,不写默认大小
特有方法:
String readLine()读取一个文本行,读取一行数据
行的终止符号:通过下列字符之一即可认为某行已终止:换行(‘\n’)、回车(‘\r’)、或(\r\n)
返回值:包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回null
使用步骤:
1、创建字符缓冲输入流对象,构造方法中传递字符输入流
2、使用字符缓冲输入流对象中的方法read/readLine读取文本
3、释放资源
public class Demo04BufferedReader {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("D:\\Test\\src\\Day17\\Demo07\\b.txt"));
String line;
while ((line = br.readLine()) != null){
System.out.println(line);
}
br.close();
}
}
7.7 练习
练习:对文本的内容进行排序
按照(1,2,3…)顺序排序
/*
练习:对文本的内容进行排序
按照(1,2,3...)顺序排序
分析:
1、创建一个HashMap集合对象,可以存储每行文本的序号(1,2,3,...)value:存储每行的文本
2、创建字符缓冲输入流对象,构造方法中绑定字符输入流
3、创建字符缓冲输出流对象,构造方法中绑定字符输出流
4、使用字符缓冲输入流中的方法readline,逐行读取文本
5、对读取到的文本进行切割,获取行中的序号和文本内容
6、把切割好的序号和文本的内容存储到HashMap集合中(key序号是有序的,会自动排序)
7、遍历HashMap集合,获取每一个键值对
8、把每一个键值对,拼接为一个文本行
9、把拼接好的文本,使用字符缓冲输出流中的方法write,写入到文件中
10、释放资源
*/
public class Test {
public static void main(String[] args) throws IOException {
HashMap<String, String> map = new HashMap<>();
BufferedReader br = new BufferedReader(new FileReader("D:\\Test\\src\\Day17\\Demo07\\b.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\Test\\src\\Day17\\Demo07\\c.txt"));
String line;
while ((line = br.readLine()) != null){
String[] array = line.split("\\、");
map.put(array[0], array[1]);
}
for (String key : map.keySet()){
String value = map.get(key);
line = key + "." + value;
bw.write(line);
bw.newLine();
}
bw.close();
br.close();
}
}
第八节 转换流
8.1 编码引出的问题
/*
FileReader可以读取默认编码格式(UTF-8)的文件
FileReader读取系统默认编码(中文GBK)会产生乱码:С��ʨ
*/
public class Demo01Reader {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("D:\\Test\\src\\Day17\\Demo08\\1.txt");
int len = 0;
while ((len = fr.read()) != -1){
System.out.print((char) len);
}
fr.close();
}
}
8.2 OutputStreamWriter
java.io.OutputStreamWriter extends Writer
OutputStreamWriter是字符流通向字节流的桥梁:可使用指定的charset将要写入流中的字符编码成字节
继承自父类的共性成员方法
构造方法:
OutputStreamWriter(OutputStream out)创建使用默认字符编码的OutputStreamWriter
OutputStreamWriter(OutputStream out, String charsetName)创建使用指定字符集的OutputStreamWriter
参数:
OutputStream out:字节输出流,可以用来写转换之后的字节到文件中
String charsetName:指定的编码表名称,不区分大小写,可以是utf-8,gbk…不指定默认使用UTF-8
使用步骤:
1、创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称
2、使用OutputStreamWriter对象中的方法write,把字符转换为字节存储到缓冲区中(编码)
3、使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的字节刷新到文件中(使用字节流写字节的过程)
4、释放资源
public class Demo02OutputStream {
public static void main(String[] args) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\Test\\src\\Day17\\Demo08\\gbk.txt"),"gbk");
osw.write("小松狮");
osw.flush();
osw.close();
}
}
8.3 InputStreamReader
java.io.InputStreamReader extends Reader
InputStreamReader:是字节流通向字符流的桥梁:它使用指定的charset读取字节并将其解码为字符
继承自父类的共性成员方法
构造方法:
InputStreamReader(InputStream in):创建一个使用默认字符集的InputStreamReader
InputStreamReader(InputStream in, String charsetName):创建使用指定字符集的InputStreamReader
参数:
InputStream in:字节输入流,用来读取文件中保存的字节
String charsetName:指定的编码表名称,不区分大小写,可以是utf-8,gbk…不指定默认使用UTF-8
使用步骤:
1、创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称
2、使用InputStreamReader对象中的方法read读取文件
3、释放资源
注意事项:
构造方法中指定的编码表名称要和文件的编码相同,否则会发生乱码
public class Demo02InputStream {
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\Test\\src\\Day17\\Demo08\\gbk.txt"),"gbk");
int len = 0;
char[] chars = new char[1024];
while ((len = isr.read(chars)) != -1){
System.out.println(new String(chars, 0, len));
}
isr.close();
}
}
8.4 练习
练习:将GBK编码的文本文件,转换为UTF-8编码的文本文件
/*
练习:将GBK编码的文本文件,转换为UTF-8编码的文本文件
分析:
1、创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称gbk
2、创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称UTF-8
3、使用InputStreamReader对象中的方法read读取文件
4、使用OutputStreamWriter对象中的方法write,把读取的数据写入到文件中
5、释放资源
*/
public class Test {
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\Test\\src\\Day17\\Demo08\\gbk.txt"),"GBK");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\Test\\src\\Day17\\Demo08\\utf_8.txt"),"utf-8");
int len = 0;
while ((len = isr.read()) != -1){
osw.write(len);
}
osw.close();
isr.close();
}
}
第九节 序列化流
把对象以流的方式,写入到文件中保存,叫写对象,也叫对象的序列化
对象中包含的不仅仅是字符,使用字节流
ObjectOutputStream:对象的序列化流
把文件中保存的对象,以流的方式读取出来,叫做读对象,也叫对象的反序列化
读取的文件保存的都是字节,使用字节流
ObjectInputStream:对象的反序列化流
9.1 ObjectOutputStream
java.io.ObjectOutputStream extends OutputStream
ObjectOutputStream:对象的序列化流
作用:把对象以流的方式写入到文件中保存
构造方法
ObjectOutputStream(OutputStream out)创建写入指定OutputStream的ObjectOutputStream
参数:
OutputStream out:字节输出流
特有的成员方法:
void writeObject(Object obj)将指定的对象写入ObjectOutputStream
使用步骤:
1、创建ObjectOutputStream对象,构造方法中传递字节输出流
2、使用ObjectOutputStream对象中的writeObject,把对象写入到文件中
3、释放资源
import java.io.Serializable;
/*
序列化和反序列化的时候,会抛出NotSerializableException没有序列化异常
类通过实现java.io.Serializable接口以启用其序列化功能
未实现此接口的类将无法使其任何状态序列化或反序列化
Serializable接口也叫标记型接口
要进行序列化和反序列化的类必须实现Serializable接口,就会给类添加一个标记
当我们进行序列化和反序列化的时候,就会检测类上是否有这个标记
有:就可以序列化和反序列化
没有:就会抛出NotSerializableException异常
*/
public class Person implements Serializable {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class Demo01ObjectOutputStream {
public static void main(String[] args) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\Test\\src\\Day17\\Demo09\\person.txt"));
oos.writeObject(new Person("小松狮",18));
oos.close();
}
}
9.2 ObjectInputStream
java.io.ObjectInputStream extends InputStream
ObjectInputStream:对象的反序列化流
作用:把文件中保存的对象,以流的方式读取出来使用
构造方法:
ObjectInputStream(InputStream in)创建从指定InputStream读取的ObjectInputStream
参数:
InputStream:字节输入流
特有的成员方法:
Object readObject()从ObjectInputStream读取对象
使用步骤:
1、创建ObjectInputStream对象,构造方法中传递字节输入流
2、使用ObjectInputStream对象中的方法readObject读取保存对象的文件
3、释放资源
4、使用读取出来的对象(打印)
readObject方法声明抛出了ClassNotFoundException
当不存在对象的class文件时抛出此异常
反序列化的前提:
1、类必须实现Serializable
2、必须存在类对应的class文件
public class Demo01ObjectInputStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\Test\\src\\Day17\\Demo09\\person.txt"));
Object obj = ois.readObject();
ois.close();
System.out.println(obj);
}
}
static关键字:静态关键字
静态优先于非静态加载到内存中(静态优先于对象进入到内存中)
被static修饰的成员变量不能被序列化的,序列化的都是对象
transient关键字:瞬态关键字
被transient修饰的成员变量,不能被序列化
9.3 练习
import java.io.*;
import java.util.ArrayList;
/*
练习:序列化集合
当我们想在文件中保存多个对象的时候,可以把对个对象存储到一个集合中
对集合进行序列化和反序列化
分析:
1、定义一个存储Person对象的ArrayList集合
2、往ArrayList集合中存储Person对象
3、创建一个序列化流对象
4、使用序列化流对象中的方法writeObject对集合进行序列化
5、创建一个反序列化流对象
6、使用反序列化流对象中的方法readObject读取文件中保存的集合
7、把Object类型的集合转换为ArrayList类型
8、遍历ArrayList集合
9、释放资源
*/
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("小松狮",18));
list.add(new Person("小锦鲤",19));
list.add(new Person("小松狮",18));
list.add(new Person("小锦鲤",19));
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\Test\\src\\Day17\\Demo09\\person.txt"));
oos.writeObject(list);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\Test\\src\\Day17\\Demo09\\person.txt"));
Object o = ois.readObject();
ArrayList<Object> array = (ArrayList<Object>)o;
for (Object list1 : array) {
System.out.println(list1);
}
ois.close();
oos.close();
}
}
第十节 打印流
import java.io.FileNotFoundException;
import java.io.PrintStream;
/*
java.io.PrintStream:打印流
PrintStream为其他输出流添加了功能,使他们能够方便地打印各种数据值表示形式
PrintStream特点:
1、只负责数据的输出,不负责数据的读取
2、与其他输出流不同,PrintStream永远不会抛出IOException
3、有特有方法,print,println
void print(任意类型的值)
void println(任意类型的值并换行)
构造方法:
PrintStream(File file):输出的目的地是一个文件
PrintStream(OutputStream out):输出的目的地是一个字节输出流
PrintStream(String fileName):输出的目的地是一个文件路径
PrintStream extends OutputStream
继承自父类的成员方法
注意:
如果使用继承自父类的write方法写数据,那么查看数据的时候会查询编码表 97->a
如果使用自己特有的方法print/println方法写数据,写的数据原样输出 97->97
*/
public class Demo01PrintStream {
public static void main(String[] args) throws FileNotFoundException {
PrintStream ps = new PrintStream("D:\\Test\\src\\Day17\\Demo10\\print.txt");
//ps.write(1);
ps.print(1);
ps.close();
}
}
/*
可以改变输出语句的目的地(打印流的流向)
输出语句,默认在控制台输出
使用System.setOut方法改变输出语句的目的地,改为参数中传递的打印流的目的地
static void setOut(printStream out)
重写分配"标准"输出流
*/
public class Demo02PrintStream {
public static void main(String[] args) throws FileNotFoundException {
System.out.println("我是在控制台输出");
PrintStream ps = new PrintStream(new FileOutputStream("D:\\Test\\src\\Day17\\Demo10\\打印流目的地.txt"));
System.setOut(ps);
System.out.println("打印流的目的地中输出");
ps.close();
}
}