文件的基本使用
文件
-
什么是文件:文件是保存数据的地方,比如我们经常使用的word文档,txt文件,excel文件......都是文件。它既可以保存一张图片,也可以保存视频,声音,文字等。
-
文件流:文件在程序中是以流的形式来操作的。
-
-
注:数据在数据源(文件)和程序(内存)之间经历的路径是文件流。
输入流:数据从数据源(文件)到程序(内存)的路径
输出流:数据从程序(内存)到数据源(文件)的路径
常用的文件操作
-
创建文件对象相关的构造器和方法:
new File(String pathname);根据路径构建一个File对象。
new File(File parent,String child);根据父目录文件+子路径构建一个File对象。
new File(String parent,String child);根据父目录+子路径构建一个File对象。
createNewFile() ;创建新文件。
public class FileCreateTest {
public static void main(String[] args) {
new FileCreateTest().createFile01();
new FileCreateTest().createFile02();
new FileCreateTest().createFile03();
}
//第一种方法
public void createFile01(){
String filePath01 = "E:\\Study\\java\\newFile01.txt";//定义文件完整路径字符串
File file01 = new File(filePath01);//创建对象,参数是完整路径字符串这里只是在内存创建了对象,并没有真正的在磁盘生成文件
try {
file01.createNewFile();//创建文件,只有调用对象的createNewFile()方法才算真正在磁盘生成了文件
System.out.println("文件01创建成功");//结果:文件01创建成功
} catch (IOException e) {
e.printStackTrace();
}
}
//第二种方法
public void createFile02(){
File parentFile = new File("E:\\Study\\java\\");//创建父目录路径对象
String fileName = "newFile02.txt";//文件名
File file02 = new File(parentFile, fileName);//创建对象,第一个参数是父目录路径对象,第二个参数是子路径字符串
try {
file02.createNewFile();//创建文件,只有调用对象的createNewFile()方法才算真正在磁盘生成了文件
System.out.println("文件02创建成功");//结果:文件02创建成功
} catch (IOException e) {
e.printStackTrace();
}
}
//第三种方法
public void createFile03(){
String parentFilePath = "E:\\Study\\java\\";//定义父目录路径字符串
String childFilePath = "newFile03.txt";//定子父目录路径字符串
File file03 = new File(parentFilePath, childFilePath);//创建对象,第一个参数是父目录路径字符串,第二个参数是子路径字符串,这里只是在内存创建了对象,并没有真正的在磁盘生成文件
try {
file03.createNewFile();//创建文件,只有调用对象的createNewFile()方法才算真正在磁盘生成了文件
System.out.println("文件03创建成功");//结果:文件03创建成功
} catch (IOException e) {
e.printStackTrace();
}
}
}
-
常用获取文件的相关信息的方法:
-
getName();获取文件的文件名。
-
getAbsolutePath();获取文件的绝对路径。
-
getParent();获取文件的父级目录。
-
length();获取文件的大小,只针对文件有效。
-
exists();判断文件是否存在
-
isFile();判断是否是一个文件。
-
isDirectory();判断是否是一个目录。
public class FileInformationTest { public static void main(String[] args) { new FileInformationTest().info(); } public void info(){ String path ="E:\\Study\\java\\newtxt01.txt";//文件路径 File file = new File(path);//创建文件对象 try { file.createNewFile();//创建文件 System.out.println("文件创建成功");//结果:文件创建成功 } catch (IOException e) { e.printStackTrace(); } //常用获取文件相关信息的方法 //getName()获取文件名称 String fileName = file.getName(); System.out.println(fileName);//结果:newtxt01.txt //getAbsolutePath()获取文件绝对路径 String absolutePath = file.getAbsolutePath(); System.out.println(absolutePath);//结果:E:\Study\java\newtxt01.txt //getParent()获取文件的父级目录 String parent = file.getParent(); System.out.println(parent);//结果:E:\Study\java //length()获取文件的大小,单位是字节 long length = file.length(); System.out.println(length);//结果:50 //文件是否存在 System.out.println(file.exists());//结果:true //判断对象是不是一个文件 System.out.println(file.isFile());//结果:true ///判断对象是不是一个目录 System.out.println(file.isDirectory());//结果:false } }
-
-
目录的操作和文件的删除:
- mkdir();创建一级目录。
- mkdirs();创建多级目录。
- delete();删除空目录(目录下有文件删不了)或文件。
public class DireectoryTest { public static void main(String[] args) { new DireectoryTest().m1(); new DireectoryTest().m2(); new DireectoryTest().m3(); } //1.判断E:\Study\java\newtxt01.txt是否存在,存在就删除。 public void m1(){ String filePath = "E:\\Study\\java\\newtxt01.txt";//设置文件路径 File file = new File(filePath);//创建文件对象,并传入路径 if(file.exists()){//exists()判断文件是否存在 if (file.delete()){//删除文件 delete()会返回一个boolean类型的值 System.out.println(file.getName()+"删除成功");//结果:newtxt01.txt删除成功 }else { System.out.println(file.getName()+"删除失败"); } }else { System.out.println(file.getName()+"文件不存在"); } } //2.判断E:\Study\java\newDir是否存在,存在就删除 public void m2(){ String dirPath = "E:\\Study\\java\\newDir";//设置目录路径 File newDir = new File(dirPath);//创建目录对象,并传入路径 if (newDir.exists()){//exists()判断目录是否存在 if (newDir.delete()){//删除目录 如果目录下有文件,则不能删除 System.out.println(newDir.getName() + "删除成功");//结果:newDir删除成功 }else { System.out.println(newDir.getName() +"目录下有文件,无法删除"); } }else { System.out.println(newDir.getName()+"目录不存在"); } } //3.判断E:\\Study\\java\\a\\b\\c是否存在,如果存在就提示,不存在就创建 public void m3(){ String moreDirPath = "E:\\Study\\java\\a\\b\\c";//设置多级目录路径 File moreDir = new File(moreDirPath);//创建目录对象,并传入路径 if (moreDir.exists()){//exists()判断目录是否存在 System.out.println(moreDir.getAbsolutePath()+"存在"); }else { if (moreDir.mkdirs()){//mkdirs()创建多级目录 System.out.println(moreDir.getAbsolutePath()+"创建成功");//结果:E:\Study\java\a\b\c创建成功 }else { System.out.println(moreDir.getAbsolutePath()+"创建失败"); } } } }
IO流原理及流的分类
-
JavaIO原理:
- I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理数据传输。如读/写文件,网络通讯等。
- Java程序中,对于数据的输入/输出操作以“流(stream)”的方式进行。
- java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过方法输入或输出数据。
- 输入input:读取外部数据(磁盘,光盘等存储设备的数据)到程序(内存)中。
- 输出ouput:将程序(内存)数据输出到磁盘,光盘等存储设备中。
- 流和文件的关系:流是文件的通道。
-
流的分类:
-
按操作数据单位不同分为:字节流(8bit),字符流(按字符)。
-
按数据流的流向不同分为:输入流,输出流。
-
按流的角色的不同分为:字节流,处理流/包装流。
-
字节流和字符流相比字符流的效率要高一些,一个字符对应多少个字节具体要看文件编码是什么,字节流一般用来处理二进制的文件,因为可以做到无损操作。而字符流一般用来处理文本文件等。
-
-
Java的IO流共涉及40多个类,实际上非常规则,都是从如上4个抽象基类派生的。
-
由这四个类派生出的子类名称都是以父类名作为子类的后缀。
-
-
IO流体系图:
-
FileInputStream,FileOutputStream
-
FileInputStream,ObjectInputStream,BufferedInputStream的继承关系:
-
FileInputStream类:
-
演示读取文件:将E:\Study\java\hello.txt文件的内容读取到控制台。hello.txt内容为:HelloWorld!原神!。
-
read();方法一个字节一个字节读取(读取到最后返回-1):
public class FileInputStreamTest { public static void main(String[] args) { new FileInputStreamTest().m1(); } /* * 演示读取文件总结 * 1.read();单个字节输入,效率比较低。 * 2.read()返回的是int类型,所以要显示文本的内容,要强转转成char类型输出。 * 3.输出的中文乱码,因为FileInputStream是字节输入流,一个字节一个字节读取,而UTF-8中一个中文占三个字节,所以会乱码。 * 4.当有多层的try/catch嵌套,应注意捕获异常的范围大小。 * 5.程序运行完成之后一定要在finally中关闭流,释放资源。 * */ public void m1(){ String filePath="E:\\Study\\java\\hello.txt";//设置文件路径 int result = 0;//创建一个int类型变量用于接受fileInputStream.read(); FileInputStream fileInputStream =null; try { fileInputStream = new FileInputStream(filePath);//创建FileInputStream字符输入流对象 try { while ((result = fileInputStream.read())!=-1){//这里read()返回的是int类型,read()读到最后一个字节返回的是-1,所以只要不为-1就让他一直循环读 System.out.print((char)result);//结果:HelloWorld!åç¥! } } catch (IOException e) { e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); }finally { try { fileInputStream.close();//关闭流 } catch (IOException e) { e.printStackTrace(); } } } }
-
read(byte[] b);方法用字节类型数组读取(读取到最后返回-1)。
public class FileInputStreamTest { public static void main(String[] args) { new FileInputStreamTest().m2(); } /* * 演示读取文件总结 * 1.read(byte[] b);用字节类型数组读取,效率相对单个字节读取更高。 * 2.read(buf)返回的是int类型,返回的是实际读取的字节数,例如:读取了三个字节就是返回3,读取八个字节就返回8。 * 3.length接受read(buf)返回值,用于确定大小,在后面输出时需要new一个String(byte bytes[], int offset, int length)对象,用于以字符串的形式输出字符数组。int offset是开始的位置。int length是读取的长度。 * 4.当有多层的try/catch嵌套,应注意捕获异常的范围大小。 * 5.程序运行完成之后一定要在finally中关闭流,释放资源。 * */ public void m2(){ String filePath="E:\\Study\\java\\hello.txt";//设置文件路径 byte[] buf =new byte[8];//一次读取8个字节 int length = 0;//创建int类型变量用于接受fileInputStream.read(buf)实际读取的字节数 FileInputStream fileInputStream =null; try { fileInputStream = new FileInputStream(filePath);//创建FileInputStream字符输入流对象 try { while ((length=fileInputStream.read(buf))!=-1){//这里read(buf)返回的是int类型,read(buf)读到最后一个字节返回的是-1,所以只要不为-1就让他一直循环读 System.out.print(new String(buf,0,length));//结果:HelloWorld } } catch (IOException e) { e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); }finally { try { fileInputStream.close();//关闭流 } catch (IOException e) { e.printStackTrace(); } } } }
-
-
-
FileOutputStream类:
-
FileOutputStream类继承关系:
-
-
演示写入文件:使用FileOutputStream在E:\Study\java\hello.txt中写入“hello,world”,如果文件不存在,会创建文件(注意:前提是目录已经存在)。
public class FileOutputStreamTest { public static void main(String[] args) { new FileOutputStreamTest().m1(); } /* * 演示用FileOutputStream将内容写入文件中 * 如果该文件不存在,则创建该文件 *String有一个getBytes方法可以将字符串转为byte类型 * 和FileInputStream一样也有waite(byte[] b,int off,int length)去设置写入的长度和内容 * new FileOutputStream(filePath)这种方式是覆盖写入,new FileOutputStream(filePath,true),是追加写入 * */ public void m1(){ String filePath = "E:\\Study\\java\\hello.txt";//设置目标文件的路径 FileOutputStream fileOutputStream = null;//初始化对象 String str = "hello,world";//设置需要写入的内容 try { //new FileOutputStream(filePath)这种方式是覆盖写入,new FileOutputStream(filePath,true),是追加写入 fileOutputStream = new FileOutputStream(filePath,true);//创建FileOutputStream对象, //fileOutputStream.write('H');//waite(int b)写入单个字节,传入的是char,会自动转为int try { fileOutputStream.write(str.getBytes());//waite(byte[] b)将byte类型数组b写入,这里String有一个getBytes方法可以将字符串转为byte类型。 } catch (IOException e) { e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); }finally { try { fileOutputStream.close();//关闭流 } catch (IOException e) { e.printStackTrace(); } } } }
-
使用FileInputStream和FileOutputStream进行文件拷贝
-
要求:编程完成图片/音乐的拷贝。
public class FileCopyTest { public static void main(String[] args) { new FileCopyTest().m1(); } /* * 要求:将E:\Study\java\liuchang.jpg拷贝到D:\lover.jpg下 * 1.创建文件输入流,将源文件读取到程序中 * 2.创建文件输出流,将程序中的数据读取到目标文件中 * */ public void m1(){ String inFilePath = "E:\\Study\\java\\liuchang.jpg";//源文件 String outFilePath = "D:\\lover.jpg";//目标路径 FileInputStream fis =null;//初始化FileInputStream对象 FileOutputStream fos =null;//初始化FileOutputStream对象 try { fis = new FileInputStream(inFilePath);//创建FileInputStream对象并传入路径 fos = new FileOutputStream(outFilePath);//创建FileOutputStream对象并传入路径 byte[] bytes = new byte[1024];//创建字节数组,一次传输1024个字节 int readLength = 0;//创建int类型length用于接收read的实际返回值。 //读取 while ((readLength=fis.read(bytes))!=-1){ //写入 fos.write(bytes,0, readLength);//将write放入循环,每读完1024字节就写入1024字节,边读边写提高效率非常重要 } System.out.println("拷贝完成"); } catch (IOException e) { e.printStackTrace(); }finally { try { if(fis!=null){ fis.close(); } if(fos!=null){ fos.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
FileReader和FileWriter
-
两者继承关系:
-
-
FileReader和FileWriter介绍:
FileReader和FileWriter是字符流,即按照字符来操作io。
-
FileReader相关方法:
-
new FileReader(File file/String str);
-
read();每次读取单个字符,返回该字符,如果到文件末尾返回-1.
-
read(char[] c);批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1;
-
相关API:
- new String(char[] c);将char[] c转为String。
- new String(char[] c,int off,int len);将char[] c转为String。
-
案例演示:
使用FileReader从story.txt读取内容
read()单个字符单个字符读取
public class FlieReaderTest { public static void main(String[] args) { new FlieReaderTest().m1(); } /* * 使用FileReader从story.txt读取内容 *单个字符单个字符读取 * * */ public void m1(){ String filePath = "E:\\Study\\java\\story.txt";//设置源文件路径 FileReader fr=null;//初始化FileReader对象 int result = 0;//创建int类型变量接收fr.read()读取的结果 try { fr = new FileReader(filePath);//创建FileReader对象并传入源文件路径 while ((result=fr.read())!=-1) {//单个字节循环读取,返回int类型 System.out.print((char) result);//将int类型结果强转char输出 } } catch (IOException e) { e.printStackTrace(); } finally { if (fr!=null){ try { fr.close();//关闭流,释放资源 } catch (IOException e) { e.printStackTrace(); } } } } }
read(char[] c)用char数组批量读取
public class FlieReaderTest { public static void main(String[] args) { new FlieReaderTest().m2(); } /* * 使用FileReader从story.txt读取内容 * 用char数组读取read(char[] c) * int len =0;//实际读取到的字节数,而不是数据内容 * read(result)将数据读取到result数组中,转为int再返回给len,此时len是实际读取到的字节数,而不是数据的内容。 * public String(char value[], int offset, int count); String的的构造器中是可以传char数组的。 * */ public void m2(){ String filePath = "E:\\Study\\java\\story.txt";//设置源文件路径 FileReader fr=null;//初始化FileReader对象 char[] result = new char[1024]; int len =0;//实际读取到的字节数,而不是结果 try { fr = new FileReader(filePath);//创建FileReader对象并传入源文件路径 while ((len=fr.read(result))!=-1) {//read(result)将数据读取到result数组中,转为int再返回给len,此时len是实际读取到的字节数,而不是数据的内容。 System.out.print(new String(result,0,len));//将int类型结果强转char输出 } } catch (IOException e) { e.printStackTrace(); } finally { if (fr!=null){ try { fr.close();//关闭流,释放资源 } catch (IOException e) { e.printStackTrace(); } } } } }
-
-
FileWriter相关方法:
-
new FileWriter(File file/String str);覆盖模式。
-
new FileWriter(File file/String str,true);追加模式。
-
writer(int);写入单个字符,自动转为int返回。
-
writer(char[] c);写入指定数组。
-
writer(char[] c,int off, int len);写入指定数组指定部分。
-
writer(String str);写入整个字符串。
-
writer(String str,int off, int len);写入指定字符串指定部分。
-
相关API:
- String类:toCharArray:将String转为char[]。
-
注意:使用FileWriter后要close或者flush,因为在close或者flush之前所写的数据其实还在内存当中,只有当close或者flush后数据才算是真正的写入,否则写入不到目标文件。
-
案例演示:
使用FileWriter将”原神是世界上最好玩的游戏“写入到note.txt文件中
用writer(char [] c,int off,int len);写入
public class FileWriterTest { public static void main(String[] args) { new FileWriterTest().m2(); } /*使用FileWriter将"原神是世界上最好玩的游戏"写入到"E:\Study\java\note.txt"中 *用char数组写入 * */ public void m2(){ String filePath = "E:\\Study\\java\\note.txt";//设置目标文件路径 FileWriter fw=null;//初始化FileWriter对象 //String connect = "原神是世界上最好玩的游戏"; char[] arr= {'原','神','是','世','界','上','最','好','玩','的','游','戏'}; try { fw = new FileWriter(filePath,true);//创建FileWriter对象并传入路径,设置为追加模式 fw.write(arr,0,arr.length); //fw.write(connect.toCharArray(),0,connect.length()); System.out.println("写入完成"); } catch (IOException e) { e.printStackTrace(); } finally { try { if (fw!=null){ fw.close();//关闭流,释放资源,一定要关闭,不关闭上面程序白运行 } } catch (IOException e) { e.printStackTrace(); } } } }
用writer(String str,int off,int len);写入
public class FileWriterTest { public static void main(String[] args) { new FileWriterTest().m1(); } /*使用FileWriter将"原神是世界上最好玩的游戏"写入到"E:\Study\java\note.txt"中 *用String字符串写入 * */ public void m1(){ String filePath = "E:\\Study\\java\\note.txt";//设置目标文件路径 FileWriter fw=null;//初始化FileWriter对象 String contect = "原神是世界上最好玩的游戏"; try { fw = new FileWriter(filePath,true);//创建FileWriter对象并传入路径,设置为追加模式 fw.write(contect,0,contect.length()); System.out.println("写入完成"); } catch (IOException e) { e.printStackTrace(); } finally { try { if (fw!=null){ fw.close();//关闭流,释放资源,一定要关闭,不关闭上面程序白运行 } } catch (IOException e) { e.printStackTrace(); } } } }
-
节点流和处理流
-
基本介绍:
节点流和处理流一览图:
-
节点流可以从一个特定的数据源(例如:文件,数组,管道,字符串等)读写数据,如FileReader,FileWriter。
-
处理流也叫包装流(对节点流进行包装)是”连接“在已经存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,如BufferedReader,BufferedWriter。例如BufferedReader类源码中有一个Private Reader in;的属性,即我们可以封装任意的一个节点流,比如文件,数组等,不再局限于数据源,只要是Reader的子类都可以进行包装。
-
节点流和处理流的区别和联系:
- 节点流是底层流/低级流,直接跟数据源相接。
- 处理流包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。
- 处理流也叫包装流对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连。
-
处理流的功能主要体现在以下两个方面:
- 性能的提高:主要以增加缓冲的方式来提高输入输出的效率。
- 操作更加便捷:处理流可能提供了一系列边界的方法来一次输入输出大批量的数据,使用起来更加灵活方便。
-
BufferedReader和BufferedWriter
-
BufferedReader和BufferedWriter用于读取文本文件,不要读取二进制文件(视频,图像,doc,pdf等),可能会造成文件损坏!!!。
-
BufferedReader案例演示:
使用BufferedReader读取文本文件,并显示在控制台。
read(char[] arr)读取:
public class BufferedReaderTest { public static void main(String[] args) { new BufferedReaderTest().m1(); } /* * 使用BufferedReader读取文本文件,读取图片视频等二进制文件可能会损坏 * 用read(char[] arr)读取 * 创建BufferedReader程序运行完后只需要关闭外层的流即可,即BufferedReader,传进来的流不需要手动关闭,因为在调用的时候底层已经帮我们关闭了 * */ public void m1(){ String filePath = "E:\\Study\\java\\note.txt"; BufferedReader bufferedReader = null; char[] charArr= new char[1024]; int len=0; try { bufferedReader = new BufferedReader(new FileReader(filePath)); while ( (len=bufferedReader.read(charArr))!=-1) {//用read(char[] arr)读取 System.out.println(new String(charArr,0,len)); } System.out.println("读取成功"); } catch (IOException e) { e.printStackTrace(); }finally { try { if (bufferedReader!=null) { bufferedReader.close();//关闭流释放资源 } } catch (IOException e) { e.printStackTrace(); } } } }
使用BufferedReader读取文本文件,并显示在控制台。
用readLine()读取:
public class BufferedReaderTest { public static void main(String[] args) { new BufferedReaderTest().m2(); } /* * 使用BufferedReader读取文本文件,读取图片视频等二进制文件可能会损坏 * 用readLine()读取,当返回值String为null时停止 * 按行读取,效率高 * 创建BufferedReader程序运行完后只需要关闭外层的流即可,即BufferedReader,传进来的流不需要手动关闭,因为在调用的时候底层已经帮我们关闭了 * */ public void m2(){ String filePath = "E:\\Study\\java\\note.txt"; BufferedReader bufferedReader = null; String line = null;//用line去接受readLine的返回值 try { bufferedReader = new BufferedReader(new FileReader(filePath)); while ((line=bufferedReader.readLine())!=null) {//用readLine()读取,当返回值为null时停止 System.out.println(line); } System.out.println("读取成功"); } catch (IOException e) { e.printStackTrace(); }finally { try { if (bufferedReader!=null) { bufferedReader.close();//关闭流释放资源 } } catch (IOException e) { e.printStackTrace(); } } } }
-
BufferedWriter案例演示:
使用BufferedWriter将“原神是世界上最好玩的游戏”写入到文件中。
使用write(String str)方法以字符串写入:
public class BufferedWriteTest { public static void main(String[] args) { new BufferedWriteTest().m1(); } /* * 使用BufferedWrite将“原神是世界上最好玩的游戏”写入到文件中 *用write(String str)方法以字符串写入 **newLine()插入换行 * */ public void m1(){ String filePath = "E:\\Study\\java\\story.txt";//设置目标文件的路径 String connect = "原神是世界上最好玩的游戏"; BufferedWriter bufferedWriter = null; try { bufferedWriter = new BufferedWriter(new FileWriter(filePath,true));//创建BufferedWriter对象传入Write子类FileWriter对象,传入路径并设置追加模式 bufferedWriter.write(connect);//用write(String str)写入 System.out.println("写入完成"); } catch (IOException e) { e.printStackTrace(); }finally { try { if (bufferedWriter!=null) { bufferedWriter.close();//关闭外层流(内层不需关闭,调用时由底层JVM自动关闭),释放资源 } } catch (IOException e) { e.printStackTrace(); } } } }
使用BufferedWrite将“原神是世界上最好玩的游戏”写入到文件中
使用write(char[] arr,int off,int len)以字符数组写入:
public class BufferedWriteTest { public static void main(String[] args) { new BufferedWriteTest().m2(); } /* * 使用BufferedWrite将“原神是世界上最好玩的游戏”写入到文件中 *用write(char[] arr,int off,int len)以字符数组写入 *newLine()插入换行 * */ public void m2(){ String filePath = "E:\\Study\\java\\story.txt";//设置目标文件的路径 char[] charArr = {'原','神','是','世','界','上','最','好','玩','的','游','戏'}; BufferedWriter bufferedWriter = null; try { bufferedWriter = new BufferedWriter(new FileWriter(filePath,true));//创建BufferedWriter对象传入Write子类FileWriter对象,传入路径并设置追加模式 bufferedWriter.write(charArr,0,charArr.length);//用write(char[] arr,int off,int len)写入 System.out.println("写入完成"); } catch (IOException e) { e.printStackTrace(); }finally { try { if (bufferedWriter!=null) { bufferedWriter.close();//关闭外层流(内层不需关闭,调用时由底层JVM自动关闭),释放资源 } } catch (IOException e) { e.printStackTrace(); } } } }
使用BufferedReader和BufferedWriter进行文件拷贝
-
用read(char[] arr);write(char[] arr,int off,int len)方法读写。
public class BufferedFileCopyTest { public static void main(String[] args) { new BufferedFileCopyTest().m1(); } /* *拷贝文件将E:\Study\java\story.txt至E:\Study\java\copy.txt *用read(char[] arr);write(char[] arr,int off,int len)方法读写 * */ public void m1(){ String bufReFilePath = "E:\\Study\\java\\story.txt";//设置源文件读取路径 String bufWrFilePath = "E:\\Study\\java\\copy.txt";//设置写入目标文件路径 char[] arrArr =new char[1024];//以字符数组的形式读取数据,每次读取1024个字符 int len =0;//用int类型 len变量接收read(char [] arr)返回的实际字符数 BufferedReader bufferedReader =null;//初始化,方便下面关闭流 BufferedWriter bufferedWriter =null;//初始化,方便下面关闭流 try { bufferedReader = new BufferedReader(new FileReader(bufReFilePath));//创建BufferedReader包装流对象,传入FileReader节点流对象,并传入源文件读取路径 bufferedWriter = new BufferedWriter(new FileWriter(bufWrFilePath,true));//创建BufferedWriter包装流对象,传入FileReader节点流对象,并传入源文件读取路径,设置追加 //读取 while((len =bufferedReader.read(arrArr))!=-1){ //写入 bufferedWriter.write(arrArr,0,len); } System.out.println("拷贝完成"); } catch (IOException e) { e.printStackTrace(); } finally { try { if (bufferedReader!=null) { bufferedReader.close();//关闭外部包装流,节点流不需要手动关闭,调用时JVM底层自动关闭 } if (bufferedWriter!=null) { bufferedWriter.close();//关闭外部包装流,节点流不需要手动关闭,调用时JVM底层自动关闭 } } catch (IOException e) { e.printStackTrace(); } } } }
-
用readLine();write(String str)方法读写。
public class BufferedFileCopyTest { public static void main(String[] args) { new BufferedFileCopyTest().m2(); } /* *拷贝文件将E:\Study\java\story.txt至E:\Study\java\copy.txt *用readLine();write(String str)方法读写 * */ public void m2(){ String bufReFilePath = "E:\\Study\\java\\story.txt";//设置源文件读取路径 String bufWrFilePath = "E:\\Study\\java\\copy.txt";//设置写入目标文件路径 String line =null;//定义字符串line用于接收readLine返回值 BufferedReader bufferedReader =null;//初始化,方便下面关闭流 BufferedWriter bufferedWriter =null;//初始化,方便下面关闭流 try { bufferedReader = new BufferedReader(new FileReader(bufReFilePath));//创建BufferedReader包装流对象,传入FileReader节点流对象,并传入源文件读取路径 bufferedWriter = new BufferedWriter(new FileWriter(bufWrFilePath,true));//创建BufferedWriter包装流对象,传入FileReader节点流对象,并传入源文件读取路径,设置追加 //读取 while((line=bufferedReader.readLine())!=null){ //写入 bufferedWriter.write(line); bufferedWriter.newLine();//每读写一行就换行,非常重要 } System.out.println("拷贝完成"); } catch (IOException e) { e.printStackTrace(); } finally { try { if (bufferedReader!=null) { bufferedReader.close();//关闭外部包装流,节点流不需要手动关闭,调用时JVM底层自动关闭 } if (bufferedWriter!=null) { bufferedWriter.close();//关闭外部包装流,节点流不需要手动关闭,调用时JVM底层自动关闭 } } catch (IOException e) { e.printStackTrace(); } } } }
BufferedInputStream和BufferedOutputStream
-
BufferedInputStream和BufferedOutputStream和上面BufferedReader和BufferedWriter不同,它既可以用于读取二进制文件(视频,图像,doc,pdf等),也可以读取含中文等文本文件。
-
案例演示:
使用BufferedInputStream和BufferedOutputStream编程完成图片/音乐的拷贝。
public class BufferedMusicFileCopyTest { public static void main(String[] args) { new BufferedMusicFileCopyTest().m1(); } /* *使用BufferedInputStream和BufferedOutputStream编程完成图片/音乐的拷贝。 * 拷贝文件将E:\BackUpFile\音乐\陈一发儿 - 童话镇.mp3至E:\Study\java\copy.mp3 * * */ public void m1(){ String bisFilePath = "E:\\BackUpFile\\音乐\\陈一发儿童话镇.mp3";//设置音乐源文件的路径 String bosFilePath = "E:\\Study\\java\\copy.mp3";//设置目标文件的路径 BufferedInputStream bis =null;//初始化BufferedInputStream对象,方便下面关闭资源 BufferedOutputStream bos =null;//初始化BufferedOutputStream对象,方便下面关闭资源 byte[] bytes = new byte[1024];//创建字节数组用于存储读写的数据,每次读写1024字节 int len=0;//创建int类型变量len用于接收read(byte[] bytes);返回的实际字节数 try { bis = new BufferedInputStream(new FileInputStream(bisFilePath));//创建BufferedInputStream包装流对象,传入创建的FileInputStream节点流对象,传入源文件的路径字符串 bos = new BufferedOutputStream(new FileOutputStream(bosFilePath,true));//创建BufferedOutputStream包装流对象,传入创建的FileOutputStream节点流对象,传入目标文件的路径字符串,设置为追加模式 while ((len=bis.read(bytes))!=-1){//read(byte[] bytes)方法读取数据,返回的是int类型,len接收的不是文件实际内容,而是每次读取的字节数,用于写入时控制长度,当读取到文件末尾是返回-1 bos.write(bytes,0,len);//write(bytes, int off,int len)方法写入 } System.out.println("拷贝完成"); } catch (IOException e) { e.printStackTrace(); } finally { try { if (bis!=null){ bis.close();//关闭输入包装流释放资源 } if (bos!=null){ bos.close();//关闭输出包装流释放资源 } } catch (IOException e) { e.printStackTrace(); } } } }
对象流-ObjectInputStream和ObjectOutputStream
-
看一个需求:
- 将int num = 100这个int数据保存到文件中,注意不是100数字,而是int 100,并且能够从文件中直接回复int 100。
- 将Dog dog =new(“小黄”,3),这个对象dog保存到文件中,并且能从文件中恢复。
- 上面的要求就是能将基本数据类型或者对象进行序列化和反序列化操作
-
序列化和反序列化:
-
序列化就是在保存数据时,保存数据的值和数据类型。
-
反序列化就是在恢复数据时,恢复数据的值和数据类型。
-
需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现以下接口之一:
- Serializable //这是一个标记接口没有方法,推荐使用这个。
- Externalizable
-
-
案例演示序列化和反序列化:
-
注意事项:
-
读写顺序要一致。
-
要求实现序列化和反序列化的对象的类需要实现Serializable。
-
序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性。
private static final long serialVersionUID =1L;//SerialVersionUID,提高版本的兼容性。
-
序列化对象时,默认将里面的所有属性都进行序列化,但除了static或transient修饰的成员。
-
序列化对象时,要求里面属性的类型也需要实现序列化接口。
-
序列化具备可继承性,也就是如果某类已经实现了序列化,则他的所有子类也已经默认实现了序列化。
public class ObjectOutStreamTest { public static void main(String[] args) { new ObjectOutStreamTest().m1(); new ObjectOutStreamTest().m2(); } /* * 使用ObjectOutputStream完成数据的序列化 * 序列化后,保存文件的格式不是纯文本,而是按照他的格式去保存的 * oos.writeObject(new Student("xiaohuang",21,'女'));保存对象,如果要保存的对象的类不实现Serializable就会报错:NotSerializableException * * */ public void m1(){ String filePath = "E:\\Study\\java\\date.dat";//设置目标文件的路径 ObjectOutputStream oos =null;//初始化对象,方便关闭资源 String s = new String("抽烟只抽煊赫门,一生只爱一个人"); try { oos = new ObjectOutputStream(new FileOutputStream(filePath));//创建ObjectOutputStream包装流对象,传入节点流对象FileOutputStream,传入目标文件路径 //序列化写入 oos.writeInt(100);//用writeInt(int val)写入,int 100自动装箱成Integer,而Integer类实现了Serializable oos.writeBoolean(true); //用writeBoolean(boolean val)写入 oos.writeChar('a');//用writeChar(char val)写入 oos.writeDouble(9.5);//用writeDouble(Double val)、 oos.writeUTF(s);//保存String字符串 oos.writeObject(new Student("xiaohuang",21,'女'));//保存对象,如果要保存的对象的类不实现Serializable就会报错:NotSerializableException System.out.println("序列化完成"); } catch (IOException e) { e.printStackTrace(); }finally { try { if (oos!=null){ oos.close();//关闭包装流,释放资源,节点流底层自动关闭 } } catch (IOException e) { e.printStackTrace(); } } } /* * 使用ObjectInputStream完成数据的反序列化 * 读取(反序列化)的顺序要和你保存数据(序列化)的顺序一致 * 如果反序列化出现错误,修改后要重新序列化后再反序列化 * */ public void m2(){ String filePath = "E:\\Study\\java\\date.dat";//设置源文件的路径 ObjectInputStream ois=null;//初始化对象,方便关闭资源 try { ois = new ObjectInputStream(new FileInputStream(filePath)); //读取(反序列化)的顺序要和你保存数据(序列化)的顺序一致 System.out.println(ois.readInt()); System.out.println(ois.readBoolean()); System.out.println(ois.readChar()); System.out.println(ois.readDouble()); System.out.println(ois.readUTF()); try { Object o =ois.readObject(); System.out.println(o); } catch (ClassNotFoundException e) { e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); }finally { try { if (ois!=null){ ois.close();//关闭包装流,释放资源,节点流底层自动关闭 } } catch (IOException e) { e.printStackTrace(); } } } }
-
标准输入输出流
-
System.out.println(System.in.getClass());//结果:class java.io.BufferedInputStream 包装流
- 由上可得:System.in 编译类型是InputStream,运行类型是BufferedInputStream
-
System.out.println(System.out.getClass());//结果:class java.io.PrintStream 包装流
- 由上可得:System.out 编译类型是PrintStream,运行类型是PrintStream
转换流-InputStreamReader和OutputStreamWriter
-
为什么有转换流-InputStreamReader和OutputStreamWriter:
-
例如:默认情况下,读取文件是按照UTF-8读取是没问题的,但如果不是UTF-8那么一定会乱码。
默认情况:
public class CodeQuestion { public static void main(String[] args) throws IOException { new CodeQuestion().m1(); } //默认情况下,读取文件是按照UTF-8读取是没问题的,但如果不是UTF-8那么一定会乱码 public void m1() throws IOException { //读取文件E:\Study\java\中文乱码.txt到程序 String filePath = "E:\\Study\\java\\中文乱码.txt"; String line =null; BufferedReader br = new BufferedReader(new FileReader(filePath)); while ((line=br.readLine())!=null) { System.out.println(line); } br.close(); } }
改变源文件编码(gbk)后再次运行
-
当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换为字符流。
-
可以在使用时指定编码的格式(比如:utf-8,gbk,gb2312,IOS8859-1等)。
-
所以引出转换流-InputStreamReader和OutputStreamWriter解决的就是这种问题。转换流可以让文件从字节流转换为字符流,而字节流可以去设置编码格式,从而解决乱码问题。下图InputStreamReader和OutputStreamWriter结构相似只放一个图参考。
-
-
案例演示:
编程将字节流FileOutputStream包装成(转换成)字符流OutputStreamWriter,对文件进行读取(按照utf-8格式),进而在包装成BufferedWriter。
public class OutputStreamWriterTest { public static void main(String[] args) throws IOException { new OutputStreamWriterTest().m1(); } /* * 编程将字节流FileOutputStream包装成(转换成)字符流OutputStreamWriter,对文件进行读取(按照utf-8格 式),进而在包装成BufferedWriter。 * 解决上面文件中文乱码问题,E:\\Study\\java\\中文乱码.txt * */ public void m1() throws IOException { String filePath ="E:\\\\Study\\\\java\\\\中文乱码.txt";//设置写入目标文件路径 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath,true), "gbk");//用OutputStreamWriter包装FileOutputStream,并设置编码 BufferedWriter bw = new BufferedWriter(osw);//最终还是用BufferedWriter写入,效率更高 bw.write("hello,原神!"); bw.newLine();//换行 bw.close();//关闭外层流即可,内层流底层自动关闭 } }
-
案例演示:
编程将字节流FileInputStream包装成(转换成)字符流InputStreamReader,对文件进行读取(按照utf-8格式),进而在包装成BufferedReader。
public class InputStreamReaderTest { public static void main(String[] args) throws IOException { new InputStreamReaderTest().m1(); } /* 编程将字节流FileInputStream包装成(转换成)字符流InputStreamReader,对文件进行读取(按照utf-8格式),进而在包装成BufferedReader。 *解决上面文件中文乱码问题,E:\\Study\\java\\中文乱码.txt */ public void m1() throws IOException { String filePath ="E:\\Study\\java\\中文乱码.txt";//源文件路径 源文件编码格式为gbk InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), "gbk");//用InputStreamReader包装FileInputStream,并设置编码 BufferedReader br = new BufferedReader(isr);//最终还是用BufferedReader去读取,效率更高 String line =null; while ((line=br.readLine())!=null){ System.out.println(line); } br.close();//关闭外层流即可,内层流底层自动关闭 } }
打印流 PrintStream和PrintWriter
-
PrintStream(字节流)和PrintWriter(字符流)打印流只有输出流,没有输入流。
-
继承关系看上面IO流体系图
-
打印流 PrintStream和PrintWriter不仅可以传节点流,还可以传文件,可以将数据打印显示,也可以将数据打印在文件中。
-
字节打印流PrintStream:
public class PrintStreamTest { public static void main(String[] args) throws IOException { new PrintStreamTest().m1(); } /* * 演示PrintStream字节打印流/输出流 */ public void m1() throws IOException { PrintStream out = System.out;//在默认情况下,PrintStream输出数据位置是标准输出,即显示器 out.println("标准输出"); out.write("调用write进行打印输出".getBytes());//因为print()底层使用的是write()方法,所以我们可以直接调用write进行打印输出 System.setOut(new PrintStream("E:\\Study\\java\\test1.txt"));//System有一个方法setOut可以设置数据传输的位置,传入一个PrintStream再传入路径即可,会直接打印输出在文件中 System.out.println("111111"); out.close(); } }
-
字符打印流PrintWriter:
public class PrintWriterTest { public static void main(String[] args) throws IOException { new PrintWriterTest().m1(); } /* * 演示PrintWrite字节打印流/输出流 * 重点:一切关于write的流没有close或flush写不进去东西 * */ public void m1() throws IOException { // PrintWriter pw = new PrintWriter(System.out); // pw.print("hello,原神!");// PrintWriter pw = new PrintWriter(new FileWriter("e:\\Study\\java\\test1.txt")); pw.println("hello,原神!");//可以直接打印到文件中 pw.close();//重点:一切关于write的流没有close或flush写不进去东西 } }
Properties类
-
基本介绍:
-
Properties类专门用于读写配置文件的集合类。
-
配置文件的格式为:
键=值
键=值
-
注意:键值对不需要有空格,值不需要用引号引起来。默认类型是String。
-
Properties类常用的方法:
-
load:加载配置文件的键值对到Properties对象。
-
list:将数据显示到指定设备/流对象。
-
getProperty(key):根据键获取值。
-
setProperty(key,value):设置键值对到Properties对象。如果没有这个键值,就会自动创建该键值。
-
store:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件中,如果含有中文,会存储为unicode码。
Unicode编码转换 - 站长工具 unicode码查询工具。
-
-
-
为什么要使用Properties配置文件,因为我们在使用或换数据库时需要读取配置文件中的账号和密码等相关信息,如果在程序中将这些信息写死就不利于我们后期去修改信息和换数据库。因此引出Properties类。
-
先看一个需求:
- 如下有一个配置文件mysql.properties
- ip = 192.168.0.13
- user = root
- pwd=12345
- 请问编程读取ip,user和pwd的值是多少。
- 分析:
- 传统的方法。
- 使用Properties类可以方便实现。
-
使用传统的方法:
传统的方法可以实现,但配置文件内容过多会很麻烦,修改也很麻烦。
public class PropertiesTest { public static void main(String[] args) throws IOException { new PropertiesTest().m1(); } //获取src下mysql.properties配置文件中的信息 public void m1() throws IOException { String filePath = "E:\\Study\\java\\JavaFullStack\\src\\mysql.properties"; BufferedReader br = new BufferedReader(new FileReader(filePath)); String line =null; while ((line=br.readLine())!=null){ // System.out.println(line);//这是打印全部的内容,我们只要ip,user,pwd的值 String[] split = line.split("=");//根据“=”分组变成一个字符串数组 // //如果我们要指定获取ip的值,就只能判断,这比较麻烦 // if("ip".equals(split[0])){ // System.out.println(split[0]+"的值是:"+split[1]); // } System.out.println(split[0]+"的值是:"+split[1]);//split[1]即为我们想要的值 } br.close(); } }
输出结果:
ip的值是:192.168.100.100 user的值是:root pwd的值是:12345
-
使用Properties类:
-
案例演示:
- 使用Properties类完成对mysql.properties的读取。
- 使用Properties类添加key-val到新文件mysql2.properties中。
- 使用Properties类完成对mysql.properties的读取,并修改某个key-val。
public class PropertiesTest { public static void main(String[] args) throws IOException { new PropertiesTest().m1(); new PropertiesTest().m2(); new PropertiesTest().m3(); } //使用Properties类完成对mysql.properties的读取。 public void m1() throws IOException { String filePath ="src\\mysql.properties"; Properties properties = new Properties();//创建对象 properties.load(new FileReader(filePath));//加载指定配置文件 //properties.list(System.out);//输出到显示器 System.out.println(properties.getProperty("user"));//根据键获取值并输出 } //使用Properties类添加key-val到新文件mysql2.properties中。 public void m2() throws IOException { String filePath = "src\\mysql2.properties"; Properties properties = new Properties(); properties.setProperty("username","root");//有这个键就是修改,没有就是创建 properties.setProperty("password","330366");//有这个键就是修改,没有就是创建 properties.store(new FileOutputStream(filePath),null);//保存数据到指定文件,没有这句话上面代码就不会运行,comments是注释的意思,生成配置文件是会显示在配置文件最上面,必须要写,没有可写null } //使用Properties类完成对mysql.properties的读取,并修改某个key-val。 public void m3() throws IOException { String filePath = "src\\mysql.properties"; Properties properties = new Properties(); properties.load(new FileReader(filePath)); properties.setProperty("user","Hangover");//修改user的值为Hangover,有这个键就是修改,没有就是创建 properties.store(new FileOutputStream(filePath),null);//保存数据到指定文件,没有这句话上面代码就不会运行,comments是注释的意思,生成配置文件是会显示在配置文件最上面,必须要写,没有可写null } }
-
练习1
-
题目:
- 在判断e盘下是否有文件夹mytemp,如果没有就创建mytemp。
- 在e:\mytemp目录下,创建文件hello.txt。
- 如果hello.txt存在,提示该文件已经存在,就不要重复创建了。
public class Homework01 { public static void main(String[] args) { new Homework01().m1(); new Homework01().m2(); } //在判断e盘下是否有文件夹mytemp,如果没有就创建mytemp。 public void m1(){ String filePath = "e:\\"; String fileName = "mytemp"; File mytemp = new File(filePath, fileName); if(mytemp.exists()){ System.out.println(fileName+"该文件夹存在"); }else { mytemp.mkdirs(); } } public void m2(){ String filePath = "e:\\mytemp\\"; String fileName = "hello.txt"; File hello = new File(filePath,fileName); if (hello.exists()){ System.out.println(fileName+"该文件夹存在"); }else { try { hello.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } } }
练习2
-
题目:
- 使用BufferedReader读取一个文本文件,为每行加上行号,在连同内容一并输出到屏幕上。
public class Homework02 { public static void main(String[] args) { new Homework02().m1(); } public void m1(){ String filePath = "E:\\Study\\java\\test1.txt"; BufferedReader br = null; try { br = new BufferedReader(new FileReader(filePath)); int hanghao=0; String line = null; while ((line=br.readLine())!=null) { hanghao++; System.out.println("第"+hanghao+"行内容为:"+line); } } catch (IOException e) { e.printStackTrace(); }finally { try { if (br!=null) { br.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
练习3
-
题目:
-
要编写一个dog.properties
name=tom
age=5
color=red
-
编写Dog类(name,age,color)创建一个dog对象,读取dog.properties用相应的内容完成属性初始化,并输出。
public class Homework03 { public static void main(String[] args) { Homework03 homework03 = new Homework03(); homework03.m1(); homework03.m2(); } //创建dog.properties,并添加相应的键值对 public void m1(){ String propertiesFilePath ="src\\"; String propertiesFileName ="dog.properties"; File dogProper = new File(propertiesFilePath,propertiesFileName); try { dogProper.createNewFile(); } catch (IOException e) { e.printStackTrace(); } Properties properties = new Properties(); properties.setProperty("name","tom"); properties.setProperty("age","5"); properties.setProperty("color","red"); try { properties.store(new FileOutputStream(propertiesFilePath+propertiesFileName),null); } catch (IOException e) { e.printStackTrace(); } } //获取dog.properties里面的值 public void m2(){ String propertiesFilePath ="src\\"; String propertiesFileName ="dog.properties"; Properties properties = new Properties(); try { properties.load(new FileReader(propertiesFilePath+propertiesFileName)); String name = properties.getProperty("name"); int age = Integer.parseInt(properties.getProperty("age")) ; String color = properties.getProperty("color"); Dog dog = new Dog(name, age, color); System.out.println(dog.toString()); } catch (IOException e) { e.printStackTrace(); } } } class Dog{ String name =null; int age =0; String color =null; public Dog() { } public Dog(String name, int age, String color) { this.name = name; this.age = age; this.color = color; } 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 String getColor() { return color; } public void setColor(String color) { this.color = color; } @Override public String toString() { return "Dog{" + "name='" + name + '\'' + ", age=" + age + ", color='" + color + '\'' + '}'; } }
-