IO流是整个Java开发包中最复杂的一个,那么我们一句话概括它的核心: “根据实例化子类的不同,完成的功能也不同”, 整个IO包中包含五个类一个接口:File、OutputStream、InputStream、Writer,Reader; Serializable。
注:java的输入流主要是InputStream和Reader作为基类,而输出流则是主要由outputStream和Writer作为基类。它们都是一些抽象基类,无法直接创建实例。
划重点:要从程序的角度来理解(程序去读去写)
IO可以简单的理解成input和out,代表输入输出的意思。输入就是读,输出就是写。
IO可以读写硬盘、光盘、内存、键盘、网络等资源上的数据。
下面的图说明了一个程序从一个地方读数据并且写数据到目的地的原理:
一个程序从数据源读取数据的时候,需要 InputStream或者Reader。程序写数据的时候,就需要OutputStream或Writer。具体可以参见下面图例:
java输入/输出流体系中常用的流的分类表
分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
---|---|---|---|---|
抽象基类 | InputStream | OutputStream | Reader | Writer |
访问文件 | FileInputStream | FileOutputStream | FileReader | FileWriter |
访问数组 | ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter |
访问管道 | PipedInputStream | PipedOutputStream | PipedReader | PipedWriter |
访问字符串 | StringReader | StringWriter | ||
缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
转换流 | InputStreamReader | OutputStreamWriter | ||
对象流 | ObjectInputStream | ObjectOutputStream | ||
抽象基类 | FilterInputStream | FilterOutputStream | FilterReader | FilterWriter |
打印流 | PrintStream | PrintWriter | ||
推回输入流 | PushbackInputStream | PushbackReader | ||
特殊流 | DataInputStream | DataOutputStream |
注:表中粗体字所标出的类代表节点流,必须直接与指定的物理节点关联:斜体字标出的类代表抽象基类,无法直接创建实例。
一、File类:
File类是文件和目录的抽象表示形式,也是整个IO包中唯一一个与文件本身有关的操作类。文件本身是指文件的创建、查询、删除等操作。一个File类被创建时,它就不能再被改变内容。注意:在Java.IO包中的File类本身是一个跨平台的文件操作类,因此在操作中更多的要考虑到各个操作系统的 区别
1、File类的使用:
package io;
import java.io.File;
import java.io.IOException;
public class FileDemo1 {
public static void main(String[] args) {
// //兼容不同系统
File f = new File("e:"+File.separator+"io"+File.separator+"tt.txt");
if(f.exists()){
System.out.println("有这个文件");
}else{
System.out.println("no");
}
try {
f.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(f.canRead()){
System.out.println("canread");
}
if(!f.canWrite()){
System.out.println("no");
}
System.out.println(f.getAbsolutePath());
System.out.println(f.getParent());
System.out.println(f.getPath());
System.out.println(f.getParentFile());
File f1 = f.getParentFile();
if(f1.isDirectory()){
System.out.println("是个目录");
File[] files = f1.listFiles();
for(File f2 :files){
System.out.println(f2.getName());
}
}
if(f1.isFile()){
System.out.println("是个文件");
}else{
System.out.println("noo");
}
File f3 = new File("e:"+File.separator+"io"+File.separator+"new");
if(!f3.exists()){
//创建目录
f3.mkdir();
}
}
}
package io;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/*
* 在e:/io目录里创建一个新的目录old
在old里创建一个新文件old.txt
在old.txt中写入hello word
*/
public class FileDemo2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
File f = new File("e:"+File.separator+"io"+File.separator+"old");
if(!f.exists()){
f.mkdir();
}
if(f.exists()){
File f1 = new File(f.getAbsoluteFile()+File.separator+"old.txt");
if(!f1.exists()){
try {
f1.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(f1.exists()){
FileOutputStream fos ;
try {
fos =new FileOutputStream(f1,true);
try {
fos.write("hello\r\n".getBytes());
fos.flush();
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
/**
* @program: demo
* @description: ss
* @author: Mr.Jia
* @create: 2018-08-09 15:57
**/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo3 {
public void copyFile(File sourcefile, File destFile) {
try {
FileInputStream fis = new FileInputStream(sourcefile);
FileOutputStream fos = new FileOutputStream(destFile);
int len = -1;
byte[] data = new byte[1024];
while ((len = fis.read(data)) != -1) {
fos.write(data, 0, len);
}
fis.close();
fos.flush();
fos.close();
System.out.println("copied");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void copy(String sourcePath,String destPath){
File f = new File(sourcePath);
File destFile = new File(destPath);
if(!destFile.exists()){
destFile.mkdir();
}
for(File file:f.listFiles()){
if(f.isDirectory()){
// d:/new_io
File subFile = new File(destFile.getAbsoluteFile()+File.separator+file.getName());
if(!subFile.exists()){
subFile.mkdir();
}
copy(file.getAbsolutePath(), subFile.getAbsolutePath());
}
else {
File s = new File(destFile.getAbsoluteFile() + File.separator
+ file.getName());
copyFile(file, s);
System.out.println(file.getAbsolutePath() + "\t"
+ file.length());
}
}
}
public static void main(String[] args) {
Demo3 test = new Demo3 ();
test.copy("e:io", "e:newio");
}
}
2、缓冲流的使用(BufferedInputStream/BufferedReader, BufferedOutputStream/BufferedWriter):
字符缓存流的用法和字节缓存流一致
package io;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileDemo4 {
public static void main(String[] args)throws IOException {
FileInputStream fis=null;
FileOutputStream fos=null;
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
try {
//创建字节输入流
fis=new FileInputStream("E:\\io\\rr.txt");
//创建字节输出流
fos=new FileOutputStream("E:\\io\\tt.txt");
//创建字节缓存输入流
bis=new BufferedInputStream(fis);
//创建字节缓存输出流
bos=new BufferedOutputStream(fos);
byte[] b=new byte[1024];
int hasRead=0;
//循环从缓存流中读取数据
while((hasRead=bis.read(b))>0){
//向缓存流中写入数据,读取多少写入多少
bos.write(b,0,hasRead);
}
}catch (IOException e){
e.printStackTrace();
}finally {
bis.close();
bos.close();
}
}
}
上面代码中我们使用了缓存流和文件流,但是我们只关闭了缓存流。这个需要注意一下,当我们使用处理流套接到节点流上的使用的时候,只需要关闭最上层的处理就可以了。java会自动帮我们关闭下层的节点流。
3、对象流的使用(ObjectInputStream/ObjectOutputStream)
写入对象:
public static void writeObject(){
OutputStream outputStream=null;
BufferedOutputStream buf=null;
ObjectOutputStream obj=null;
try {
//序列化文件輸出流
outputStream=new FileOutputStream("E:\\io\\rr.txt");
//构建缓冲流
buf=new BufferedOutputStream(outputStream);
//构建字符输出的对象流
obj=new ObjectOutputStream(buf);
//序列化数据写入
obj.writeObject(new Person("A", 21));//Person对象
//关闭流
obj.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
使用对象流的一些注意事项
1.读取顺序和写入顺序一定要一致,不然会读取出错。
2.在对象属性前面加transient关键字,则该对象的属性不会被序列化
4、何为NIO,和传统Io有何区别?
传统IO读取数据时,如果数据源没有数据则会导致线程阻塞,都是阻塞式的输入输出。
传统IO都是通过字节的移动来处理,一次只能处理一个字节,效率不高。
JDK1.4新增了一系列改进的IO处理功能,被称为NIO。
NIO采用内存映射文件的方式来处理输入输出,NIO将文件或文件的一段区域映射到内存中,
这样就可以像访问内存一样访问文件了。非阻塞, 性能大幅度提高。
Channel(通道)是传统输入输出的模拟,在NIO中所有数据的传输都需要通过通道。
Channel有个map()方法,可以直接将"一块数据"映射到内存中。
传统IO是面向流的处理,NIO是面向块的处理。
Buffer可以理解成一个容器,本质上是一个数组,数据通过Channel传输之前都需要放入到Buffer中,
Buffer像竹筒,去Channel里取水,也允许使用Channel直接将文件的模块数据映射成Buffer。
NIO需要使用Buffer、Channel、Selector结合使用才能方显威力(具体参考java非阻塞网络编程)
把Socket通过Channel注册到Selector,使用一个线程在Selector中轮询,
发现Channel有读写的事件,就可以分配给其他线程来处理(通常使用线程池)。
二、序列化:
序列化:存到内存;反序列化:从内存中读出;
序列化是将对象状态转换为可保持或传输的格式的过程。说明白点就是你可以用对象输出流输出到文件.如果不序列化输出的话.很可能会乱!
实现方式是实现java.io.Serializable接口.这个接口不需要实现任何具体方法.只要implements java.io.Serializable 就好了
参考:https://blog.csdn.net/nightcurtis/article/details/51324105