13. IO流
一、File类的使用
- File类的一个对象,代表一个文件或一个文件目录(俗称文件夹)
- File类声明在java.io包下
1.1、构造器
- public File(String pathname)
- 以pathname为路径创建File对象,可以是绝对路径或者相对路径,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储
- 绝对路径:是一个固定的路径,从盘符开始
- 相对路径:是相对于某个位置开始
- 以pathname为路径创建File对象,可以是绝对路径或者相对路径,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储
- public File(String parent,String child)
- 以parent为父路径,child为子路径创建File对象
- public File(File parent,String child)
- 根据一个父File对象和子文件路径创建File对象
public class FileTest {
public static void main(String[] args) {
//相对路径:相较于某个路径下,指明的路径
File file1 = new File("Akame.txt");
//绝对路径:包含盘符在内的文件或文件夹目录的路径
File file2 = new File("E:\\Source\\java\\hi.txt");
System.out.println(file1);
System.out.println(file2);
File file3 = new File("E:\\Source", "java");
System.out.println(file3);
File file4 = new File(file3, "Kurome.txt");
System.out.println(file4);
}
}
1.1.1、路径分隔符
??路径中每集目录之间用一个路径分隔符隔开,路径分隔符和系统有关:windows和DOS系统默认使用“\”来表示UNIX和URL使用“/”来表示。File类提供了一个常量:public static final String separator,根据操作系统,动态的提供分隔符。
1.2、常用方法
public String getAbsolutePath() //获取绝对路径
public String getPath() //获取路径
public String getName() //获取名称
public String getParent() //获取上层文件目录路径。若无,返回null
public long length() //获取文件长度(即:字节数)。不能获取目录的长度
public long lastModified() //获取最后一次修改的时间,毫秒数
public String[] list() //获取指定目录下的所有文件或者文件目录的名称数组
public File[] listFiles() //获取指定目录下的所有文件或者文件目录的File数组
public boolean renameTo(File dest) //把文件重命名为指定的文件路径
public boolean isDirectory() //判断是否是文件目录
public boolean isFile() //判断是否是文件
public boolean exists() //判断是否存在
public boolean canRead() //判断是否可读
public boolean canWrite() //判断是否可写
public boolean isHidden() //判断是否隐藏
public boolean createNewFile() throws IOException //创建文件。若文件存在,则不创建,返回false
public boolean mkdir() //创建文件目录。如果此文件目录存在或此文件目录的上层目录不存在,就不创建
public boolean mkdirs() //创建文件目录。如果上层目录不存在,一并创建
public boolean delete() //删除文件或文件夹
二、IO流概述与流的分类
2.1、IO流概述
??I/O是Input/Output的缩写,用于处理设备之间的数据传输。如读/写文件,网络通信等。Java程序中,对于数据的输入/输出操作以“流(stream)”的方法进行。java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。
- 输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中
- 输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中
2.2、IO流的分类
- 按操作数据单位不同分为:字节流(8 bit)、字符流(16 bit)
- 按数据流的流向不同分为:输入流、输出流
- 按流的角色的不同分为:节点流、处理流
抽象基类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
由这四个类派生出来的子类名称都是以其父类名作为子类名后缀
三、IO流的体系结构
分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
---|---|---|---|---|
抽象基类 | InputStream | OutputStream | Reader | Writer |
访问文件 | FileInputStream | FileOutputStream | FileReader | FileWriter |
访问数组 | ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter |
访问管道 | PipedInputStream | PipedOutStream | PipedReader | PipedWriter |
访问字符串 | StringReader | StringWriter | ||
缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
转换流 | InputStreamReader | OutputStreamWriter | ||
对象流 | ObjectInputStream | ObjectOutputStream | ||
FilterInputStream | FilterOutputStream | FilterReader | FilterWriter | |
打印流 | PrintStream | PrintWriter | ||
推回输入流 | PushbackInputStream | PushbackReader | ||
特殊流 | DataInputStream | DataOutputStream |
3.1、FileReader与FileWriter
不能用来复制非文本文件
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyFile {
public static void main(String[] args) {
FileReader fReader = null;
FileWriter fWriter = null;
long begin = System.currentTimeMillis();
/**
* 读入的文件一定要存在,否则就会报FileNotFoundException
* 输出操作,对应的file可以不存在。
* file对应的硬盘文件如果不存在,在输出过程中,会自动创建此文件
* file对应的硬盘文件如果存在:
* 如果流使用的构造器使用:FileWrite(file,false) / FileWriter(file):对原有文件的覆盖
* 如果流使用的构造器使用:FileWrite(file,true):对原有文件进行追加
*/
try {
//1.实例化File类的对象,指明要操作的文件
File srcFile = new File("./java/file/滕王阁序.txt");
File destFile = new File("./java/file/滕王閣序.txt");
//2.提供具体的流
fReader = new FileReader(srcFile);
fWriter = new FileWriter(destFile);
//3.数据的读入和写出
char[] cbuf = new char[5];
int len;
while((len = fReader.read(cbuf)) != -1){
fWriter.write(cbuf,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流资源的关闭
if(fReader != null){
try {
fReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fWriter != null){
try {
fWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
long end = System.currentTimeMillis();
System.out.println("time: " + (end-begin) + "ms");
}
}
运行前
运行后
3.2、FileInputStream与FileOutputStream
使用字节流FileInputStream读取文本文件到控制台,可能出现乱码!
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Copy {
public static void main(String[] args) {
FileInputStream fInputStream = null;
FileOutputStream fOutputStream = null;
long begin = System.currentTimeMillis();
//读入的文件一定要存在,否则就会报FileNotFoundException
try {
//1.实例化File类的对象,指明要操作的文件
File srcFile = new File("./java/video/kinomoto.flv");
File destFile = new File("./java/video/sakura.flv");
//2.提供具体的流
fInputStream = new FileInputStream(srcFile);
fOutputStream = new FileOutputStream(destFile);
//3.数据的读入和写出
byte[] buffer = new byte[1024];
int len;
while((len = fInputStream.read(buffer)) != -1){
fOutputStream.write(buffer,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流的关闭操作
if(fInputStream != null){
try {
fInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fOutputStream != null){
try {
fOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
long end = System.currentTimeMillis();
System.out.println("time: " + (end-begin) + "ms");
}
}
运行前
运行后
3.3、BufferedInputStream与BufferedOutputStream
缓冲流内部提供了一个缓冲区,因此能提高流的读取、写入的速度
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class BufferedTest {
public static void main(String[] args) {
FileInputStream fInputStream = null;
FileOutputStream fOutputStream = null;
BufferedInputStream bInputStream = null;
BufferedOutputStream bOutputStream = null;
long begin = System.currentTimeMillis();
//读入的文件一定要存在,否则就会报FileNotFoundException
try {
//1.实例化File类的对象,指明要操作的文件
File srcFile = new File("./java/video/kinomoto.flv");
File destFile = new File("./java/video/sakura.flv");
//2.提供具体的流
fInputStream = new FileInputStream(srcFile);
fOutputStream = new FileOutputStream(destFile);
bInputStream = new BufferedInputStream(fInputStream);
bOutputStream = new BufferedOutputStream(fOutputStream);
//3.数据的读入和写出
byte[] buffer = new byte[1024];
int len;
while((len = bInputStream.read(buffer)) != -1){
bOutputStream.write(buffer,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流的关闭操作:先关闭外层的流,再关闭内层的流,再关闭外层流的同时,内层流也会自动关闭
if(bInputStream != null){
try {
bInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bOutputStream != null){
try {
bOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
long end = System.currentTimeMillis();
System.out.println("time: " + (end-begin) + "ms");
}
}
运行前
运行后
3.4、BufferedReader与BufferedWtiter
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Buffered {
public static void main(String[] args) {
BufferedReader bReader = null;
BufferedWriter bWriter = null;
long begin = System.currentTimeMillis();
try {
//1.创建文件和相应的流
bReader = new BufferedReader(new FileReader(new File("./java/file/滕王阁序.txt")));
bWriter = new BufferedWriter(new FileWriter(new File("./java/file/滕王閣序.txt")));
//2.文件的读写操作
String data;
while((data = bReader.readLine()) != null){
bWriter.write(data);
bWriter.newLine();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//3.关闭相应的流
if(bReader != null){
try {
bReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bWriter != null){
try {
bWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
long end = System.currentTimeMillis();
System.out.println("time: " + (end-begin) + "ms");
}
}
运行前
运行后
3.5、InputStreamReader与OutputStreamWriter
??InputStreamReader和OutputStreamWriter属于字符流,提供字符流与字节流之间的转换;InputStreamReader将一个字节的输入流转换成字符的输入流;OutputStreamWriter将一个字符的输出流转换成字节的输出流;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
public class Transform {
public static void main(String[] args) {
FileInputStream fInputStream = null;
FileOutputStream fOutputStream = null;
InputStreamReader iStreamReader = null;
OutputStreamWriter oStreamWriter = null;
try {
File file1 = new File("滕王阁序.txt");
File file2 = new File("滕王閣序.txt");
fInputStream = new FileInputStream(file1);
fOutputStream = new FileOutputStream(file2);
iStreamReader = new InputStreamReader(fInputStream,"utf-8");
oStreamWriter = new OutputStreamWriter(fOutputStream,"gbk");
char[] buffer = new char[20];
int len;
while((len = iStreamReader.read(buffer)) != -1){
oStreamWriter.write(buffer, 0, len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(iStreamReader != null) {
try {
iStreamReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(oStreamWriter != null){
try {
oStreamWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3.6、标准输入、输出流
- System.in和System.out分别代表系统标准的输入和输出设备
- 默认输入设备是:键盘,默认输出设备是:显示器
- System.in的类型是InputStream
- System.out的类型是PrintStream,其是OutputStream的子类FilterOutputStream的子类
- 重定向:通过System类的setIn(),setOut()对默认设备进行改变
- public static void setIn(InputStream in)
- public static void setOut(PrintStream out)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class InputTest {
public static void main(String[] args) {
InputStreamReader iStreamReader = null;
BufferedReader bReader = null;
try {
iStreamReader = new InputStreamReader(System.in);
bReader = new BufferedReader(iStreamReader);
while(true){
System.out.print("请输入字符串:");
String data = bReader.readLine();
if("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)){
System.out.println("程序结束");
break;
}
String upperCase = data.toUpperCase();
System.out.println("你输入的字符串是" + upperCase);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bReader != null){
try {
bReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3.7、PrintStream与PrintWriter
- PrintStream和PrintWriter,提供了一系列重载的print()和println(),实现将基本数据类型的数据格式转化为字符串输出
- PrintStream和PrintWriter的输出不会抛出IOException
- PrintStream和PrintWriter有自动flush功能
- PrintStream打印的所有字符都使用平台的默认字符编码转换为字节
- System.out返回的是PrintStream的实例
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class PrintTest {
public static void main(String[] args) {
FileOutputStream fOutputStream = null;
PrintStream pStream = null;
try {
fOutputStream = new FileOutputStream(new File("text.txt"));
pStream = new PrintStream(fOutputStream,true);
if(pStream != null){
System.setOut(pStream);
}
for(int i=0;i<=255;i++){
System.out.print((char)i);
if(i%50 == 0){
System.out.println();
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if(pStream != null){
pStream.close();
}
}
}
}
3.8、DataInputStream与DataOutputStream
??DataInputStream和DataOutputStream用于读取和写出基本数据类型和String类型的数据,分别套接在InputStream和OutputStream子类的流上;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class DataTest {
public static void main(String[] args) {
DataOutputStream dOutputStream = null;
DataInputStream dInputStream = null;
try {
dOutputStream = new DataOutputStream(new FileOutputStream("data.txt"));
dInputStream = new DataInputStream(new FileInputStream("data.txt"));
dOutputStream.writeUTF("小樱");
dOutputStream.flush();
dOutputStream.writeInt(9);
dOutputStream.flush();
dOutputStream.writeBoolean(true);
dOutputStream.flush();
//读取不同类型的数据的顺序要与写入文件时保存的数据的顺序一致
String name = dInputStream.readUTF();
int age = dInputStream.readInt();
boolean gril = dInputStream.readBoolean();
System.out.println("name:" + name + ",age:" + age + ",gril:" + gril);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(dOutputStream != null){
try {
dOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(dInputStream != null){
try {
dInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3.9、ObjectInputStream与ObjectOutputStream
??ObjectInputStream和ObjectOutputStream用于存储和读取基本数据类型或对象的处理流,可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。其中,用ObjectOutputStream类保存基本类型数据或对象的机制称为序列化;用ObjectInputStream类读取基本类型数据或对象的机制称为反序列化;ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量。
3.9.1、对象的序列化
??对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久的保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。序列化的好处在于可将任何实现Serializable接口的对象转化成字节数据,使其在保存和传输时可被还原。
??序列化是 RMI(Remote Method Invoke - 远程方法调用) 过程的参数和返回值都必须实现的机制,而 RMI 是 Java EE 的基础。因此序列化机制是 Java EE 平台的基础;
??如果需要让某个对象支持序列化机制,则必须让对象所属的类及其属性是可以序列化的,为了让某个类是可序列化的,该类必须实现如下的两个接口之一:Serializable、Externalizable,否则或抛NotSerizlizableException,还需要提供一个表示序列化版本标识符的静态常量:private static final long serialVersionUID;serialVersionUID用来表明类的不同版本间的兼容性,其目的是以序列化对象进行版本控制,有关各版本反序列化时是否兼容。如果类没有显示定义这个静态常量,它的值时Java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID可能发生改变。
??Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID于本地相应的实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的差异(InvalidCastException)。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class ObjectTest {
public static void main(String[] args) {
ObjectOutputStream oOutputStream = null;
ObjectInputStream oInputStream = null;
try {
oOutputStream = new ObjectOutputStream(new FileOutputStream("object.data"));
oInputStream = new ObjectInputStream(new FileInputStream("object.data"));
oOutputStream.writeObject(new String("我爱中华!"));
oOutputStream.flush();
oOutputStream.writeObject(new Person("Sakura", 9,new Account(1001, 100)));
oOutputStream.flush();
Object object = oInputStream.readObject();
String string = (String)object;
Person person = (Person)oInputStream.readObject();
System.out.println(string);
System.out.println(person);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if(oOutputStream != null){
try {
oOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(oInputStream != null){
try {
oInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
import java.io.Serializable;
public class Person implements Serializable{
private static final long serialVersionUID = 457987983215494590L;
private String name;
private int age;
private Account account;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public Person(String name,int age,Account account){
this(name, age);
this.account = account;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
public String toString(){
return "Person{ name:" + name + ",age:" + age + " " + account + "}";
}
}
import java.io.Serializable;
public class Account implements Serializable{
private static final long serialVersionUID = 4579879832131416134L;
private int id;
private double balance;
public Account(){
}
public Account(int id,double balance){
this.id = id;
this.balance = balance;
}
public void setId(int id){
this.id = id;
}
public int getId(){
return id;
}
public void setBalance(double balance){
this.balance = balance;
}
public double getBalance(){
return balance;
}
public String toString(){
return "Account{id: "+ id + ",balance:" + balance + "}";
}
}
3.10、RandomAccessFile
??RandomAccessFile声明在java.io包下,但直接继承于java.lang.Object类,并且它实现了DataInput、DataOutput这两个接口,也就意味着这个类既可以读也可以写。RandomAccessFile类支持“随机访问”的方式,程序可以直接跳到文件的任意地方来读、写文件;RandomAccessFile对象包含一个记录指针,用以标示当前读写出的位置;
- 构造器
- public RandomAccessFile(File file,String mode)
- public RandomAccessFile(String name,String mode)
- 创建RandomAccessFile类实例需要指定一个mode参数,该参数指定RandomAccessFile的访问模式
- r:以只读方式打开
- rw:打开以便读取和写入
- rwd:打开以便读取和写入;同步文件内容的更新
- rws:打开以便读取和写入;同步文件内容和元数据的更新
- 如果以模式为只读r,则不会创建文件,而是会去读取一个已经存在的文件,如果读取的文件不存在则会出现异常。
- 如果模式为rw读写,如果文件不存在则会去创建文件,如果写出的文件存在,则会对原有内容进行覆盖。(默认情况下,从头覆盖)
- RandomAccessFile类对象可以自由移动记录指针:
- long getFilePointer():获取文件记录指针的当前位置
- void seek(long pos):经文件记录指针定位到pos位置
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileTest {
public static void main(String[] args) {
RandomAccessFile rAccessFile1 = null;
RandomAccessFile rAccessFile2 = null;
try {
rAccessFile1 = new RandomAccessFile(new File("sakura.jpeg"), "r");
rAccessFile2 = new RandomAccessFile(new File("kinomoto.jpeg"), "rw");
byte[] buffer = new byte[1024];
int len;
while((len = rAccessFile1.read(buffer)) != -1){
rAccessFile2.write(buffer, 0, len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(rAccessFile1 != null){
try {
rAccessFile1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(rAccessFile2 != null){
try {
rAccessFile2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}