IO流
一、什么是IO流
IO流(InputOutput )即文件的输入输出流,负责对文件的读和写。
IO流在 java.io.*包下
io 流章节主要是使用流对文件的读写和通过File类操作目录和文件。
二、IO流的分类
所有流都实现了 java.io.Closeable 的colse()
方法皆为可关闭的。
所有流都实现了 java.io.Flushable 的 fiush()
方法皆为可刷新的
记忆小窍门:以Stream 结尾的均为字节流,以 Reader 或 Writer 结尾的均为字符流。
按照家族分类:
以下皆为抽象类,
流 | 概述 |
---|---|
java.io .InputStream | 字节输入流 |
java.io.OutputStream | 字节输出流 |
java.io.Reader | 字符输入流 |
java.io .Writer | 字符输出流 |
按照功能分类
!!! 只列出常用的16个流
文件专属流
流 | 概述 |
---|---|
java.io.FileInputStream | 字节输入流 |
java.io.FileOutStream | 字节输出流 |
java.io.FileReader | 字符输入流 |
java.io.FileWriter | 字符输出流 |
转换流
将字节流转为字符流
流 | 概述 |
---|---|
java.io.InputStreamReader | 输入流转换 |
java.io.OutStreamWriter | 输出流转换 |
缓冲流专属
流 | 概述 |
---|---|
java.io.BufferedInputStream | 带缓冲的字节输入流 |
java.io.BufferedOutStream | 带缓冲的字节输出流 |
java.io.BufferedReader | 带缓冲的字符输入流 |
java.io.BufferedWriter | 带缓冲的字符输出流 |
数据专属流
流 | 概述 |
---|---|
java.io.DateInputStream | 可以读取带数据类型的文件 |
java.io.DateOutputStream | 可以写入数据类型的流 |
标准输出流
流 | 概述 |
---|---|
java.io.PrintWriter | |
java.io.PrintStream | 系统打印流 |
对象专属流
流 | 概述 |
---|---|
java.io.ObjectInputStream | 反序列化 |
java.io.ObjectOutputStream | 序列化 |
待补充
三、IO流的使用
其实每种流的使用方式都大同小异,使用对象调用方法,以下展示文件专属流的使用方法,和其他流之间的小异之处,具体请参照API文档。
文件专属流示例:
FileInputStream 和 FileOutputStream 是文件字节输入输出流,主要读写字节
FileReader 和 FileWriter 是文件字符输入输出流,主要读写字符(只能读取普通文本不能读取图片等)
FileInputStream
读取指定个数的字符
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class MyFileInputStream {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = null;
try {
/*
FileInputStream 构造方法有三个重载:String name | File file | FileDescriptor fdObj。
*/
fileInputStream = new FileInputStream("C:\\Users\\Desktop\\新建文本文档.txt");
byte[] bytes = new byte[10];
int count =0;
while ((count = fileInputStream.read(bytes)) != -1){
/*
int i = fileInputStream.read()每次只读一个字节,返回值为读到的字节的阿克斯码
int i = fileInputStream.read(bytes)每次读取byte长度的字节数,读取到的字节将存入byte数组中,
返回值为读到的字节的个数,当最后一次读取到的所剩字节若少于byte数组的长度时,则将读到的字节按照顺序
覆盖数组中前若干个字节,在读取不到时则返回-1,当返回-1时使用new String(byte,起始位置,长度)将
字节转换为字符串即可完成读取。
*/
String s = new String(bytes,0,count);//读到的字节
System.out.println(s);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
/* 关闭流 */
if (fileInputStream != null){
fileInputStream.close();
}
}
}
}
一次读取全部字符
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class MyFileInputStream {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = null;
try {
/*
FileInputStream 构造方法有三个重载:String name | File file | FileDescriptor fdObj。
*/
fileInputStream = new FileInputStream("C:\\Users\\Desktop\\新建文本文档.txt");
/*返回从此输入流中可以读取(或跳过)的剩余字节数的估计值,*/
int number =fileInputStream.available();
/*一次读取全部*/
byte[] bytes = new byte[number];
/*读取 全部 大小的字节,返回字符个数 */
int byt = fileInputStream.read(bytes);
System.out.println(new String(bytes));
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
/* 关闭流 */
if (fileInputStream != null){
fileInputStream.close();
}
}
}
}
跳过一些字符不读取
/*跳过一些字节不读取*/
fileInputStream.skip(10);
FileOutputStream
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class MyFileOutputStream {
public static void main(String[] args) throws IOException {
FileOutputStream outputStream = null;
try {
/*创建文件输出流 三个重载 File file | File file, boolean append | FileDescriptor fdObj| String name |
String name, boolean append
以下构造为从文件的开始位置开始写入,在流写入关闭后再次使用流进行写入时。会清空原文件内容!!!!使用第五个构造方法
new FileOutputStream("文件名",true) 为从文件内容的末尾开始写入
*/
outputStream = new FileOutputStream("C:\\Users\\XinPeng.SHI\\Desktop\\IO测试.txt");
byte[] bytes = {94,95,96,97,98,99,100};
/*全部写出*/
outputStream.write(bytes);
/*部分写出*/
/*outputStream.write(bytes,0,4);*/
/*一次写一个*/
/*outputStream.write(int byt)*/
/*刷新*/
outputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
if (outputStream != null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
FileReader
package IO;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class MyFileReader {
public static void main(String[] args) throws IOException {
FileReader reader = null;
try {
reader = new FileReader("C:\\Users\\Desktop\\新建文本文档.txt");
/*创建一个char数组,表示每次读取的个数*/
char[] chars = new char[10];
/*读取到的个数*/
/*int number = reader.read(chars);*/
/*判断值*/
int count = 0;
while ((count = reader.read(chars)) != -1){
System.out.println(new String(chars,0,count));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
if (reader != null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
FileWriter
package IO;
import java.io.FileWriter;
import java.io.IOException;
public class MyFileWriter {
public static void main(String[] args) {
FileWriter writer = null;
/*FileWriter 有五种方法重载,重载参数和 FileOutputStream相同 */
try {
writer = new FileWriter("C:\\Users\\XinPeng.SHI\\Desktop\\FileWriter测试.txt");
/* FileWriter也可以直接写入String字符串 或 char 数组*/
char[] chars = {'一','二','三','四','五','六' };
/*全部写入*/
writer.write(chars);
/*部分写入*/
/* writer.write(chars,0,5);*/
/*刷新*/
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (writer!=null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
带缓冲的流
Buffered即带缓冲的流,这四个流不需要数组,自带缓冲。只展示了BufferedReader。
使用了装饰者模式。
BufferedReader
import java.io.*;
public class MyBufferedReader {
public static void main(String[] args) {
try {
/**/
BufferedWriter bufferedWriter = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream("C:\\Users\\XinPeng.SHI\\Desktop\\新建文本.txt")
)
);
char[] chars = {'一','二','三','四','五','六' };
/*开始写*/
bufferedWriter.write(chars,0,4);
/*换行*/
bufferedWriter.newLine();
/*内容末尾追加*/
bufferedWriter.append()
bufferedWriter.write(chars,0,4);
/* 关闭流 */
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
数据专属流
DataOutputStream 和 DataInputStream是数据字节输入输出流
数据专属流可以将数据以及数据类型共同写入文件中。
在读取DataOutputStream写的文件时。读取文件的顺序必须按照写入时的顺序进行读取,
DataOutputStream
import java.io.*;
public class MyOutputStream {
public static void main(String[] args) {
long l = 10000;
DataOutputStream dataOutputStream = null;
try {
dataOutputStream = new DataOutputStream(new FileOutputStream("C:\\Users\\XinPeng.SHI\\Desktop\\新建文本.txt"));
/*在写入时根据数据类型选择*/
/*dataOutputStream.writeInt();
dataOutputStream.writeChar();*/
try {
dataOutputStream.writeLong(l);
} catch (IOException e) {
e.printStackTrace();
}
//......
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
if (dataOutputStream != null){
try {
dataOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
标准流
标准的字节流默认输出到控制台。标准输出流不需要关闭,我们可以改变输出的位置从而达到日志输出的功能。
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class MyPrintStream {
public static void main(String[] args) {
try {
PrintStream printStream = new PrintStream(new FileOutputStream("C:\\Users\\Desktop\\文本.txt",true));
/*修改输出位置*/
System.setOut(printStream);
/*输出内容*/
System.out.println("123123131");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
四、File类
File类不是一种流不能进行文件的读写,在系统中的任何一个都是一个File,File可以理解为所有文件的抽象表示,是文件和目录路径名的抽象表示。使用File类可以对文件和文件目录进行操作
以下展示File常用的方法
package IO;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyFile {
public static void main(String[] args) throws IOException {
/*四种重载*/
File file = new File("C:\\Users\\Desktop\\新建文本.txt");
/*判断文件或目录是否在存在*/
boolean b = file.isFile();
/*如果不存在则创建这个文件*/
if (!b){
file.createNewFile();
}
/*如果不存在则创建这个 目录*/
if (!b){
file.mkdir();
/*以多重目录的方式新建时只需将newFile()中写入多重目录的路径即可*/
/*file.mkdirs();*/
}
/*获取该文件的父路径(两种返回值不相同)*/
file.getParent();
file.getParentFile();
/*获取绝对路径*/
file.getAbsolutePath();
/*获取文件的名字*/
file.getName();
/*判断是否为目录*/
file.isDirectory();
/*判断是否为文件*/
file.isFile();
/*判断是否为隐藏文件*/
file.isHidden();
/*获取文件的最后修改时间 返回毫秒 1970.01.01.00.00*/
long l = file.lastModified();
/*将毫秒转换为日期*/
Date date = new Date(l);
/*穿件日期格式*/
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
/*返回日期时间*/
format.format(date);
/*获取文件大小(字节)*/
file.length();
/*获取目录下的子文件*/
file.listFiles();
}
}
五、对象专属流(序列化与反序列化)
- 序列化是指将java对象转换为字节存储在文件中,方便传输或存储。
反序列化是将序列化后得到文件转换为java对象。 - 需要序列化的类必须实现 Serializable 标志性接口。
- 在序列化多个对象时请将对象放入集合中, 一次性序列化整个集合即可,反序列化时也是如此。
序列化
package IO;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class MyObjectOutputStream {
public static void main(String[] args) {
String s = new String();
ObjectOutputStream outputStream = null;
try {
outputStream = new ObjectOutputStream(new FileOutputStream("String类"));
/*序列化*/
outputStream.writeObject(s);
/*刷新*/
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (outputStream != null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
反序列化
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class MyObjectInputStream {
public static void main(String[] args) {
try {
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("user"));
/*反序列化*/
String s = (String)inputStream.readObject();
System.out.println(s.getClass());//class java.lang.String
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
序列化版本号
在一个类序列化时JVM会为此类默认生成一个序列化版本号内置其中。
在java序列化中在区分类时,若类名不同则类定然不同,在类名且包名都相同时,依靠序列化本号区分。若一个类在后续修改了代码,此时再次编译后将会产生不同的序列化版本号,这会使原先已经序列化过的类在反序列化时出错,因此,我们应在创建一个需要序列化的类时应手动以常量的形式指定序列化版本号,且最好唯一不重复。
/*常量名为固定不可自定义*/
private static final long serialVersionUID = 8888888888888L;
transient关键字
在类中为属性使用transient关键字修饰可以使属性不参加序列化。
import java.io.Serializable;
public class User implements Serializable {
private transient int aeg;
}
六、使用IO流读取Properties文件
- 在java中 Properties 文件为推荐的属性配置文件,在 Properties中 以Key Value键值对的方式存在,在此文件中如果有相同的 Key 时则会覆盖 Value。
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
public class ReadProperties {
public static void main(String[] args) throws IOException {
/*创建流*/
FileReader fileReader = new FileReader("D:\\源码\\untitled\\src\\a.properties");
/*创建 properties 对象*/
Properties properties = new Properties();
/*加载文件*/
properties.load(fileReader);
/*获取属性*/
String name = properties.getProperty("name");
String password = properties.getProperty("password");
System.out.println(name);//admin
System.out.println(password);//123456
}
}