文件流
文件在程序中是以流的形式来操作的
- 流:数据在数据源(文件)和程序(内存)之间经历的路径
- 输入流:数据从数据源到程序的路径
- 输出流:数据从程序到数据源的路径
常用文件操作
创建文件的三种方式
public class FileCreate {
public static void main(String[] args) {
method01();
method02();
method03();
}
//方式1
public static void method01(){
String filePath = "D:/news1.txt";
File file = new File(filePath);
try {
file.createNewFile();
System.out.println("文件创建成功");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//方式2 根据父目录文件+子路径构建
public static void method02(){
File parentFile = new File("D:/");//D:\\
String fileName = "news2.txt";
File file = new File(parentFile, fileName);
try {
file.createNewFile();
System.out.println("创建成功");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//方式3 根据父目录+子路径构建
public static void method03(){
String parentPath = "D:\\";
String fileName = "news3.txt";
File file = new File(parentPath, fileName);
try {
file.createNewFile();
System.out.println("创建成功");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
获取文件相关信息
public class FileInformation {
public static void main(String[] args) {
info();
}
//获取文件信息
public static void info(){
//先创建文件对象
File file = new File("D:\\news1.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());
System.out.println("文件是否存在"+file.exists());
System.out.println("是否是一个文件"+file.isFile());
System.out.println("是否是一个目录"+file.isDirectory());
}
}
目录操作
public static void main(String[] args) {
m2();
}
//判断D:\\news.txt 是否存在,如果存在就删除
public static void m1(){
String filePath = "D:\\news1.txt";
File file = new File(filePath);
if (file.exists()){
if (file.delete()) {
System.out.println(filePath+"删除成功");
} else {
System.out.println(filePath+"删除失败");
}
}else {
System.out.println("文件不存在");
}
}
//判断D:\\demo是否存在,存在就删除
//在java编程中,目录也被当做文件
public static void m2(){
String directoryPath = "D:\\demo";
File file = new File(directoryPath);
if (file.exists()){
if (file.delete()) {
System.out.println(directoryPath+"删除成功");
} else {
System.out.println(directoryPath+"删除失败");
}
}else {
System.out.println("目录不存在");
}
}
//判断D:\\demo\\a\\b是否存在,存在就提示存在信息,否则就创建
public static void m3(){
String directoryPath = "D:\\demo\\a\\b";
File file = new File(directoryPath);
if (file.exists()){
System.out.println("该目录存在");
}else {
if (file.mkdirs()){//创建多级目录
System.out.println("创建成功");
}else {
System.out.println("创建失败");
}
}
}
}
流的分类
- 按操作数据单位不同分为:字节流(8 bit),字符流(按字符)
- 按数据流的流向不同分为:输入流,输出流
- 按流的角色不同分为:节点流,处理流/包装流
(抽象基类) | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
(Java程序中,对于数据的输入/输出操作以“流(stream)”的方式进行)
字节流
字节输入流 FileInputStream
public class FileInputStream_ {
public static void main(String[] args) {
readFile02();
}
//read(int a)单个字节地读取,效率比较低
public static void readFile01(){
FileInputStream fileInputStream = null;
String filePath = "D:\\hello.txt";
int readData = 0;
try {
//创建 FileInputStream 对象用于读取文件
fileInputStream = new FileInputStream(filePath);
//如果返回-1,表示读取完毕
while ((readData = fileInputStream.read())!=-1){
System.out.print((char) readData);
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
fileInputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
//使用read(byte[] b) 读取文件提高效率
public static void readFile02(){
FileInputStream fileInputStream = null;
String filePath = "D:\\hello.txt";
byte[] buffer = new byte[8];//一次读取8个字节
int len = 0;
try {
fileInputStream = new FileInputStream(filePath);
//如果返回-1,表示读取完毕
//如果读取正常,返回实际读取的字节数
while ((len = fileInputStream.read(buffer))!=-1){
System.out.println(new String(buffer,0,len));
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
fileInputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
字节输出流 FileOutputStream
- 覆盖模式:FileOutputStream fileOutputStream = new FileOutputStream(File/String) 写入内容会覆盖原来的内容
- 追加模式:FileOutputStream fileOutputStream = new FileOutputStream(File/String,true) 写入内容会追加到原内容末尾
public class FileOutputStream01 {
public static void main(String[] args) {
writeFile();
}
//将数据写到文件中,如果文件不存在则创建该文件
public static void writeFile(){
String filePath = "D:\\a.txt";
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(filePath);
/*
写入一个字节
fileOutputStream.write('H');//char和int类型相互转换
*/
//写入字符串
String str = "hello, world!";
//str.getBytes()可以把字符串转换为字节数组
//fileOutputStream.write(str.getBytes());
fileOutputStream.write(str.getBytes(),1,5);
System.out.println(str.length());
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fileOutputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
文件拷贝
public class FileCopy {
public static void main(String[] args) {
//1.创建文件输入流,将文件读取到程序
//2.创建文件输出流,将读取到的数据写入指定文件
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
String srcFilePath = "D:\\hello.txt";
String destFilePath = "D:\\hello2.txt";
try {
fileInputStream = new FileInputStream(srcFilePath);
fileOutputStream = new FileOutputStream(destFilePath);
//定义一个字节数组提高读取效率
byte[] buffer = new byte[1024];
int len = 0;
while ((len=fileInputStream.read(buffer))!=-1){
fileOutputStream.write(buffer,0,len);
}
System.out.println("拷贝完毕");
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
if (fileInputStream!=null){
fileInputStream.close();
}
if (fileOutputStream!=null){
fileOutputStream.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
字符流
字符输入流 FileReader
public class FileReader_ {
public static void main(String[] args) {
method02();
}
//单个字符读取文件
public static void method01(){
String filePath = "D:\\code.txt";
FileReader fileReader = null;
int data = 0;
try {
//1.创建FileReader对象
fileReader = new FileReader(filePath);
//使用read循环读取,单个读取
while ((data=fileReader.read())!=-1){
System.out.print((char) data);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if (fileReader != null){
fileReader.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
//字符数组读取文件
public static void method02(){
String filePath = "D:\\code.txt";
FileReader fileReader = null;
int len = 0;
char[] buffer = new char[8];
try {
//1.创建FileReader对象
fileReader = new FileReader(filePath);
//返回的是实际读到的字符数,如果返回为-1说明文件读取完毕
while ((len=fileReader.read(buffer))!=-1){
System.out.print(new String(buffer,0,len));
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if (fileReader != null){
fileReader.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
字符输出流 FileWriter
-
覆盖模式:FileWriter fileWriter = new FileWriter(File/String) 相当于流的指针在首端
-
追加模式:FileWriter fileWriter = new FileWriter(File/String,true) 相当于流的指针在首端
-
注意:FileWriter使用后,必须要关闭(close)或者刷新(flush),否则写入不到指定文件
public class FileWriter_ {
public static void main(String[] args) {
String filePath = "D:\\note.txt";
FileWriter fileWriter = null;
char[] chars = {'a','b','c'};
try {
//创建FileWriter对象
fileWriter = new FileWriter(filePath);
//write(int)写入单个字符
//fileWriter.write('j');
//write(char[])写入指定数组
//fileWriter.write(chars);
//write(char[],off,len)写入数组的指定部分
//fileWriter.write("歪比歪比,歪比巴卜".toCharArray(),0,4);
//write(String)写入整个字符串
//fileWriter.write("你好你好");
//write(String,off,len)写入字符串指定部分
fileWriter.write("你好你好",0,3);
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
if (fileWriter!=null){
fileWriter.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
System.out.println("end");
}
}
节点流和处理流
-
基本介绍
- 节点流可以从一个特定的数据源读写数据,如FileReader、FileWriter
- 处理流(也叫包装流)是“连接”在已存在的流(节点流或处理流)之上,为程序提供更强大、更灵活的读写功能,如BufferedReader、BufferedWriter
-
节点流和处理流的区别和联系
-
节点流是底层流/低级流,直接跟数据源相接
-
处理流包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出
-
处理流对节点流进行包装,使用了修饰器设计模式,不会直接于数据源相连
-
-
处理流主要功能体现
-
性能提高:主要以增加缓冲的方式来提高输入输出的效率
-
操作便捷:处理流提供了一系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便
-
处理流设计模式演示
-
Reader_ 抽象父类
public abstract class Reader_ { public void readFile(){} public void readString(){} //使用抽象方法统一管理 //public abstract void read(); }
注意:父类中用抽象方法统一管理read()方法使效率更高,后面在调用时,利用对象动态绑定机制,绑定到对应的实现子类即可
-
FileReader_ 节点流
public class FileReader_ extends Reader_{ public void readFile(){ System.out.println("对文件进行读取。。。"); } }
-
StringReader_ 节点流
public class StringReader_ extends Reader_{ public void readString(){ System.out.println("对字符串进行读取。。。"); } }
-
BufferedReader_ 处理流
public class BufferedReader_ extends Reader_{ private Reader_ reader_; public BufferedReader_(Reader_ reader_) { this.reader_ = reader_; } //对原方法封装一层,这样才能使用,不然会跳到父类Reader_ public void readFile(){ reader_.readFile(); } public void readString(){ reader_.readString(); } //拓展功能 //让方法更灵活,多次读取文件、字符串 public void readFiles(int num){ for (int i = 0; i < num; i++) { reader_.readFile(); } } public void readStrings(int num){ for (int i = 0; i < num; i++) { reader_.readString(); } } }
-
Test_ 测试类
public class Test_ { public static void main(String[] args) { BufferedReader_ bufferedReader_ = new BufferedReader_(new FileReader_()); bufferedReader_.readFile(); } }
处理流
字符流 BufferedReader
public class BufferedReader_ {
public static void main(String[] args) throws IOException {
String filePath = "D:\\a.java";
//创建BufferedReader
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
String line;
while ((line = bufferedReader.readLine())!=null){//按行读取,当返回为null时,表示读取完毕
System.out.println(line);
}
//关闭资源
bufferedReader.close();
}
}
字符流 BufferedWriter
public class BufferedWriter_ {
public static void main(String[] args) throws IOException {
String filePath = "D:\\ok.txt";
//创建BufferedWriter
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath));//覆盖模式
//BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath,true)); 追加模式
bufferedWriter.write("hello,幸会幸会!");
bufferedWriter.newLine();//插入一个和系统相关的换行
bufferedWriter.write("hello2,幸会幸会!");
bufferedWriter.newLine();
bufferedWriter.close();
}
}
字符处理流拷贝
注意:BufferedReader和BufferedWriter是按字符操作,不要去操作二进制文件,可能造成文件损坏
public class BufferedCopy_ {
public static void main(String[] args) {
String srcFilePath = "D:\\a.java";
String destFilePath = "D:\\a2.java";
BufferedReader bufferedReader = null;
BufferedWriter bufferedWriter = null;
String line = null;
try {
bufferedReader = new BufferedReader(new FileReader(srcFilePath));
bufferedWriter = new BufferedWriter(new FileWriter(destFilePath));
while ((line= bufferedReader.readLine())!=null){
bufferedWriter.write(line);
bufferedWriter.newLine();
}
System.out.println("拷贝完毕");
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
//关闭资源
try {
if (bufferedReader!=null){
bufferedReader.close();
}
if (bufferedWriter!=null){
bufferedWriter.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
字节处理流拷贝
public class BufferedCopy_ {
public static void main(String[] args) {
String srcPath = "D:\\img.jpg";
String destPath = "D:\\img2.jpg";
BufferedInputStream bis = null;
BufferedOutputStream bos =null;
byte[] buffer = new byte[8];
int len = 0;
try {
bis = new BufferedInputStream(new FileInputStream(srcPath));
bos = new BufferedOutputStream(new FileOutputStream(destPath));
while ((len=bis.read(buffer))!=-1){
bos.write(buffer,0,len);
}
System.out.println("拷贝完毕");
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
if (bos != null){
bos.close();
}
if (bis!=null){
bis.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
对象流
- 序列化:保存数据时,保存数据的值和数据类型
- 反序列化:恢复数据时,恢复数据的值和数据类型
- 需要让某个对象支持序列化机制,则必须让其类是可序列化的,该类必须实现如下两个接口之一:
- Serializable 标记接口,没有方法
- Externalizable
- 注意:反序列化顺序要和序列化顺序一致
- 序列化的类中建议添加SerialVersionUID以提高兼容性
- 序列化对象时,默认将里面的所有属性都进行序列化,static和transient修饰的成员除外
- 序列化对象时,要求里面的属性也需要实现序列化接口
- 序列化具备可继承性
- 准备一个支持序列化的类
public class Dog implements Serializable {
private String name;
private int age;
private static String nation;
private transient String color;
public Dog(String name, int age, String nation,String color) {
this.name = name;
this.age = age;
this.nation = nation;
this.color = color;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
", nation=" + nation +
", 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 static String getNation() {
return nation;
}
public static void setNation(String nation) {
Dog.nation = nation;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
- 序列化 ObjectOutputStream
public class ObjectOutputStream_ {
public static void main(String[] args) throws IOException {
//序列化后,保存的文件格式是按照系统格式来保存
String filePath = "D:\\data.dat";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
//序列化数据到D:\data.dat
oos.writeInt(100);//int -> Integer(实现了serializable)
oos.writeBoolean(true);//boolean -> Boolean
oos.writeChar('c');//char -> Character
oos.writeDouble(9.5);//double -> Double
oos.writeUTF("歪比巴卜");//String
//保存对象
oos.writeObject(new Dog("旺财",2,"Japan","brown"));
oos.close();
System.out.println("保存完毕");
}
}
- 反序列化 ObjectInputStream
public class ObjectInputStream_ {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//指定反序列化文件
String filePath = "D:\\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信息:"+dog);//底层 Object -> Dog
//注意
//1.如果希望调用Dog的方法,需要向下转型
//2.需要将Dog类的定义放在可以引用的地方
Dog dog2 = (Dog)dog;
System.out.println(dog2.getName());
ois.close();
}
}
- 打印结果:
100
true
c
9.5
歪比巴卜
运行类型:class outputStream_.Dog
dog信息:Dog{name='旺财', age=2, nation=null, color='null'}
旺财
转换流
标准输入输出
类型 | 默认设备 | |
---|---|---|
System.in | InputStream | 键盘 |
System.out | PrintStream | 显示器 |
编码问题
public class CodeQuestion {
public static void main(String[] args) throws IOException {
//1. 创建字符输入流 BufferedReader 处理流
//2. 使用BufferedReader对象读取a.txt
//3. 默认情况下,读取文件按照utf-8编码
String filePath = "D:\\a.txt";
BufferedReader br = new BufferedReader(new FileReader(filePath));
String s = br.readLine();
System.out.println("读取到的内容:"+s);
br.close();
}
}
如果读取的文件编码格式不为utf-8则会出现乱码,这时就需要用转换流指定编码格式
InputStreamReader
//将字节流FileInputStream转成字符流InputStreamReader,指定编码gbk/utf-8
public class InputStreamReader_ {
public static void main(String[] args) throws IOException {
String filePath = "D:\\a.txt";
//1.把FileInputStream 转成 InputStreamReader,指定gbk编码
InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath),"gbk");
//2.把InputStreamReader传入BufferedReader
BufferedReader br = new BufferedReader(isr);
//BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath),"gbk"));
//3.读取
String s = br.readLine();
System.out.println("读取到的内容:"+s);
//4.关闭外层流
br.close();
}
}
OutputStreamWriter
//把字节流FileOutputStream转成字符流OutputStreamWriter,指定编码gbk/utf-8
public class OutputStreamWriter_ {
public static void main(String[] args) throws IOException {
String filePath = "D:\\nb.txt";
String charSet = "gbk";
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath), charSet);
osw.write("hi,你真厉害!");
osw.close();
System.out.println("按照"+charSet+"方式保存文件");
}
}
打印流
打印流只有输出流,没有输入流
字节打印流 PrintStream
public class PrintStream_ {
public static void main(String[] args) throws IOException {
PrintStream out = System.out;
//默认情况下PrintStream的输出位置是标准输出
out.print("hello,john");
//print底层使用write进行打印
out.write("你好你好".getBytes());
out.close();
//修改打印流输出的位置/设备
System.setOut(new PrintStream("D:f1.txt"));
System.out.println("hi,玛卡巴卡");
}
}
字符打印流 PrintWriter
public class PrintWriter_ {
public static void main(String[] args) throws IOException {
//PrintWriter printWriter = new PrintWriter(System.out);
PrintWriter printWriter = new PrintWriter(new FileWriter("D:\\f2.txt"));
printWriter.println("hi,玛卡巴卡");
printWriter.close();//不写这个就无法写入数据
}
}
Properties
基本介绍
-
专门用于读写配置文件的集合类
配置文件的格式:
键=值
键=值
-
注意:键值对不需要有空格,值不需要用引号括起来。默认类型是String
-
常用方法
- load:加载配置文件的键值对到properties对象
- list:将数据显示到指定设备
- getProperty(key):根据键值获取值
- setProperty(key,value):设置键值对的值,没有则创建再赋值
- store:将properties中的键值对存储到配置文件,在idea中,保存信息到配置文件
需求
-
目标文件 mysql.properties
ip=192.168.100.100 user=root pwd=123456
-
疑问:读取ip、user、pwd的值
传统方法
public class Properties01 {
public static void main(String[] args) throws IOException {
//读取mysql.properties文件并获取ip user pwd
BufferedReader br = new BufferedReader(new FileReader("src\\mysql.properties"));
String line = "";
while ((line = br.readLine())!=null){//循环读取
//System.out.println(line);
String[] split = line.split("=");
System.out.println(split[0]+"的值="+split[1]);
}
br.close();
}
}
properties 读取文件
public class Properties02 {
public static void main(String[] args) throws IOException {
//1.创建Properties类对象
Properties properties = new Properties();
//2.加载指定配置文件
properties.load(new FileReader("src\\mysql.properties"));
//3.把k-v显示到控制台
properties.list(System.out);
//4.根据key获取value
String user = properties.getProperty("user");
String pwd = properties.getProperty("pwd");
System.out.println("用户名:"+user);
System.out.println("密码:"+pwd);
}
}
properties 修改文件
//使用properties类来创建或修改配置文件
public class Properties03 {
public static void main(String[] args) throws IOException {
Properties properties = new Properties();
properties.setProperty("charser","utf-8");
properties.setProperty("user","汤姆");//中文用unicode码存入
properties.setProperty("pwd","abc111");
//将k-v从内存中存入配置文件
properties.store(new FileOutputStream("src\\mysql2.properties"),null);
}
}