IO流
IO流
文件
概念
一组有意义的信息集合,可以是文档、图片、程序等。在用户进行输入、输出时,以文件为基本单位。
文件流
Tips:输入流和输出流是站在内存的角度去看的,在使用中更多的是读取磁盘文件和写入磁盘文件。
- 输入流:从磁盘文件中读取,然后写入内存中,有read方法(输入流:读磁盘,入内存)
- 输出流:从内存中读取,向磁盘文件中写入,有write方法(输出流:读内存,入磁盘)
简记:输入流还是输出流,看内存上的操作,read方法还是write方法看磁盘上的操作,【写出,“读入”两个字】
常用的文件操作
创建文件
//new File(String pathname)
public void creatFile01() {
String filePath = "/Users/bijing/documents/hello.txt";
File file = new File(filePath);
try {
file.createNewFile();
System.out.println("文件创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}
//new File(File parent, String child)
public void createFile02() {
String father = "/Users/bijing/documents";
String child = "/hello.txt";
File file = new File(father, child);
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
获取文件的相关信息
public void info() {
File file = new File("/Users/bijing/documents/haha.txt");
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
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.isFile());
System.out.println("是不是一个目录:" + file.isDirectory());
}
目录的操作和文件删除
public void fileOption() {
String filePath = "/Users/bijing/documents/haha.txt";
File file = new File(filePath);
if (file.exists()) {
if (file.delete()) {
System.out.println("删除成功");
}
} else {
System.out.println("哈哈不存在");
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void directoryOption() {
String filePath = "/Users/bijing/documents/haha";
File file = new File(filePath);
if (file.exists()) {
if (file.delete()) {
System.out.println("删除成功");
}
} else {
System.out.println(file.getName() + "不存在");
file.mkdirs();//mkdirs()创建多级目录,mkdir()创建一级目录
if (file.exists()) {
System.out.println(file.getName() + "创建成功");
}
}
}
}
IO流原理及流的分类
IO流原理
流的分类
IO流体系图-常用的类
FileInputStream和FileOutputStream
FileInputStream实例
注意:
1. try中新建的对象,作用范围不能超过try
2. 记得用完后要close()
//单个字节的读取,效率较低
public void read1() {
String path = "/Users/bijing/documents/haha.txt";
int readData = 0;
FileInputStream fileInputStream = null;
try {
//创建FileInputStream对象,用于读取文件
fileInputStream = new FileInputStream(path);
//从该输入流读取一个字节的数据. 如果没有输入可用,此方法将阻止,如果返回-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),用字节数组去读,提高了读取的效率
public void read2() {
String path = "/Users/bijing/documents/haha.txt";
int readLen = 0;
byte[] bytes = new byte[8];//一次读取八个字节
FileInputStream fileInputStream = null;
try {
//创建FileInputStream对象,用于读取文件
fileInputStream = new FileInputStream(path);
// 从该输入流读取最多b.length字节的数据到字节数组. 此方法将阻塞,直到某些输入可用,
// 如果返回-1,表示文件读取完毕
// 如果读取正常,返回实际读取的字节数
while ((readLen = fileInputStream.read(bytes)) != -1) {
// 字节数组转为字符串
System.out.print(new String(bytes, 0, readLen));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭文件流,释放资源
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileOutputStream实例1
public void write1() {
String path = "/Users/bijing/documents/haha.txt";
FileOutputStream fileOutputStream = null;
String txt = "abcdefg";
//将字符串转成字节数组
byte[] b = txt.getBytes();
try {
//构造器中如果不加true就是覆盖,加了就是追加
fileOutputStream = new FileOutputStream(path, true);
//写入一个字节,char可以自动转的
fileOutputStream.write('H');
//写入字符串
fileOutputStream.write(b);
//写入从start到end字符串
fileOutputStream.write(b, 1, 5);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileOutputStream实例2
public void copy() {
String path1 = "/Users/bijing/documents/picture/003950-164338799031d6.jpeg";
// String path1 = "/Users/bijing/documents/haha.txt"; 拷贝文本
String path2 = "/Users/bijing/documents/girl.jpeg";//拷贝图片
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
byte[] b = new byte[1024];
int readLen = 0;
try {
fileInputStream = new FileInputStream(path1);
fileOutputStream = new FileOutputStream(path2);
while ((readLen = fileInputStream.read(b)) != -1) {
//如果是拷贝文本一定要使用这个方法,因为最后一次写入的长度不一定是1024个字节
fileOutputStream.write(b, 0, readLen);
//图片也可以用下面的方法
fileOutputStream.write(b);
}
} 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
注意:FileWriter使用后,必须关闭或者刷新,否则还在内存中并没有写入文件中
简记:输入流还是输出流,看内存上的操作,read方法还是write方法看磁盘上的操作
FileReader案例
public void read1() {
String path = "/Users/bijing/documents/hello.txt";
FileReader fileReader = null;
int len = 0;
char[] chars = new char[1024];
try {
fileReader = new FileReader(path);
while ((len = fileReader.read(chars)) != -1) {
System.out.print(new String(chars, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileReader != null) {
try {
fileReader.close();
} catch (IOException e) {
}
}
}
}
FileWriter案例
public void write() {
String path = "/Users/bijing/documents/note.txt";
FileWriter fileWriter = null;
String s = "风雨之后,定见彩虹";
try {
fileWriter = new FileWriter(path);
//加true就是追加,不加true就是覆盖
fileWriter = new FileWriter(path, true);
fileWriter.write(s);
// fileWriter.write('H');
// fileWriter.write("hello");
// fileWriter.write("hello", 0, s.length());
// fileWriter.write(new char[]{'1', 'a', '3'}, 0, s.length());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileWriter != null) {
try {
//一定要关闭或者刷新,否则还在内存中,没有写入到文件中
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
节点流和处理流
介绍
下图是节点流,数据源可以是一个文件,也可以是一个数组,管道。
下图是处理流也叫包装流,以BufferedReader为例,它有个属性Reader,所以构造器中可以传任意Reader子类(字节流类似)对其进行操作
节点流和处理流的区别和联系
模拟修饰器模式
Reader_.java
public abstract class Reader_ {
//把Reader_做成一个私有属性,它有子类FileReader_和StringReader_
private Reader_ in;
public void readFile() {
}
public void readString() {
}
}
Reader_.java的子类,FileReader_
public class FileReader_ extends Reader_ {
public void readFile() {
System.out.println("对文件进行读取...");
}
}
Reader_.java的子类,StringReader_
public class StringReader_ extends Reader_ {
public void readString() {
System.out.println("对字符串进行读取...");
}
}
包装流中的缓冲流BufferedReader_也要继承Reader_,在这个缓冲流中可以封装对节点流的一些列操作
public class BufferedReader_ extends Reader_ {
//这里的in可以根据构造器中传入的类型(Reader的子类),在后面对用相应的方法,同时还可以对节点流的方法进行一些额外的封装
private Reader_ in;
public BufferedReader_(Reader_ in) {
this.in = in;
}
public void readFiles(int num) {
for (int i = 0; i < num; i++) {
in.readFile();
}
}
public void readStrings(int num) {
for (int i = 0; i < num; i++) {
in.readString();
}
}
}
Test.java,构造器中传入了什么样的节点流就可以使用它的方法,同时也可以使用特有的,对节点流中方法进行封装过的方法
public class Test {
public static void main(String[] args) {
BufferedReader_ bufferedReader_ = new BufferedReader_(new FileReader_());
bufferedReader_.readFiles(10);
BufferedReader_ bufferedReader_1 = new BufferedReader_(new StringReader_());
bufferedReader_1.readStrings(10);
}
}
BufferedReader和BufferedWriter
注意:如果缓冲区没满时使用close方法不会自动的朝目标文件进行读或写,此时需要flush()方法
BufferedReader案例(按行读取)
public class BufferedReader_ {
public static void main(String[] args) throws IOException {
String path = "/Users/bijing/documents/hello.txt";
BufferedReader bufferedReader = new BufferedReader(new FileReader(path));
String line;//按行读取,效率高
//bufferedReader.readLine()是按行读取文件,当返回null时代表已经读取到文件的末尾
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
bufferedReader.close();
}
}
BufferedWriter案例
注意:一般都要加上 bufferedWriter.newLine()用来另起一行输入
public class BufferedWriter_ {
public static void main(String[] args) throws IOException {
String s = "韩顺平教育";
String path = "/Users/bijing/documents/note.txt";
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(path));
// BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(path),true); //追加
bufferedWriter.write("hello," + s);
bufferedWriter.newLine();//表示插入一个和系统相关的换行符
bufferedWriter.write("hello1," + s);
bufferedWriter.newLine();//表示插入一个和系统相关的换行符
bufferedWriter.write("hello2," + s);
bufferedWriter.newLine();//表示插入一个和系统相关的换行符
bufferedWriter.close();
}
}
文本拷贝案例
//注意:
//BufferedReader和BufferedWriter都是按照字符进行操作
//如果用来操作二进制文件可能会造成破坏(如音频,照片,视频)
public class BufferedCopy {
public static void main(String[] args) throws IOException {
String path1 = "/Users/bijing/documents/hello.txt";
String path2 = "/Users/bijing/documents/heihei.txt";
BufferedReader bufferedReader = new BufferedReader(new FileReader(path1));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(path2));
String line;
while ((line = bufferedReader.readLine()) != null) {
bufferedWriter.write(line);
bufferedWriter.newLine();
}
bufferedReader.close();
bufferedWriter.close();
}
}
BufferedInputStream和BufferedOutputStream
BufferedInputStream具有InputStream属性,所以构造器中可以传入InputStream的子类
…和上面的类似(但是它既可以处理字节流也可处理字符流)
对象处理流ObjectInputStream和ObjectOutputStream
ObjectOutputStream序列化案例
注意:序列化对象必须要实现Serializable接口或Externalizable接口
public class ObjectOutputStream_ {
public static void main(String[] args) {
String path = "/Users/bijing/documents/object.dat";
try {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(path));
//序列化数据到object.dat
objectOutputStream.writeInt(100);
objectOutputStream.writeBoolean(true);
objectOutputStream.writeUTF("放字符串不是用String,用UTF");
objectOutputStream.writeObject(new Dog("小明", 8));
objectOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Dog.java
public class Dog implements Serializable {
private String name;
private int age;
//serialVersionUID 序列化的版本号,可以提高兼容性
private static final long serialVersionUID = 1L;
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 Dog(String name, int age) {
this.name = name;
this.age = age;
}
}
ObjectInputStream反序列化案例
注意:反序列化的顺序必须和序列化的顺序一致
public class ObjectInputStream_ {
public static void main(String[] args) throws Exception, ClassCastException {
String path = "/Users/bijing/documents/object.dat";
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(path));
//这边反序列化(读),要求和序列化的顺序一致
System.out.println(objectInputStream.readInt());
System.out.println(objectInputStream.readBoolean());
System.out.println(objectInputStream.readUTF());
Object dog = objectInputStream.readObject();
System.out.println(dog);
System.out.println(((Dog) dog).getName());
objectInputStream.close();
}
}
对象处理流的注意事项(3,4,5)
标准输入输出流
public class InputAndOutput {
public static void main(String[] args) {
//System类的public final static InputStream in = null;
//System.in的编译类型 InputStream
//System.in的运行类型 BufferedInputStream
System.out.println(System.in.getClass());
//System.out public final static PrintStream out = null;
//编译类型:PrintStream
//运行类型:PrintStream
//标准输出,显示器
}
}
转换流InputStreamReader和OutStreamWriter
CodeQuestion.java
public class CodeQuestion {
public static void main(String[] args) throws IOException {
String path = "/Users/bijing/documents/hello3.txt";
BufferedReader bufferedReader = new BufferedReader(new FileReader(path));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
bufferedReader.close();
}
}
这个hello3.txt我们是用gbk编码保存的,这边直接用处理流形式的字符流去读取会出现乱码情况,由此引出InputStreamReader,它的构造器中传入字节流,指定编码方式,然后将它当做InputReader子类,传入BufferedInputReader中使用就可以避免乱码
InputStreamReader_.java
public class InputStreamReader_ {
public static void main(String[] args) throws IOException {
String path = "/Users/bijing/documents/hello3.txt";
//把FileInputStream转成了InputStreamReader,指定了编码gbk
InputStreamReader isr = new InputStreamReader(new FileInputStream(path), "gbk");
//把FileInputStream传给BufferedReader
BufferedReader bufferedReader = new BufferedReader(isr);
String s;
while ((s = bufferedReader.readLine()) != null) {
System.out.println(s);
}
}
}
案例
public class OutputStreamWriter_ {
public static void main(String[] args) throws IOException {
String path = "/Users/bijing/documents/hello3.txt";
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(path), "gbk");
outputStreamWriter.write("明天你好");
// 注释是使用了处理流,如果和上面同时使用,outputStreamWriter.write("明天你好");就不要了,否则也会写入,
// 同时outputStreamWriter.close();不要了,因为它关闭了,bufferedWriter.close();会报错
// BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
// bufferedWriter.write("明天会更好");
outputStreamWriter.close();
// bufferedWriter.close();
}
}
打印流PrintStream和PrintWriter(一个是打印字节一个是打印 字符)
字节打印流
public class PrintStream_ {
public static void main(String[] args) throws IOException {
//System.out的编译类型是PrintStream,默认的情况PrintScream输出数据的位置是标准输出,即显示器
PrintStream out = System.out;
out.print("你好China");
//print的底层就是write
out.write("明天你好".getBytes());
out.close();
// 可以修改打印流的位置
System.setOut(new PrintStream("/Users/bijing/documents/hello.txt"));
System.out.print("java好难学哈哈");
}
}
字符打印流
public class PrintWriter_ {
public static void main(String[] args) throws IOException {
//PrintWriter的构造器中可以指定输出的位置
// PrintWriter printWriter = new PrintWriter(System.out);
// PrintWriter printWriter = new PrintWriter(new FileWriter("/Users/bijing/documents/hello3.txt"));
// PrintWriter printWriter = new PrintWriter("/Users/bijing/documents/hello.txt");
// 也可以直接指定位置,指定编码进行输入
PrintWriter printWriter = new PrintWriter("/Users/bijing/documents/hello3.txt", "gbk");
printWriter.println("我是大聪明a");
printWriter.close();
}
}
Properties类
传统方法
public class Properties_ {
public static void main(String[] args) throws IOException {
// String path = "/Users/bijing/Documents/study/java/space/IO_scream/src/mysql.properties";
String path = "./src/mysql.properties";
BufferedReader bufferedReader = new BufferedReader(new FileReader(path));
String line;
while ((line = bufferedReader.readLine()) != null) {
String[] s = line.split("=");
System.out.println(s[0] + ":" + s[1]);
}
bufferedReader.close();
}
}
Properties类基本介绍
Properties类的常用方法
这边的设备可以是指定的流对象
案例:读取
public class Properties02 {
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.把key-value显示到控制台
properties.list(System.out);
//4.根据key获取对应的值
System.out.println(properties.get("user"));
}
}
案例:添加和修改
public class Properties03 {
public static void main(String[] args) throws IOException {
Properties p = new Properties();
//如果key没有,就是新建
p.setProperty("姓名:", "张三");
p.setProperty("年龄:", "40");
//如果key有就是修改
p.setProperty("姓名:", "李四");
//这个null是添加注释
p.store(new FileOutputStream("./src/mysql2.properties"), null);
}
}