13.Java的IO流

文件

概念

  • 文件:保存数据的地方。
  • 文件流:文件在程序中是以流的形式来操作的。
  • 流:数据在数据源(文件)和程序(内存)之间经历的路径。
    • 输入流:数据从数据源(文件)到程序(内存)的路径。
    • 输出流:数据从程序(内存)到数据源(文件)的路径。

文件和文件流

常用操作

文件类

构造方法

方法 说明
File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的File实例。
File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的File实例。
File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的File实例。
File(URI uri) 通过将给定的file: URI转换为抽象路径名来创建新的File实例。

获取文件信息

import java.io.File;//获取文件信息
public class FileDemo {public static void main(String[] args) {File file = new File("E:/java学习/textFile/1.txt");System.out.println("文件名字:" + file.getName()); //1.txtSystem.out.println("绝对路径:" + file.getAbsoluteFile()); //E:\java学习\textFile\1.txtSystem.out.println("文件父级目录:" + file.getParent()); //E:\java学习\textFileSystem.out.println("文件大小(字节数):" + file.length()); //9System.out.println("文件是否存在:" + file.exists()); //trueSystem.out.println("文件是否是一个文件:" + file.isFile()); //trueSystem.out.println("文件是否是一个目录:" + file.isDirectory()); //false}
}

查看文件的编码方式:

查看文件编码方式

不同编码方式中英文所占的字节数:

编码方式 英文 中文
GB2312 1 2
GBK 1 2
GB18030 1 2
ISO-8859-1 1 1
UTF-8 1 3
UTF-16 4 4

目录操作

  • mkdir:创建一级目录
  • mkdirs:创建多级目录
  • delete:删除文件或空目录
import java.io.File;//文件目录操作
public class FileDemo {public static void main(String[] args) {//判断文件是否存在,存在就删除,否则提示不存在String filePath = "E:/java学习/textFile/1.txt";File file = new File(filePath);if (file.exists()) {if (file.delete()) {System.out.println("文件删除成功!");} else {System.out.println("文件删除失败!");}} else {System.out.println("该文件不存在!");}//判断目录是否存在,存在就删除,否则提示不存在String filePath1 = "E:/java学习/textFile/folder1";File file1 = new File(filePath1);if (file1.exists()) {if (file1.delete()) {System.out.println("目录删除成功!");} else {System.out.println("目录删除失败!");}} else {System.out.println("该目录不存在!");}//判断多级目录是否存在,否则创建多级目录String filePath2 = "E:/java学习/textFile/folder1/folder1.1/folder1.1.1";File file2 = new File(filePath2);if (file2.exists()) {System.out.println("该多级目录存在!");} else {if (file2.mkdirs()) {System.out.println("创建多级目录成功!");} else {System.out.println("创建多级目录失败!");}}}
}

IO流原理及流的分类

IO流原理

  1. I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理数据传输。如读/写文件,网络通讯等。
  2. Java程序中,对于数据的输入/输出操作以“流(stream)”的方式进行。
  3. java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过方法输入或输出数据。
  4. 输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
  5. 输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中。

IO流原理

流的分类

  • 按操作数据单位不同分为:字节流(8 bit))适合操作二进制文件(声音,word),字符流(按字符) 文本文件,其中不同文件编码类型字符所占字节个数不同。
  • 按数据流的流向不同分为:输入流,输出流。
  • 按流的角色的不同分为:节点流,处理流/包装流。
(抽象基类) 字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer

注意:

  1. Java的I0流共涉及40多个类,实际上非常规则,都是从如上4个抽象基类派生的。
  2. 由这四个类派生出来的子类名称都是以其父类名作为子类名后缀。

常用的类

JavaIO流体系图

JavaIO流体系图

字节流

  • InputStream抽象类是所有类字节输入流的超类。
  • 常用子类
    • FileInputStream 文件输入流
    • BufferedInputStream 缓冲字节输入流
    • ObjectInputStream 对象字节输入流

字节输入流类

FileInputStream

常用方法

FileInputStream常用方法

代码示例:read()方法

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;//FileInputStream read()方法
public class FileInputStreamDemo {public static void main(String[] args) {//read()方法 一次从输入流中读取一个字节的数据 单字节读取File file = new File("E:/java学习/textFile/1.txt");FileInputStream fileInputStream = null;try {//创建FileInputStream对象fileInputStream = new FileInputStream(file);//read:从该输入流读取一个字节的数据。 如果没有输入可用,此方法将阻止。//数据的下一个字节,如果达到文件的末尾,返回-1。读一个字节,如果中文,有可能不止一个字节,会乱码。int read = -1;while ((read = fileInputStream.read()) != -1) {System.out.println((char) read); //转成char显示}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {//关闭文件流,释放资源try {fileInputStream.close();} catch (IOException e) {e.printStackTrace();}}}
}

代码示例:read(byte[] b)方法

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;//FileInputStream read(byte[] b)方法
public class FileInputStreamDemo {public static void main(String[] args) {//读文件String filePath = "E:/java学习/textFile/1.txt";FileInputStream fileInputStream = null;try {//创建FileInputStream对象fileInputStream = new FileInputStream(filePath);//read(byte[] b):从该输入流读取最多b.length字节的数据到字节数组。此方法将阻塞,直到某些输入可用。//返回值: 读入缓冲区的总字节数,如果没有更多的数据,因为文件的结尾已经到达,返回-1 。//乱码可能:缓冲区边界的一个中文字符拆成了多个字节//字节数组byte[] buffer = new byte[8]; //一次读8个字节int readLen = 0; //一次读取的字节长度while ((readLen = fileInputStream.read(buffer)) != -1) {System.out.println(readLen);System.out.println(new String(buffer, 0, readLen)); //显示}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {//关闭文件流,释放资源try {fileInputStream.close();} catch (IOException e) {e.printStackTrace();}}}
}

FileOutputStream

字节输出流类

常用方法

FileOutputStream常用方法

代码示例

import java.io.*;/*** 演示使用FileOutputStream将数据写到文件中,* 如果该文件不存在,则创建该文件*/
public class FileOutputStreamDemo {public static void main(String[] args) {File file = new File("E:/java学习/textFile/1.txt");FileOutputStream fileOutputStream = null;try {//创建FileOutputStream 对象//new FileOutputStream(file); 覆盖写//new FileOutputStream(file,true); 构造器后面的一个参数append设置为true,不覆盖原来的数据,追加写fileOutputStream = new FileOutputStream(file, true);//写入一个字节fileOutputStream.write('a'); //char自动转换int//写入字符串String str = "QWER";//str.getBytes()可以把字符串转换为字节数组fileOutputStream.write(str.getBytes());//write(byte[] b, int off, int len)//将len字节从位于偏移量off的指定字节数组写入此文件输出流fileOutputStream.write(str.getBytes(), 1, str.length() - 1);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {//关闭文件流,释放资源try {fileOutputStream.close();} catch (IOException e) {e.printStackTrace();}}}
}

作业

完成英语文件的拷贝

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;//完成英语文件的拷贝
public class FileDemo {public static void main(String[] args) {String inputPath = "E:/java学习/textFile/1.txt";FileInputStream fileInputStream = null;String outputPath = "E:/java学习/textFile/2.txt";FileOutputStream fileOutputStream = null;try {int readLen = 0;byte[] buffer = new byte[256];fileInputStream = new FileInputStream(inputPath);fileOutputStream = new FileOutputStream(outputPath);while ((readLen = fileInputStream.read(buffer)) != -1) {fileOutputStream.write(buffer, 0, readLen);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {//关闭文件流,释放资源try {if (fileInputStream != null) {fileInputStream.close();}if (fileOutputStream != null) {fileOutputStream.close();}} catch (IOException e) {e.printStackTrace();}}}
}

字符流

FileReader和FileWriter是字符流,即按照字符来操作io。

FileReader

下方为FileReader的继承关系类图,继承InputStreamReader。

FileReader的继承关系类图

相关方法

方法 说明
new FileReader(File/String) 构造方法
read() 每次读取单个字符(一个汉字算一个字符),返回该字符,如果到文件末尾返回-1
read(char[]) 批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1

字符数组转换为字符串处理的相关API:

new String(char[]) : 将char[]转换成String

new String(char[], off, len):将char[]的指定部分转换成String

代码示例:使用read()读取文件

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;//FileReader read()方法
public class FileReaderDemo {public static void main(String[] args) {//read()方法 一次从输入流中读取一个字符的数据 单字符读取String filePath = "E:/java学习/textFile/1.txt";FileReader fileReader = null;try {//创建FileReader对象fileReader = new FileReader(filePath);//read() 每次读取单个字符(一个汉字算一个字符),返回该字符,如果到文件末尾返回-1。int read = 0;while ((read = fileReader.read()) != -1) {System.out.print((char) read);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {if (fileReader != null) {fileReader.close();}} catch (IOException e) {e.printStackTrace();}}}
}

代码示例:使用read(char [])读取

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;//FileReader read(char [])方法
public class FileReaderDemo {public static void main(String[] args) {String filePath = "E:/java学习/textFile/1.txt";FileReader fileReader = null;try {//创建FileReader对象fileReader = new FileReader(filePath);//read(char []) 批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1。int readLen = 0;char[] buffer = new char[256];while ((readLen = fileReader.read(buffer)) != -1) {System.out.print(new String(buffer, 0, readLen));}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {if (fileReader != null) {fileReader.close();}} catch (IOException e) {e.printStackTrace();}}}
}

FileWriter

下方为FileWriter的继承关系类图,继承OutputStreamWriter。

FileWriter的继承关系类图

常用方法

方法 说明
new FileWriter(File/String) 构造方法,覆盖模式,相当于流的指针在首端
new FileWriter(Fiie/String , true) 构造方法,追加模式,相当于流的指针在尾端
write(int) 写入单个字符
write(char[]) 写入指定数组
write(char[],off,len) 写入指定数组的指定部分
write (string) 写入整个字符串
write(string,off, len) 写入字符串的指定部分

字符串转换为字符数组处理的相关API:

String类的toCharArray:将String转换为char[]

⭐️注意:
FileWriter使用后,必须要关闭(close)或刷新(flush),否则写入不到指定的文件!

代码示例

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;//FileWriter
public class FileWriterDemo {public static void main(String[] args) {String filePath = "E:/java学习/textFile/1.txt";FileWriter fileWriter = null;try {//创建FileWriter 对象//new FileWriter(file); 覆盖写//new FileWriter(file,true); 构造器后面的一个参数append设置为true,不覆盖原来的数据,追加写fileWriter = new FileWriter(filePath, true);//1.write() 写入单个字符fileWriter.write("H");//2.write(char []) 写入指定数组char[] chars = {'J', '林', '1'};fileWriter.write(chars);//3.write(char [], off, len) 写入指定数组的指定部分fileWriter.write("林黛玉".toCharArray(), 0, 2);//4.write(string) 写入整个字符串fileWriter.write("孙悟空");//5.write(string, off, len) 写入字符串的指定部分fileWriter.write("刘玄德", 0, 2);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {//对于FileWriter,一定要关闭流,只有在close或者flush之后才能真正地把数据写入到文件中if (fileWriter != null) {fileWriter.close(); //等价于flush()+关闭流//fileWriter.flush();/*两个方法源码最终调用了OutputStream的writeBytes方法private void writeBytes() throws IOException {bb.flip();int lim = bb.limit();int pos = bb.position();assert (pos <= lim);int rem = (pos <= lim ? lim - pos : 0);if (rem > 0) {if (ch != null) {if (ch.write(bb) != rem)assert false : rem;} else {out.write(bb.array(), bb.arrayOffset() + pos, rem);}}bb.clear();}*/}} catch (IOException e) {e.printStackTrace();}}}
}

节点流和处理流

基本介绍

  • 节点流可以从一个特定的数据源读写数据,如FileReader、 FileWriter。

    节点流

  • 处理流(也叫包装流)是“连接”在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,也更加灵活,如BufferedReader、BufferedWriter。

    处理流

  • 节点流和处理流一览图

    节点流和处理流

辅助理解处理流(包装流):以BufferedReader为例

BufferedReader类中,有属性Reader,即可以封装一个节点流,该节点流可以是任意的,只要是Reader子类。(装饰者模式)

BufferedReader

区别和联系

  1. 节点流是底层流/低级流,直接跟数据源相接。
  2. 处理流(包装流)包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。
  3. 处理流(包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连[模拟修饰器设计模式]。

模拟代码(模拟修饰器设计模式)

//模拟修饰器设计模式
public class DecoratorDemo {public static void main(String[] args) {BufferedReader_ bufferedReader_ = new BufferedReader_(new FileReader_());bufferedReader_.readFile();bufferedReader_.readFiles(2);//通过bufferReader_多次读取字符串BufferedReader_ bufferedReader_1 = new BufferedReader_(new StringReader_());bufferedReader_1.readString();bufferedReader_1.readStrings(2);/*输出结果:对文件进行读取...对文件进行读取...对文件进行读取...读取字符串...读取字符串...读取字符串...*/}
}abstract class Reader_ {public void readFile() {}public void readString() {}//也可以将readFile和readString写成一个抽象方法,利用动态绑定机制
}//模拟节点流
class FileReader_ extends Reader_ {public void readFile() {System.out.println("对文件进行读取...");}
}//模拟字符流
class StringReader_ extends Reader_ {public void readString() {System.out.println("读取字符串...");}
}//模拟处理流(包装流)
class BufferedReader_ extends Reader_ {private Reader_ reader_;public BufferedReader_(Reader_ reader_) {this.reader_ = reader_;}public void readFile() { //封装一层reader_.readFile();}public void readString() { //封装一层reader_.readString();}//让方法更加灵活,多次读取文件,或者加缓冲char[]...public void readFiles(int num) {for (int i = 0; i < num; i++) {reader_.readFile();}}//扩展readString,批量处理字符串数据public void readStrings(int num) {for (int i = 0; i < num; i++) {reader_.readString();}}
}

根据示例代码也不难理解处理流(包装流)的两个主要方面的功能:

  • 性能的提高:主要以增加缓冲的方式来提高输入输出的效率。
  • 操作的便捷:处理流(包装流)可能提供了一系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便。

处理流讲解

  • BufferedReader和BufferedWriter属于字符流,是按照字符来读取数据的。
  • BufferedInputStream和BufferedInputStream是字节流,是按照字节来读取数据的。
  • 关闭处理流时,只需要关闭外层流即可,关闭处理流包含关闭节点流。

处理流:BufferedReader和BufferedWriter

代码示例一:读取文本文件

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;//BufferedReader 读取文本文件
public class BufferedReaderDemo {public static void main(String[] args) {String filePath = "E:/java学习/textFile/1.txt";BufferedReader bufferedReader = null;try {//创建BufferedReader对象bufferedReader = new BufferedReader(new FileReader(filePath));//读取/*说明:1.bufferedReader.readLine(); //按行读取2.当返回null时,表示文件读取完毕。*/String line = null;while ((line = bufferedReader.readLine()) != null) {System.out.print(line);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {if (bufferedReader != null) {//关闭流 只需要关闭处理流(包装流),底层自动关闭节点流bufferedReader.close();/*源码:private Reader in;public void close() throws IOException {synchronized (lock) {if (in == null)return;try {in.close();} finally {in = null;cb = null;}}}*/}} catch (IOException e) {e.printStackTrace();}}}
}

代码示例二:写文本文件

import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;//BufferedWriter 写文本文件
public class BufferedWriterDemo01 {public static void main(String[] args) {String filePath = "E:/java学习/textFile/1.txt";BufferedWriter bufferedWriter = null;try {//创建BufferedWriter对象//说明 new FileWriter(filePath,true)  追加写//说明 new FileWriter(filePath)  覆盖写bufferedWriter = new BufferedWriter(new FileWriter(filePath, true));bufferedWriter.write("Hello World1");bufferedWriter.newLine(); //插入一个和系统相关的换行bufferedWriter.write("Hello World2");bufferedWriter.write("Hello World3");} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {if (bufferedWriter != null) {//关闭外层流会自动关闭内部流bufferedWriter.close();}} catch (IOException e){e.printStackTrace();}}}
}

代码示例三:复制文本文件

import java.io.*;//BufferedReader和BufferedWriter 复制文本文件
public class BufferedDemo {public static void main(String[] args) {//BufferedReader和BufferedWriter是按照字符操作的//不要去操作二进制文件,可能造成文件损坏String srcFilePath = "E:/java学习/textFile/1.txt";String destFilePath = "E:/java学习/textFile/2.txt";BufferedReader bufferedReader = null;BufferedWriter bufferedWriter = null;try {bufferedReader = new BufferedReader(new FileReader(srcFilePath));bufferedWriter = new BufferedWriter(new FileWriter(destFilePath));String line = null;while ((line = bufferedReader.readLine()) != null) {bufferedWriter.write(line);bufferedWriter.newLine();//bufferedWriter.write(line + "\n"); //等同于上边两行代码}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {if (bufferedReader != null) {//关闭外层流会自动关闭内部流bufferedReader.close();}if (bufferedWriter != null) {//关闭外层流会自动关闭内部流bufferedWriter.close();}} catch (IOException e){e.printStackTrace();}}}
}

处理流:BufferedInputStream和BufferedOutputStream

  • BufferedlnputStream是字节流,在创建BufferedlnputStream时,会创建一个内部缓冲区数组。

    BufferedInputStream

  • BufferedOutputStream是字节流,实现缓冲的输出流,可以将多个字节写入底层输出流中,而不必对每次字节写入调用底层系统。

    BufferedOutputStream

代码示例:完成二进制文件的拷贝

import java.io.*;//BufferedInputStream和BufferedOutputStream 完成二进制文件的拷贝
public class BufferedDemo02 {public static void main(String[] args) {String srcFilePath = "E:/java学习/textFile/1.wav";String destFilePath = "E:/java学习/textFile/2.wav";BufferedInputStream bufferedInputStream = null;BufferedOutputStream bufferedOutputStream = null;byte[] buffer = new byte[1024];int len = 0;try {bufferedInputStream = new BufferedInputStream(new FileInputStream(srcFilePath));bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(destFilePath));while ((len = bufferedInputStream.read(buffer)) != -1) {bufferedOutputStream.write(buffer, 0, len);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {if (bufferedInputStream != null) {//关闭外层流会自动关闭内部流bufferedInputStream.close();}if (bufferedOutputStream != null) {//关闭外层流会自动关闭内部流bufferedOutputStream.close();}} catch (IOException e){e.printStackTrace();}}}
}

对象处理流:ObjectInputStream和ObjectOutputStream

看一个需求:(保存数据的值和相应的数据类型)

  1. 将int num = 100这个int数据保存到文件中,注意不是100数字,而是int 100,并且,能够从文件中直接恢复int 100。
  2. 将Dog dog = new Dog(“小黄”,3)这个dog对象保存到文件中,并且能够从文件中恢复。
  3. 上面的要求,就是能够将基本数据类型或者对象进行序列化和反序列化操作。

序列化和反序列化

  1. 序列化就是在保存数据时,保存数据的值数据类型

  2. 反序列化就是在恢复数据时,恢复数据的值数据类型

  3. 需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:

    Serializable //这是一个标记接口,没有方法

    Externalizable //该接口有方法需要实现,一般使用上面的方法

基本介绍

  1. 功能:提供了对基本类型或对象类型的序列化和反序列化的方法。
  2. ObjectOutputStream提供序列化功能。
  3. ObjectlnputStream提供反序列化功能。

ObjectOutputStream

ObjectOutputStream

代码示例一

题目描述:使用ObjectOutputStream序列化基本数据类型和一个Dog对象(name, age),并保存到data.dat文件中。

import java.io.*;//ObjectOutputStream 序列化
public class ObjectOutputStreamDemo {public static void main(String[] args) {//题目描述:使用ObjectOutputStream序列化基本数据类型和一个Dog对象(name, age),并保存到data.dat文件中。//序列化后,保存的文件的格式,不是纯文本,而是按照它的格式来保存String filePath = "E:/java学习/textFile/data.dat";ObjectOutputStream objectOutputStream = null;try {objectOutputStream = new ObjectOutputStream(new FileOutputStream(filePath));//序列化数据到data.dat文件中objectOutputStream.writeInt(100); //自动装箱:int->Integer(实现了Serializable)objectOutputStream.writeBoolean(true); //自动装箱:boolean->Boolean(实现了Serializable)objectOutputStream.writeChar('a'); //charobjectOutputStream.writeDouble(3.14); //doubleobjectOutputStream.writeFloat(3.14f); //floatobjectOutputStream.writeUTF("Hello,World"); //String//保存一个dog类//如果需要实现序列化某个类的对象,SerializableobjectOutputStream.writeObject(new Dog("旺财", 3));System.out.println("序列化完成");} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {if (objectOutputStream != null) {//关闭外层流会自动关闭内部流objectOutputStream.close();}} catch (IOException e){e.printStackTrace();}}}
}class Dog implements Serializable {private static final long serialVersionUID = 1L;private String name;private int age;public Dog(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}@Overridepublic String toString() {return "Dog{" +"name='" + name + '\'' +", age=" + age +'}';}
}

代码示例二

题目描述:使用ObjectInputStream读取data.dat文件并反序列化恢复数据。

import java.io.*;//ObjectInputStream 反序列化
public class ObjectInputStreamDemo {public static void main(String[] args) {//题目描述:使用ObjectInputStream读取data.dat文件并反序列化恢复数据。//指定反序列化文件String filePath = "E:/java学习/textFile/data.dat";ObjectInputStream objectInputStream = null;try {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.readDouble());System.out.println(objectInputStream.readFloat());System.out.println(objectInputStream.readUTF());//dog的编译类型是Object,运行类型是DogObject dog = objectInputStream.readObject();System.out.println(dog.getClass()); //运行类型会自动转换,底层Object->DogSystem.out.println(dog);//访问Dog类的方法//1.向下转型//2.Dog类放在可以引用的地方,且与序列化的位置、定义都要一致Dog dog1 = (Dog) dog;System.out.println(dog1.getName());//注意:如果在序列化后,类的定义被修改了,例如增加了方法,会导致反序列化失败,可以添加SerialVersionUID解决这个问题//注意:在序列化时,包名信息已经固定,所以不能反序列化为不同包的Dog对象System.out.println("反序列化完成");} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} finally {try {if (objectInputStream != null) {//关闭外层流会自动关闭内部流objectInputStream.close();}} catch (IOException e){e.printStackTrace();}}}
}

注意事项和细节说明

  1. 读写顺序要一致。
  2. 要求实现序列化或反序列化的对象,需要实现Serializable接口。
  3. 序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性。
  4. 序列化对象时,默认将里面所有属性都进行序列化,除了static或transient修饰的成员。
  5. 序列化对象时,要求里面属性的类型也需要实现序列化接口。
  6. 序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化。

输入流和输出流

标准输入输出流

类型(编译类型) 默认设备
System.in 标准输入 lnputStream 键盘
System.out 标准输出 PrintStream 显示器

代码示例

import java.util.Scanner;//标准输入输出流
public class InOutDemo {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()); //class java.io.BufferedInputStream//System类中::public final static PrintStream out = null;//System.out 编译类型 PrintStream//System.out 运行类型 PrintStream//标准输出 显示器System.out.println(System.out.getClass()); //class java.io.PrintStreamSystem.out.println("Hello World"); //使用out对象将数据输出到显示器上Scanner scanner = new Scanner(System.in); //使用标准输入 键盘接收数据System.out.println("输入内容");String next = scanner.next();System.out.println("next=" + next);scanner.close();}
}

转换流(InputStreamReader和OutputStreamWriter)

问题引入

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;public class BufferedReaderDemo {public static void main(String[] args) {//读取txt文件//1.创建字符输入流 BufferedReader[处理流]//2.使用BufferedReader对象读取1.txt//3.默认情况下,读取文件是按照utf-8编码的。若文件不是utf-8则读取文件可能会出现文件乱码问题。//介绍一下ANSI国标码,ANSI并不是某一种特定的字符编码,它指的是在不同国家和地区基于ASCII扩展的编码方式。//和操作系统和区域设置有关,美国的系统中ANSI编码其实是ASCII编码(ASCII编码不能表示汉字,所以汉字为乱码),而中国的系统中(“汉字”正常显示)ANSI编码其实是GBK编码。String filePath = "E:/java学习/textFile/1.txt";BufferedReader bufferedReader = null;try {bufferedReader = new BufferedReader(new FileReader(filePath));String line = bufferedReader.readLine();System.out.println("读取到的内容:" + line); //文本文件为ANSI编码,而使用utf-8编码读取文件,中文乱码} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {if (bufferedReader != null) {bufferedReader.close();}} catch (IOException e) {e.printStackTrace();}}}
}

说明

  • InputStreamReader:Reader的子类,可以将InputStream(字节流)包装(转换)成Reader(字符流)。
  • OutputStreamWriter:Writer的子类,实现将OutputStream(字节流)包装成Writer(字符流)。
  • 当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换成字符流。
  • 可以在使用时指定编码格式(比如utf-8,gbk,gb2312,ISO8859-1等)。

类图

InputStreamReader

代码示例一

使用InputStreamReader转换流解决中文乱码问题,将字节流FileInputStream 包装成(转换成)字符流InputStreamReader,对文件进行读取(按照utf-8/gbk格式),进而再包装成BufferedReader。

import java.io.*;//InputStreamReader
public class InputStreamReaderDemo {public static void main(String[] args) {String filePath = "E:/java学习/textFile/1.txt";//1. 把FileInputStream转成InputStreamReader//2.指定编码:gbk//InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(filePath), "gbk");//3.把InputStreamReader传入BufferedReader//BufferedReader bufferedReader = new BufferedReader(inputStreamReader);BufferedReader bufferedReader = null;try {//把2,3合并到一起bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath),"gbk"));//4.读取String line = bufferedReader.readLine();System.out.println("读取到的内容:" + line); //文本文件为ANSI编码,而使用utf-8编码读取文件,中文乱码} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {if (bufferedReader != null) {//5.关闭外层流bufferedReader.close();}} catch (IOException e) {e.printStackTrace();}}}
}

代码示例二

编程将字节流FileOutputStream包装成(转换成)字符流OutputStreamWriter,对文件进行写入(按照gbk格式,可以指定其他,比如:utf-8)。

import java.io.*;//OutputStreamWriter
public class OutputStreamWriterDemo {public static void main(String[] args) {String filePath = "E:/java学习/textFile/1.txt";OutputStreamWriter outputStreamWriter = null;try {outputStreamWriter = new OutputStreamWriter(new FileOutputStream(filePath, true), "gbk");outputStreamWriter.write("Bye");} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {if (outputStreamWriter != null) {//关闭外层流outputStreamWriter.close();}} catch (IOException e) {e.printStackTrace();}}}
}

打印流(PrintStream和PrintWriter)

  • 打印流只有输出流,没有输入流。

类图

PrintStream

PrintWriter

代码示例一

import java.io.IOException;
import java.io.PrintStream;//PrintStream
public class PrintStreamDemo {public static void main(String[] args) {PrintStream out = System.out;//在默认情况下,PrintStream输出数据的位置是 标准输出,即显示器/*public void print(String s) {if (s == null) {s = "null";}write(s);}*/try {out.print("Hello World");//因为print底层使用的是write,所以我们可以直接调用write进行打印/输出out.write("Hello World".getBytes());//我们可以修改打印流的输出位置/设备/*默认打印/输出的位置是显示器,那么也可以修改输出的位置比如:修改输出位置改到E:/java学习/textFile/1.txtpublic static void setOut(PrintStream out) {checkIO();setOut0(out); //native方法, 修改了out位置}*/System.setOut(new PrintStream("E:/java学习/textFile/1.txt"));System.out.println("Kobe");} catch (IOException e) {e.printStackTrace();} finally {if (out != null) {out.close();}}}
}

代码示例二

import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;//PrinterWriter
public class PrintWriterDemo {public static void main(String[] args) {PrintWriter printerWriter = new PrintWriter(System.out);printerWriter.print("Hello World");printerWriter.close();try {PrintWriter printerWriter2 = new PrintWriter(new FileWriter("E:/java学习/textFile/1.txt"));printerWriter2.print("Hello 北京");printerWriter2.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
}

Properties类

说明

  • 专门用于读写配置文件的集合类。
    配置文件的格式:
    键=值
    键=值

  • 注意:键值对不需要有空格,值不需要用引号引起来,默认类型是String。

  • 常见方法:

    • load:加载配置文件的键值对到Properties对象。
    • list:将数据显示到指定设备。
    • getProperty(key):根据键获取值。
    • setProperty(key, value):设置键值对到Properties对象。
    • store:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件,如果含有中文,会存储为unicode码。

代码示例

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;//Properties
public class PropertiesDemo {public static void main(String[] args) {//使用Properties类读取mysql.properties文件try {//1.创建Properties对象Properties properties = new Properties();//2.加载指定配置文件properties.load(new FileReader("E:/java学习/textFile/mysql.properties"));//3.把key-value显示到控制台properties.list(System.out);/*输出结果:-- listing properties --age=18name=mlt*///4.根据key获取对应的valueString name = properties.getProperty("name");String age = properties.getProperty("age");System.out.println("name=" + name + ", age=" + age); //name=mlt, age=18//使用Properties类创建配置文件,修改配置文件内容Properties prop = new Properties();//如果该文件有key,就是创建,如果没有就是修改/*Properties父类是HashTable,底层public synchronized V put(K key, V value) {// Make sure the value is not nullif (value == null) {throw new NullPointerException();}// Makes sure the key is not already in the hashtable.Entry<?,?> tab[] = table;int hash = key.hashCode();int index = (hash & 0x7FFFFFFF) % tab.length;@SuppressWarnings("unchecked")Entry<K,V> entry = (Entry<K,V>)tab[index];for(; entry != null ; entry = entry.next) {if ((entry.hash == hash) && entry.key.equals(key)) {V old = entry.value;entry.value = value;//如果是旧key就替换return old;}}addEntry(hash, key, value, index);//如果是新key,就添加return null;}*/properties.setProperty("name", "孙悟空");properties.setProperty("age", "1000");properties.setProperty("address", "花果山");properties.store(new FileWriter("E:/java学习/textFile/mysql1.properties"), null);properties.list(System.out);/*输出结果:-- listing properties --address=花果山age=1000name=孙悟空*/} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/823932.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

论文词汇积累-铁路专业术语如车务段等(在进行小论文翻译的过程中遇到的问题,搜集整理一下)

一、铁路专用英语 专业词汇中英对照翻译 来源:https://blog.csdn.net/weixin_44304362/article/details/108827567 铁路工程词汇 线路工程 railway line engineering 铁路勘测 ;铁道勘测 railway reconnaissance 铁路选线 ;铁道选线 railway route selection;railway location…

考研打卡(2)

开局(2) 开始时间 2024-10-29 19:21:57 结束时间 2024-10-29 23:32:52呜呜,昨天被老师骂了数据结构能说明快速排序是不稳定的排序方法的一组关键字序列是____(暨南大学2011) A (10,20,30,40,50) B (50,40,30,20,10) C (20,20,30,10,40) D (20,40,30,30,10)C (20,…

vue2基础组件通信案例练习:把案例Todo-list改写成本地缓存

vue2基础组件通信案例练习:把案例Todo-list改写成本地缓存@目录概述前端代码本人其他相关文章链接 概述前面文章案例已经练习了父子组件之间的通信,这一节讲述如何把todos数组放进本地缓存中,因为实际开发场景中频繁查询的数据很有可能会用到本地缓存技术。思考:如何改成使…

Webstorm 2024 安装使用 (附加永久激活码、补丁)

下载安装第二步,安装完成之后,下载补丁 下载地址(里面包含激活码)完成,之后输入激活码免责声明:本文中的资源均来自互联网,仅供个人学习和交流使用,严禁用于商业行为,下载后请在24小时内从电脑中彻底删除。对于因非法使用而引起的版权争议,与作者无关。所有资源仅供学习…

高级语言程序设计课程第五次个人作业

这个作业属于哪个课程:https://edu.cnblogs.com/campus/fzu/2024C/ 这个作业要求在哪里: https://edu.cnblogs.com/campus/fzu/2024C/homework/13298 学号:<102400229> 姓名:<杨灿> 书本第8章8.11编程练习题目中的第1题 没有问题书本第8章8.11编程练习题目中的…

代码生产力提高100倍,Claude-3.5 +Cline 打造超强代码智能体!小白也能开发各种app!

嘿,各位小伙伴们。 今天,带大家走进神奇的 AI 世界,一起探索强大的工具和技术。 最近,Anthropic 发布了全新的 Claude-3.5-sonnet 模型,这可是 Claude-3.5-sonnet 模型的升级版哦!这款最新的模型在多方面的能力都有了显著提升,尤其是在编程方面。已经完全超越 GPT 模型,…

在线协作产品有哪些

在线协作产品主要有以下四类:一、通信工具,如Slack、Microsoft Teams、Zoom;二、文件共享与协作,如Google Workspace、Dropbox、Microsoft OneDrive;三、项目管理与任务追踪,如Trello、Asana、JIRA;四、设计与创作协作,如Figma、Adobe Creative Cloud、Canva。通信工具…

AEER-Applied Ecology and Environmental Research

生态环境、生物地理学、动物学、植物学、古生物学、生物计量学、生物数学和定量的生态学或多学科农业研究。@目录一、征稿简介二、重要信息三、服务简述四、投稿须知 一、征稿简介二、重要信息期刊官网:https://ais.cn/u/3eEJNv三、服务简述 生态环境、生物地理学、动物学、植…

学习笔记(十二):ArkUi-相对布局 (RelativeContainer)

基本概念锚点:通过锚点设置当前元素基于哪个元素确定位置。对齐方式:通过对齐方式,设置当前元素是基于锚点的上中下对齐,还是基于锚点的左中右对齐。锚点设置 锚点设置是指设置子元素相对于父元素或兄弟元素的位置依赖关系。 在水平方向上,可以设置left、middle、right的锚…

Dingdone和Apicloud开发出的APP的区别在哪里

Dingdone和Apicloud是两个流行的移动应用开发平台,它们在许多方面具有不同的特点和优势。本文将详细探讨:1、开发环境和工具集的差异;2、编程语言和框架支持的对比;3、开发效率和灵活性的区别;4、社区支持和资源的差异。例如,Dingdone可能更专注于提供快速开发的解决方案…

GeoChat论文阅读

GeoChat 任务 图像级对话任务 在此任务中,GeoChat 处理图像和用户文本查询,利用图像的全局上下文执行对话的任务。 区域级对话任务 在图像输入中向 GeoChat 提供空间框位置 ( b ),指导模型关注图像中的特定区域,执行区域级的对话任务。 具体化对话任务 通过使用特殊的标记,…

lvgl8图像改成lvgl9图像的方法(c文件)

[1] 离线png->c的工具: LittlevGL - 里飞网 - Powered by Discuz! LvglImgTool更新V0.2版本 - LittlevGL - 里飞网 - Powered by Discuz! Lvgl_image_convert_tool: 基于LVGl图片转换离线版封装的小工具,不仅有界面,还可以一键生成到项目里哦 问题 通过Image Converter —…