Day13-IO流
IO流
文件
-
用来保存数据
-
文件流
-
流:数据在数据源(文件)和程序(内存)之间经历的路径
-
输入流:数据从数据源(文件)到程序(内存)的路径
-
输出流:数据从程序(内存)到数据源(文件)的路径
-
创建文件对象相关构造器和方法
new File(String pathname) //根据路径构建一个File对象
new File(File parent,String child) //根据父目录文件+子路径构建
new File(String parent,String child) //根据父目录+子路径构建
createNewFile 创建新文件
package com.lsq.study.IO流;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.IOException;
public class Demo01 {
public static void main(String[] args) {
}
public void createFile(){
//方式1
String filePath="/Users/liushaoqin/Desktop/test.txt";
File file = new File(filePath);
try {
file.createNewFile();
System.out.println("创建成功");
} catch (IOException e) {
throw new RuntimeException(e);
}
//方式2
File parentFile = new File("/Users/liushaoqin/Desktop");
String childFileName="test1.txt";
File file2 = new File(parentFile, childFileName);
try {
System.out.println("创建成功");
file2.createNewFile();
} catch (IOException e) {
throw new RuntimeException(e);
}
//方式3
String parentFilePath="/Users/liushaoqin/Desktop";
String childFileName1="test2.txt";
File file3 = new File(parentFilePath, childFileName1);
try {
file3.createNewFile();
System.out.println("创建成功");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
IO流原理及流的分类
-
按操作数据单位不同分为:字节流(8 bit)二进制文件,字符流(按字符)文本文件
-
按数据流的流向不同分为:输入流,输出流
-
按流的角色的不同分为:节点流,处理流/包装流
抽象基类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
1)java的IO流共涉及40多个类,实际上非常规则,都是从如上4个抽象类派生的
2)由这四个类派生出来的子类名称都是以其父类名作为子类名后缀
InputStream抽象类是所有类
InputStream常用的子类
-
FileInputStream:文件输入流
-
BufferedInputStream:缓冲字节输入流
-
ObjectInputStream:对象字节输入流
package com.lsq.study.IO流;
import org.junit.jupiter.api.Test;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Demo02 {
public static void main(String[] args) {
}
//FileInputStream 文件输入流用法演示
public void readFile() throws IOException {
String filePath = "/Users/liushaoqin/Desktop/test.txt";
FileInputStream fileInputStream = new FileInputStream(filePath);
int readData = 0;
while ((readData = fileInputStream.read()) != -1) {
System.out.print((char)readData);
}
fileInputStream.close();
}
public void readFile02() throws IOException {
String filePath = "/Users/liushaoqin/Desktop/test.txt";
FileInputStream fileInputStream = new FileInputStream(filePath);
byte[] buf=new byte[8];
int readCount = 0;
//从该输入流读取最多b.length字节的数据到字节数组,如果字节长度小于数组长度,则返回字节长度。
//如果返回-1,则说明到达文件末尾
while ((readCount=fileInputStream.read(buf))!=-1) {
System.out.print(new String(buf,0,readCount));
}
fileInputStream.close();
}
}
OutputStream抽象类是所有类
package com.lsq.study.IO流;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo03 {
public static void main(String[] args) {
}
//FileOutputStream类演示
public void writeFile() {
String filePath = "/Users/liushaoqin/Desktop/a.txt";
FileOutputStream fileOutputStream=null;
try {
//1.new FileOutputStream(filePath)创建方式,当写入内容时,会覆盖原来的内容
//2.new FileOutputStream(filePath,true)创建方式,当写入内容时,是追加到文件后面
fileOutputStream = new FileOutputStream(filePath,true);
String content="Hello,world";
//str.getBytes()可以把字符串-》字节数组
fileOutputStream.write(content.getBytes());
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
fileOutputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
练习
编程完成图片/音乐的拷贝
package com.lsq.study.IO流;
import org.junit.jupiter.api.Test;
import java.awt.*;
import java.io.*;
public class Demo04 {
public static void main(String[] args) {
}
//编程完成图片/音乐的拷贝
public void copyFile(){
String filePath="/Users/liushaoqin/Desktop/兔年快乐.jpg";
String filePath2="/Users/liushaoqin/Desktop/兔年快乐1.jpg";
FileInputStream fileInputStream=null;
FileOutputStream fileOutputStream=null;
try {
fileInputStream = new FileInputStream(filePath);
//这里构造器里不用true,不会覆盖是因为这里只创建了一个对象,不停的在文件里写信息
//会覆盖是因为多次打开文件,每次都创建了一个新的对象,不指定append就会覆盖
fileOutputStream = new FileOutputStream(filePath2);
byte[] buf=new byte[1024];
int read = 0;
while ((read=fileInputStream.read(buf))!=-1){
//读取到后就写入到文件,通过fileOutputStream即,一边读一边写
fileOutputStream.write(buf,0,read);
}
} 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相关方法
-
new FileReader(File/String)
-
read:每次读取单个字符,返回该字符,如果到文件末尾返回-1
-
read(char[]):批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1
-
new String(char[]):将char[]转换成String
-
new String(char[],off,len):将char[]的指定部分转换成String
-
-
FileWriter相关方法
-
new FileWriter(File/String):覆盖模式,相当于流的指针在首端
-
new FileWiriter(File/String,true):追加模式,相当于流的指针在尾端
-
write(int):写入单个字符
-
write(char[]):写入指定数组
-
write(char[],off,len):写入指定数组的指定部分
-
write(string):写入整个字符串
-
write(string, off,len):写入字符串的指定部分
-
String类:toCharArray,将String转换成char[]
-
FileWriter使用后,必须要关闭(close)或刷新(flush),否则写入不到指定的文件
-
-
节点流:可以从一个
-
处理流(包装流):是"连接"在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,如BufferedReader、BufferedWriter
package com.lsq.study.IO流;
import org.junit.jupiter.api.Test;
import java.io.*;
//使用BufferedReader读取文本文件,并显示在控制台
public class Demo06 {
public static void main(String[] args) {
}
public void readFile(){
String filePath="/Users/liushaoqin/Desktop/note.txt";
BufferedReader bufferedReader=null;
try {
bufferedReader = new BufferedReader(new FileReader(filePath));
//按行读取
String line;
//当返回null是,表示文件读取完毕
while ((line=bufferedReader.readLine())!=null){
System.out.println(new String(line));
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
//关闭流,这里注意,只需要关闭BufferedReader,因为底层会自动的去关闭节点流
bufferedReader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
package com.lsq.study.IO流;
import com.sun.org.apache.xerces.internal.util.EntityResolverWrapper;
import org.junit.jupiter.api.Test;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.security.cert.TrustAnchor;
////使用BufferedWriter将"hello,world"写入到文件中
public class Demo07 {
public static void main(String[] args) {
}
public void writeFile() throws IOException {
String filePath="/Users/liushaoqin/desktop/note.txt";
//new FileWriter(filePath,true)表示以追加的方式写入
//new FileWriter(filePath)表示以覆盖的方式写入
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath,true));
bufferedWriter.write("hello,world");
//插入一个和系统相关的换行符
bufferedWriter.newLine();
bufferedWriter.close();
}
}
package com.lsq.study.IO流;
import org.junit.jupiter.api.Test;
import java.io.*;
//综合使用BufferedReader和BufferedWriter完成文本文件拷贝
public class Demo08 {
public static void main(String[] args) {
}
public void fileCopy() throws IOException {
String filePath="/Users/liushaoqin/Desktop/note.txt";
String filePath1="/Users/liushaoqin/Desktop/note1.txt";
//BufferedReader和BufferedWriter是安装字符操作
//不要去操作二进制文件[声音、视频、doc、pdf...],可能造成文件损坏
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath1));
String line;
while((line=bufferedReader.readLine())!=null){
//说明:readLine读取一行内容,但是没有换行
bufferedWriter.write(line);
bufferedWriter.newLine();
}
if (bufferedReader!=null){
bufferedReader.close();
}
if (bufferedWriter!=null){
bufferedWriter.close();
}
}
}
-
序列化就是在保存数据时,保存数据的值和数据类型
-
反序列化就是在恢复数据时,恢复数据的值和数据类型
-
需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:
-
Serializable //这是一个标记接口
-
Externalizable //该接口有方法需要实现,因此我们一般实现上面的Serializable接口
-
-
ObjectInputStream提供
-
ObjectOutputStream提供
-
读取(反序列化)的顺序需要和你保存数据(序列化)的顺序一致,否则会出现异常
package com.lsq.study.IO流;
import org.junit.jupiter.api.Test;
import java.io.*;
//编程完成图片/音乐的拷贝(要求使用Buffered...流)
public class Demo09 {
public static void main(String[] args) {
}
public void copyFile() throws IOException {
String srcPath = "/Users/liushaoqin/Desktop/兔年快乐.jpg";
String destPath = "/Users/liushaoqin/Desktop/兔年快乐1.jpg";
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(srcPath));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(destPath));
byte[] bytes=new byte[1024];
int readLen;
while ((readLen=bufferedInputStream.read(bytes))!=-1){
bufferedOutputStream.write(bytes,0,readLen);
}
if (bufferedInputStream!=null){
bufferedInputStream.close();
}
if (bufferedOutputStream!=null){
bufferedOutputStream.close();
}
}
}
package com.lsq.study.IO流;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
//演示序列化用法,使用ObjectOutputStream序列化基本数据和一个Dog对象(name,age)
// 并保存到data.dat文件中
public class Demo10 {
public static void main(String[] args) throws IOException {
String filePath = "/Users/liushaoqin/Desktop/data.dat";
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(filePath));
objectOutputStream.writeInt(100);
objectOutputStream.writeBoolean(true);
objectOutputStream.writeChar('a');
objectOutputStream.writeUTF("刘文姬");
objectOutputStream.writeObject(new Dog("小绿",3));
objectOutputStream.close();
}
}
package com.lsq.study.IO流;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
//使用ObjectInputStream读取data.dat并反序列化恢复数据
public class Demo11 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
String filePath="/Users/liushaoqin/Desktop/data.dat";
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filePath));
//读取的时候必须按照序列化的顺序读取,否则会抛出异常
System.out.println(objectInputStream.readInt());
System.out.println(objectInputStream.readBoolean());
System.out.println(objectInputStream.readChar());
System.out.println(objectInputStream.readUTF());
Object object = objectInputStream.readObject();
System.out.println(object.getClass());
System.out.println("当前对象"+object);
objectInputStream.close();
}
}
package com.lsq.study.IO流;
import java.io.Serializable;
public class Dog implements Serializable {
private String name;
private int age;
//serialVersionUID序列化的版本号,可以提高兼容性
//例如,当添加新的属性时不会认为是一个新的Dog类而是在原版本上做升级
private static final long serialVersionUID =1L;
public Dog(String name, int age) {
this.name = name;
this.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 String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
注意事项
-
读写顺序要一致
-
要求序列化或反序列化对象,需要实现Serializable
-
序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性
-
序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员
-
序列化对象时,要求里面属性的类型也需要实现序列化接口
-
序列化具备可继承行,也就是说如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化
类型 | 默认设备 | |
---|---|---|
System.in 标准输入 | InputStream | 键盘 |
System.out 标准输出 | PrintStream | 显示器 |
字节流----》字符流
-
InputStreamReader:Reader的子类,可以将InputStream(字节流)包装成Reader(字符流)
-
OutputStreamWriter:Writer的子类,实现将OutputStream(字节流)包装成Writer(字符流)
-
当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换成字符流
-
可以在使用时指定编码格式(比如utf-8,gbk,gb2312,ISO8859-1等)
package com.lsq.study.IO流;
import java.io.*;
//演示使用InputStreamReader转换流解决中文乱码问题
//将字节流FileInputStream转化成字节流InputStreamReader,指定编码gbk/utf-8
public class Demo12 {
public static void main(String[] args) throws IOException {
String filePath = "/Users/liushaoqin/Desktop/note.txt";
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(filePath), "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String s = bufferedReader.readLine();
System.out.println(s);
}
}
package com.lsq.study.IO流;
import java.io.*;
//演示OutputStreamWriter使用
//把FileOutputStream字节流转换成字符流OutputStreamWriter
public class Demo13 {
public static void main(String[] args) throws IOException {
String filePath = "/Users/liushaoqin/Desktop/note.txt";
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(filePath), "utf-8");
//BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
outputStreamWriter.write("加油,希望总在前方!");
outputStreamWriter.close();
}
}
打印流只有输出流没有输入流
package com.lsq.study.IO流;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
//演示PrintStream(字节打印流)
public class Demo14 {
public static void main(String[] args) throws IOException {
PrintStream out = System.out;
//在默认情况下,PrintStream输出数据的位置是标准输出,即显示器
out.println("Hello,world");
out.write("刘文姬".getBytes());
out.close();
//可以修改打印流输出的位置/设备
System.setOut(new PrintStream("/Users/liushaoqin/Desktop/note.txt"));
System.out.println("加油,你一定可以找到一个新工作 ");
}
}
package com.lsq.study.IO流;
import java.io.*;
//演示PrintWriter使用方式
public class Demo15 {
public static void main(String[] args) throws IOException {
//PrintWriter printWriter = new PrintWriter(System.out);
PrintWriter printWriter = new PrintWriter(new FileWriter("/Users/liushaoqin/Desktop/note.txt"));
printWriter.println("Hello,刘文姬");
printWriter.close();
}
}
-
专门用于读取配置文件的集合类
-
配置文件的格式
-
键=值
-
键=值
-
-
注意:键值对不需要有空格,值不需要引号引起来,默认类型是String
-
Properties的常见方法
-
load:加载配置文件的键值对到Properties对象
-
list:将数据显示到指定设备/流对象
-
getProperty(key):根据键获取值
-
s etProperty(key,value):设置键值对到Properties对象
-
store:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件,如果含有中文,会存储为unicode编码
-
package com.lsq.study.IO流;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
public class Demo16 {
public static void main(String[] args) throws IOException {
//使用Properties类来读取mysql.properties文件
//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);
}
}
package com.lsq.study.IO流;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
//
public class Demo17 {
public static void main(String[] args) throws IOException {
//使用Properties类来创建配置文件,修改配置文件内容
//创建
//1.如果该文件没有key,就是创建
//2.如果该文件有key,就是修改
Properties properties = new Properties();
properties.setProperty("charset","utf-8");
properties.setProperty("user","文姬");
properties.setProperty("pwd","1234");
//将k-v存储文件中即可
properties.store(new FileOutputStream("src/mysql2.properties"),null);
}
}
例题1
public void h1() throws IOException {
String directoryPath="/Users/liushaoqin/Desktop/mytemp";
File file = new File(directoryPath);
if (!(file.exists())) {
if(file.mkdirs()){
System.out.println("创建"+directoryPath+"目录成功");
}else {
System.out.println("创建"+directoryPath+"目录失败");
}
}
String filePath=directoryPath+"/hello.txt";
file= new File(filePath);
if(!(file.exists())){
if(file.createNewFile()){
System.out.println("创建"+filePath+"文件成功");
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file));
bufferedWriter.write("Hello,world!");
}else {
System.out.println("创建" + filePath + "文件失败");
}
}else {
System.out.println(filePath+"文件已存在");
}
}
例题2
public void h2() throws IOException {
String filePath="/Users/liushaoqin/Desktop/note.txt";
FileInputStream fileInputStream = new FileInputStream(filePath);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream,"UTF-8"));
int i=0;
String s="";
while ((s=bufferedReader.readLine())!=null){
System.out.println(++i+s);
}
bufferedReader.close();
例题3
public void h3() throws IOException {
Properties properties = new Properties();
properties.load(new FileReader("src/dog.properties"));
properties.list(System.out);
//返回的是Object类型,在后面加一个空串,Object-》string
String name = properties.get("name")+"";
//Onject-->int
int age = Integer.parseInt(properties.get("age")+"");
String color = properties.get("color")+"";
Dog_ dog = new Dog_(name,age,color);
System.out.println(dog);
String filePath="src/dog.dat";
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(filePath));
objectOutputStream.writeObject(dog);
objectOutputStream.close();
}
//再编写一个方法,反序列化dog
public void inSer() throws IOException, ClassNotFoundException {
String filePath="src/dog.dat";
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filePath));
Dog_ dog = (Dog_) objectInputStream.readObject();
System.out.println("=============反序列化后dog=========");
System.out.println(dog);
objectInputStream.close();
}
class Dog_ implements 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;
}
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;
}
public String toString() {
return "Dog_{" +
"name='" + name + '\'' +
", age=" + age +
", color='" + color + '\'' +
'}';
}
}