一、文件
1、创建文件
package com.yys02.file;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.IOException;
//演示创建文件
public class FileCreate {
public static void main(String[] args) {
}
//方式一:new File(String pathname)
@Test
public void create01(){
String filePath = "e:\\news1.txt";//第一个“/”是转义字符,要么写出“\"
File file = new File(filePath);
try {
file.createNewFile();
System.out.println("文件创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
//方式二:new File(File parent,String child) //根据父目录文件+子路径构建
@Test
public void create02(){
File parentFile = new File("e:\\");
String fileName = "news2.txt";
//这里的file对象,在java程序中,只是一个对象
//只有执行了createNewFile 方法,才会真正的,在磁盘创建该文件
File file = new File(parentFile, fileName);
try {
file.createNewFile();
System.out.println("创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
//方式三:new File(String parent,String child) //根据父目录+子路径构建
@Test
public void create03(){
String parentPath = "e:\\";
String fileName = "news3.txt";
File file = new File(parentPath, fileName);
try {
file.createNewFile();
System.out.println("文件创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}
2、获取文件信息
//获取文件的信息
public void info() throws IOException {
//先创建文件对象
File file = new File("e:\\news01.txt");
//调用相应的方法,得到对应信息
System.out.println("文件名字="+file.getName());
System.out.println("绝对路径="+file.getAbsolutePath());//获取绝对路径
System.out.println("文件父级目录="+file.getParent());
System.out.println("文件大小(字节)="+file.length());
System.out.println("文件是否存在="+file.exists());//T
System.out.println("是不是一个文件="+file.isFile());//T
System.out.println("是不是一个目录="+file.isDirectory());//F
}
3、目录的操作和文件的删除
注:delete 删除目录 只能删除 空的目录
//判断 d:\\news01.txt 是否存在,如果存在就删除
@Test
public void m1() throws IOException {
String filePath = "d:\\news01.txt";
File file = new File(filePath);
if(file.exists()){
if(file.delete()){
System.out.println("删除成功");
}else{
System.out.println("删除失败");
}
}else{
System.out.println("该文件不存在");
}
}
//判断 D:\\demo02 是否存在,存在就删除,否则就提示不存在
//这里我们需要体会到,在java编程中,目录也被当做文件
@Test
public void m2() throws IOException {
String filePath = "d:\\demo02";
File file = new File(filePath);
if(file.exists()){
if(file.delete()){
System.out.println("删除成功");
}else{
System.out.println("删除失败");
}
}else{
System.out.println("该目录不存在");
}
}
//判断 D:\\demo\\a\\b\\c 目录是否存在,如果存在就提示已经存在,否则就创建
@Test
public void m3() throws IOException {
String directoryPath = "D:\\demo\\a\\b\\c";
File file = new File(directoryPath);
if(file.exists()){
System.out.println(directoryPath+"存在...");
}else{
if(file.mkdirs()) {//创建多级目录 ,mkdir() 只能创建一级目录
System.out.println(directoryPath+"创建成功");
}else{
System.out.println(directoryPath+"创建失败");
}
}
}
二、IO流原理及流的分类
1、Java IO流原理
2、流的分类
三、输入流(字节)
1、InputStream 字节输入流
//演示FileInputStream的使用(字节输入流 文件 -> 程序)
public class FileInputStream_ {
public static void main(String[] args) {
}
//单个字节的读取,效率比较低
@Test
public void readFile01() {
String filePath = "e:\\hello.txt";
int readData = 0;
//创建了FileInputStream对象,用于读取文件
FileInputStream fileInputStream = null;//扩大作用域,让finally能使用
try {
//创建了FileInputStream对象,用于读取文件
fileInputStream = new FileInputStream(filePath);
//读取一个字节数据,如果返回-1,表示读取完毕
//循环读取
while((readData = fileInputStream.read()) != -1){
System.out.print((char)readData);//转成一个char显示
}
} catch (IOException e) {
e.printStackTrace();
}finally{
//关闭文件流,释放资源
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//使用 read(byte[] b) 读取文件,提高效率
@Test
public void readFile02() {
String filePath = "e:\\hello.txt";
//字节数组
byte[] buf = new byte[8];//一次读取8个字节
int readLength = 0;
//创建了FileInputStream对象,用于读取文件
FileInputStream fileInputStream = null;//扩大作用域,让finally能使用
try {
//创建了FileInputStream对象,用于读取文件
fileInputStream = new FileInputStream(filePath);
//从该输入流读取最多b.length字节的数据到字节数组,此方法将阻塞,知道某些输入可用
//循环读取,如果返回-1,读取完毕
//如果读取正常,返回实际读取的字节数
while((readLength = fileInputStream.read(buf)) != -1){
System.out.println(new String(buf,0,readLength));//字节数组构建一个字符串
}
} catch (IOException e) {
e.printStackTrace();
}finally{
//关闭文件流,释放资源
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
四、输出流(字节)
1、FileOutputStream
//演示使用 FileOutputStream 将数据写到文件中
//如果该文件不存在,则创建该文件
@Test
public void writeFile() {
//创建 FileOutputStream 对象
String fillePath = "e:\\a.txt";
FileOutputStream fileOutputStream = null;
try {
//得到 FileOutputStream 对象
//1、如果 new FileOutputStream(fillePath); 创建方式,当写入内容时,会覆盖原来的内容
//2、new FileOutputStream(fillePath, true); 创建方式,当写入内容时,是追加到文件后面
fileOutputStream = new FileOutputStream(fillePath);
//方式一:写入一个字节
//fileOutputStream.write('H');//char 会自动转为 int
//方式二、写入字符串
//String str = "hello,world";
//str.getBytes() 可以把字符串转化为 Byte(字节) 数组
//fileOutputStream.write(str.getBytes());
/*方式三:
write(byte[] b, int off, int len) 将 len 字节从位于偏移量 off 的指定字节数组写入此文件
*/
String str = "hello,world!!!";
fileOutputStream.write(str.getBytes(),0,str.length());//从位置 0 开始,全部写入
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
文件的拷贝:
public class FileCopy {
public static void main(String[] args) {
//完成文件拷贝
//思路分析
//1、创建文件的输入流,将文件读入到程序
//2、创建文件的输出流,将读取到的文件数据,写入到指定的位置
String filePath = "e:\\屏幕截图(5).png";//源文件路径
String destFilePath = "f:\\屏幕截图(5).png";//准备拷贝到的路径
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
fileInputStream = new FileInputStream(filePath);//文件输入流
fileOutputStream = new FileOutputStream(destFilePath);//文件输出流
//定义一个字节数组,提高读取效率
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = fileInputStream.read(buf)) != -1) {
//读取到后,就写入到文件,通过fileOutputStream
//即边读边写
fileOutputStream.write(buf, 0, readLen);//一定要使用这个
}
System.out.println("拷贝成功");
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭输入流和输出流释放资源
if(fileInputStream != null){
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fileOutputStream != null){
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
五、FileReader 和 FileWriter(文件字符流)
1、介绍
七、输入流(字符)
案例:
//方法一:使用read,单个字符读取(效率不高)
@Test
public void readFile01() {
String filePath = "e:\\story.txt";
FileReader fileReader = null;
int data = ' ';
try {
//1、创建 FileReader 对象
fileReader = new FileReader(filePath);
//循环读取,方法一:使用read,单个字符读取(效率不高)
while ((data = fileReader.read()) != -1) {
System.out.print((char) data);//转换成char,因为是字符
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
if (fileReader != null) {
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//方法二:使用字符数组读取文件(效率高)
@Test
public void readFile02() {
String filePath = "e:\\story.txt";
FileReader fileReader = null;
int readLen = 0;
char[] buf = new char[8];//一次读取8个
try {
//1、创建 FileReader 对象
fileReader = new FileReader(filePath);
//循环读取,法二:使用read(buf)字符数组读取文件(效率高),返回的是实际读取到的字符数
//如果返回-1,说明文件结束
while ((readLen = fileReader.read(buf)) != -1) {//一次8个的读取
//在buf里,从下标为0开始取readLen个转化为字符串
System.out.print(new String(buf, 0, readLen));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
if (fileReader != null) {
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
八、输出流(字符)
案例:
public class FileWriter_ {
public static void main(String[] args) {
String filePath = "e:\\note.txt";
//创建FileWriter对象
FileWriter fileWriter = null;
char[] chars = {'a','b','c'};
try {
fileWriter = new FileWriter(filePath);//默认是覆盖
//1、write(int):写入单个字符
fileWriter.write("H");
//2、write(char[]):写入指定数组
fileWriter.write(chars);
//3、write(char[].off,len):写入指定数组的指定部分
fileWriter.write("叶育笙叶育笙".toCharArray(),0,3);//toCharArray()转化为数组
//4、write(string):写入整个字符串
fileWriter.write(" 成都成都成都");
//5、write(string,off,len):写入字符串的指定部分
fileWriter.write(" 中国成都上海绵阳",0,2);
//在数据量大的情况下,可以使用循环操作
} catch (IOException e) {
e.printStackTrace();
} finally {
//对于FileWriter,一定要关闭流,或flush(刷新),才能真正的把数据写入到文件
try {
fileWriter.close();
//或 fileWriter.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
九、节点流和处理流
节点流和处理流的区别和联系:
处理流:
(一)BufferedReader 和 BufferedWriter
注:处理 字符 的,没办法处理二进制文件
1、BufferedReader
//演示BufferedReader 使用
public class BufferedReader_ {
public static void main(String[] args) throws IOException {
String filePath = "e:\\a.java";
//创建BufferedReader
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
//读取 BufferedReader 在读取的时候,底层是 FileReader 在读取
String line;//按行读取,效率高
//line = bufferedReader.readLine() 是按行读取,当返回是 null 时,读取完毕
while((line = bufferedReader.readLine()) != null){
System.out.println(line);
}
//关闭流,本身应该是关闭new FileReader(filePath)
//但是这里只需关闭 BufferedReader ,因为底层会自动关闭节点流(FileReader)
bufferedReader.close();
}
}
2、BufferedWriter
3、使用 BufferedReader 和 BufferedWriter 完成文件拷贝
public class BufferedCopy_ {
public static void main(String[] args) throws IOException {
//注意:
//1.BufferedReader 和 BufferedWriter 是安装字符操作
//2、不要去操作 二进制文件,可能造成文件损坏
String srcFilePath = "e:\\ok.txt";
String destFilePath = "e:\\ok2.txt";
BufferedReader br = null;
BufferedWriter bw = null;
br = new BufferedReader(new FileReader(srcFilePath));//源文件
bw = new BufferedWriter(new FileWriter(destFilePath));//拷贝
String line;
//读取、写入
//说明:readLine 读取一行内容,但是没有换行,需要插入换行
while ((line = br.readLine()) != null){
//每读取一行就写入
bw.write(line);
bw.newLine();//换行
}
//关闭流
if(br!=null){
br.close();
}
if(bw!=null){
bw.close();
}
}
}
(二) BufferedInputStream 和 BufferedOutputStream(字节流,可以操作二进制文件,也可以操作文本文件)
注:BufferedInputStream 可以使用 InputStream 的实现子类的对象,
BufferedOutputStream 可以使用 OutputStream 的实现子类的对象。
案例:使用 BufferedInputStream 和 BufferedOutputStream 完成文件拷贝
//演示 BufferedInputStream 和 BufferedOutputStream 使用
public class BufferedCopy {
public static void main(String[] args) throws IOException {
String srcFilePath = "e:\\ok.png";//原文件路径
String destFilePath = "e:\\ok0.png";//拷贝路径
//创建 BufferedInputStream 和 BufferedOutputStream
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
//因为 FileInputStream 是 InputStream 的子类
bis = new BufferedInputStream(new FileInputStream(srcFilePath));
bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
//循环读取文件,并写入到到 destFilePath
byte[] buff = new byte[1024];
int readLen = 0;
while ((readLen = bis.read(buff)) != -1) {//读取
bos.write(buff, 0, readLen);//写入
}
System.out.println("文件拷贝完毕");
//关闭外层处理流即可,底层会关闭节点流
if(bis != null){
bis.close();
}
if(bos != null){
bos.close();
}
}
}
注:字节流可以操作二进制文件,也可以操作文本文件
(三)ObjectInputStream(反序列化) 和 ObjectOutputStream(序列化)(对象处理流)
注:ObjectInputStream 有一个构造器,可以接收一个实现了 InputStream 的类的对象
注:ObjectOutputStream有一个构造器,可以接收一个实现 OutputStream的类的对象
1、ObjectOutputStream(序列化)
案例:
//演示 ObjectOutputStream 的使用,完成数据的序列化
public class ObjectOutputStream_ {
public static void main(String[] args) throws IOException {
//序列化后,保存的文件格式,不是纯文本的,而是按照他的格式来保存,
// 所以 data.dat 的后缀.dat并没有实际的意义
String filePath = "e:\\data.dat";//data.dat 的后缀.dat并没有实际的意义
ObjectOutputStream oos = null;
oos = new ObjectOutputStream(new FileOutputStream(filePath));
//序列化数据到 e:\data.dat
oos.writeInt(100);//int 会在底层自动装箱成 Integer(实现了Serializable)
oos.writeBoolean(true);//boolean 会在底层自动装箱成 Boolean(实现了Serializable)
oos.writeChar('a');char 会在底层自动装箱成 Character(实现了Serializable)
oos.writeDouble(9.5);//double 会在底层自动装箱成 Double(实现了Serializable)
oos.writeUTF("叶育笙");//String
//保存一个Dog对象
oos.writeObject(new Dog("黑贝",1));//注:Dog对象要实现 Serializable 接口
//关闭流
oos.close();
System.out.println("数据保存完毕(序列化)");
}
}
//如果需要序列化某个类的对象,需要实现 Serializable(标志接口) 接口
public class Dog implements Serializable {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"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;
}
}
2、ObjectInputStream(反序列化)
案例:
public class ObjectInputStream_ {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//指定反序列化文件
String filePath = "e:\\data.dat";
ObjectInputStream 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());
//dog 的编译类型是Object,dog 的运行类型是 Dog
Object dog = ois.readObject();
System.out.println("运行类型="+dog.getClass());
System.out.println("狗的信息"+dog);//底层Object -> Dog
//这里是特别重要的细节:
//1、如果我们希望调用Dog的方法,需要向下转型
//2、需要我们将Dog的定义,放在可以引用的位置(可以不同包)
Dog dog2 = (Dog) dog;
System.out.println(dog2.getName());//只会输出 黑贝
//关闭流,关闭外层流即可,底层(FileInputStream)会自动关闭
ois.close();
}
}
3、对象处理流的使用细节(ObjectInputStream ObjectOutputStream)
(四)标准输入输出流
(五)转换流-InputStreamReader 和 OutputStreamWriter
转换流可以将字节流转换成字符流,而字节流可以指定编码方式
注:可以传入一个InputStream,而且可以指定编码方式
注:可以传入一个OutputStream,而且可以指定编码方式
1、InputStreamReader
案例:
//演示使用 InputStreamReader 转换流解决中文乱码问题
//将字节流 FileInputStream 转成字符流 InputStreamReader,指定编码 gbk/utf-8
public class InputStreamReader_ {
public static void main(String[] args) throws IOException {
String filePath = "e:\\a.txt";
//把 new FileInputStream 转换成 InputStreamReader,并指定编码为 gbk
InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath),"gbk");
// 把 InputStreamReader 传给 BufferedReader
BufferedReader br = new BufferedReader(isr);
//读取
String s = br.readLine();
System.out.println(s);
//关闭外层流
br.close();
}
}
2、OutputStreamWriter
案例:
//演示 OutputStreamWriter 使用
//把 FileOutputStream 字节流,转换成字符流 OutputStreamWriter
//指定处理的编码 gbk/uft-8(uft8)
public class OutputStreamWriter_ {
public static void main(String[] args) throws IOException {
String filePath = "e:\\yys.txt";
String charSet = "utf-8";
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath), charSet);
osw.write("叶育笙");
System.out.println("按照"+charSet+"编码方式保存成功");
osw.close();
}
}
(六)打印流-PrintStream(字节流) 和 PrintWriter(字符流)(只有输出没有输 入
案例:PrintStream 字节打印
// 演示 PrintStream (字节打印流/输出流)
public class PrintStream_ {
public static void main(String[] args) throws IOException {
PrintStream out = System.out;
//在默认情况下,PrintStream 输出数据的位置是 标准输出,即显示器
out.print("hello");
//因为print的底层是write,所以我们可以直接调用write进行输出/打印
out.write("叶育笙".getBytes());//write 是按照字节打印的,因为PrintStream是字节流
out.close();
//我们可以去修改打印流输出的位置/设备
//输出修改到 "e:\\f1.txt"
//"叶育笙" 就会输出到"e:\\f1.txt"中
System.setOut(new PrintStream("e:\\f1.txt"));
System.out.println("叶育笙");
}
}
十、Properties 类
1、Properties 读文件
案例:
public static void main(String[] args) throws IOException {
//使用Properties 类来读取 mysql.properties 文件
//创建Properties对象
Properties properties = new Properties();
//2、加载指定的配置文件
properties.load(new FileReader("src\\mysql.properties"));
//3、把k-v(键值对)显示控制台
properties.list(System.out);
//4、根据key(键)获取值
String user = properties.getProperty("user");
System.out.println("user的值为:" + user);
}
2、Properties 修改文件
public static void main(String[] args) throws IOException {
//使用Properties类来创建配置文件,修改配置文件
//创建Properties对象
Properties properties = new Properties();
//创建
//如果该文件没有 key 就是创建,没有 key 就是替换或者修改
//Properties 父类是 Hashtable,底层就是 Hashtable 核心方法
properties.setProperty("charset","utf8");
properties.setProperty("user","汤姆");//注意保存是,是中文的 unicode 码值
properties.setProperty("pwd","abc111");
properties.setProperty("pwd","88888");//修改
//将k-v存储到文件中即可
properties.store(new FileOutputStream
("src\\mysql2.properties"),null);//null,这个位置是注释
System.out.println("保存配置文件成功");
}
练习1:
public class HomeWork01 {
public static void main(String[] args) throws IOException {
/*
(1)在判断e盘下是否有文件夹mytemp,如果没有就创建mytemp
(2)在e:\\mytemp目录下,创建文件hello.txt
(3)如果hello.txt已经存在,提示该文件已经存在,就不要再重复创建了
(4)并且在hello.txt文件中,写入hello,world~
*/
String directoryPath = "e:\\mytemp";
File file = new File(directoryPath);
if (!file.exists()) {
//创建
if (file.mkdirs()) { //file.mkdirs() 创建目录
System.out.println("创建" + directoryPath + "成功");
} else {
System.out.println("创建" + directoryPath + "失败");
}
}
String filePath = directoryPath + "\\hello.txt";//文件路径,e:\mytemp\hello.txt
File file1 = new File(filePath);
if (!file1.exists()) {
//创建文件
if (file1.createNewFile()) {
System.out.println("创建" + filePath + "成功");
//如果文件存在,我们就使用BufferedWriter 字符输入流写入内容
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file1));
bufferedWriter.write("hello,world");
//关闭流
bufferedWriter.close();
} else {
System.out.println("创建" + filePath + "失败");
}
}else{
//如果文件已经存在,给出提示信息
System.out.println(file1+"已经存在,不再重复创建");
}
}
}
练习2:
public class HomeWork02 {
public static void main(String[] args) throws IOException {
/*
(1)要编写一个dog.properties name=tom age= 5 color=red
(2)编写Dog类(name,age,color)创建一个dog对象,
读取dog.properties 用相应的内容完成属性初始化,并输出
(3)将创建的Dog对象,序列化到文件到 e:\dog.dat文件
*/
String filePath = "src\\dog.properties";
Properties properties = new Properties();
properties.load(new FileReader(filePath));
String name = properties.get("name")+"";//把Object转成String
int age = Integer.parseInt(properties.get("age")+"");//把Object转成int
String color = properties.get("color")+"";//把Object转成String
Dog dog = new Dog(name, age, color);
System.out.println("=====Dog对象信息=====");
System.out.println(dog);
//将创建的Dog对象,序列化到文件dog.dat文件
String serFilePath = "e:\\dog.txt";//路径
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(serFilePath));
oos.writeObject(dog);
//关闭流
oos.close();
System.out.println("dog对象序列化完成");
}
//再编写一个方法,反序列化
@Test
public void m1() throws IOException, ClassNotFoundException {
String serFilePath = "e:\\dog.txt";//反序列化路径
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(serFilePath));
Dog dog = (Dog) ois.readObject();//向下转型
System.out.println("反序列后 dog");
System.out.println(dog);
ois.close();
}
}
class Dog implements Serializable {//要被序列化,必须实现 Serializable 接口
private String name;
private int age;
private String color;
public Dog(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
", color='" + color + '\'' +
'}';
}
}