IO流
IO介绍
编程语言的I/O类库中常使用流这个抽象概念,它代表任何有能力产出数据的数据源或者是有能力接收数据的接收端对象。(from Thinking in Java)。
本文从四个方面对IO流进行概述,并举出大量案例增加理解。
-File
-字节流
-字符流
-CommonIO
核心类:
File 文件类
InputStream 字节输入流
OutputStream 字节输出流
Reader 字符输入流
Writer 字符输出流
Closeable 关闭流接口
Flushable 刷新流接口
Serializable 序列化接口
流分类1:
----一切以程序为中心,进来的是输入流,出去的叫输出流、
流分类2:
节点流:可以从数据源或目的地读写数据
处理流(包装流):不直接连接到数据源或目的地,对其他流进行封装。主要目的是简化操作和提高性能。
节点流和处理流的关系:
- 节点流处于IO操作的第一线,所有操作必须通过他们家进行;
- 处理流可以对其他流进行处理(提高效率或操作灵活性)
流分类3:
字节流:按照字节读取数据(InputStream、OutputStream)
字符流:按照字符读取数据(Reader、Writer),因为文件编码的不同,从而有了对字符进行高效操作的字符流对象。
原理: 底层还是基于字节流操作,自动搜寻了制定的码表。
File 文件类/文件夹
File api
常量:
pathSeparator:路径分隔符 ; :
separator: 名称分隔符 /
构造器:
File(File parent, String child)
File(String pathname)
File(String parent, String child)
File(URI uri)
public class Test01{
public static void main(String[] args){
String path="D:/java/01.jpg"; // 使用/或者separator
File src=new File(path);
System.out.println(src.length());
src=new File("D:/java","01.jpg");
System.out.println(src.length());
File parent=new File("D:/java");
src=new File(parent,"01.jpg");
System.out.println(src.length());
}
}
相对路径和绝对路径:
- 存在盘符,绝对路径;
- 没有盘符,相对路径。
public class Test01{
public static void main(String[] args){
String path="D:/java/01.jpg";
File src=new File(path);
System.out.println(src.getAbsolutePath());
String path="01.jpg";
File src=new File(path);
System.out.println(src.getAbsolutePath());
System.out.println(System.getProperty("user.dir));
//输出当前工程目录
}
}
File类主要方法:
getName()
getPath()
getAbsolutePath()
getParent()
exists()
isFile()
isDirectory()
length() 文件的字节数,返回long
createNewFile() 不存在才创建,无法创建文件夹
delete()
mkdir() 必须确保上一级父目录存在
mkdirs() 上级父目录可以不存在,创建父目录
list() 下级目录
listFiles() 下级Files
ListRoots() 列出所有的盘符
文件编码
US-ASCII
ISO-8859-1
UTF-8
UTF-16 -unicode
GBK
编码
getBytes()
getBytes(Charset charset)
getBytes(String charsetName)
解码
new String(datas,0,datas.length(),“utf-8”);
IO流
InputStream
implements Closeable, AutoCloseable
OutputStream
implements Closeable, AutoCloseable, Flushable
Reader
implements Closeable, AutoCloseable, Readable
Writer
implements Closeable, AutoCloseable, Flushable, Appendable
读操作步骤:
(1)创建源
(2)选择流
(3)操作
(4)释放资源
public class Test03{
public static void main(String[] args){
File file=new File("D:/1.txt"); //创建源
InputStream is=null;
try{
is=new FileInputStream(file); //选择流
int temp;
while((temp=is.read())!=-1){ //一个字节的读,也可以一段一段的读
System.out.println((char)temp);
}
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}finally{
try{ //释放资源
if(is!=null){
is.close();
}
}catch(){
e.printStackTrace();
}
}
}
}
写操作步骤:
(1)创建源
(2)选择流
(3)操作
(4)释放资源
public class Test04{
public static void main(String[] args){
File file=new File("D:/2.txt"); //创建源
OutputStream os=null;
try{
os=new FileOutputStream(file,true); //true表示文件内容追加 //选择流
String msg="IO IS EASY";
byte[] bytes=msg.getByts();
os.write(bytes,0,bytes.length); //操作
os.flush();
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}finally{
try{
if(is!=null){ //释放资源
is.close();
}
}catch(){
e.printStackTrace();
}
}
}
}
文件拷贝
读–>写
FileReader 、 FileWriter 只能处理字符,不能处理图片
字节数组流
ByteArrayInputStream 、 ByteArrayOutStream
1.源头:字节数组
2.访问虚拟机内存内的字节数组,此流无需关闭
3.任何东西都可以转成字节数组
4.字节数组不要太大
ByteArrayInputStream(Byte[] data)
public class Test05{
public static void main(String[] args){
byte[] src="talk is cheap show me the code".getBytes();
InputStream is=null;
try{
is=new ByteArrayInputStream(src);
byte[] flush=new byte[5];
int len=-1;
while((len=is.read(flush))!=-1){
String str=new String(flush,0,flush.length);
System.out.println(str);
}
}
}catch(IOException e){
e.printStackTrace();
}
}
}
public class Test06{
public static void main(String[] args){
byte[] dest=null;
ByteArrayOutputStream baos=null;
try{
baos=new ByteArrayOutputStream();
String msg="SHOW ME THE CODE";
byte[] bytes=msg.getByts();
baos.write(bytes,0,bytes.length);
baos.flush();
//获取数据
dest=baos.toByteArray();
System.out.println(dest.length);
}catch(IOException e){
e.printStackTrace();
}
}
}
对接流
过程:
(1)图片读取到字节数组中 InputStream、ByteArrayInputStream
(2)字节数组写到文件 OutputStream、ByteArrayOutStream
public class Test05{
public static void main(String[] args){
String filePath="D:/1.png";
System.out.println(fileToByteArray(filePath).length);
byteArrayToFile(fileToByteArray(filePath),"D:/2.png");
}
//(1)图片读取到字节数组中
public static byte[] fileToByteArray(String filePath){
//1创建源与目的地
File file=new File(filePath);
byte[] dest=null;
//2.选择流
InputStream is=null;
ByteArrayOutputStream baos=null;
try{
is=new FileInputStream(file);
baos=new ByteArrayOutputStream();
byte[] flush=new byte[1024*10];
int len;
while((len=is.read(flush))!=-1){
baos.write(flush,0,len);
}
baos.flush();
return baos.toByteArray();
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}finally{
try{
if(is!=null){
is.close();
}
}catch(){
e.printStackTrace();
}
return null;
}
}
(2)字节数组写到文件
public static void byteArrayToFile(byte[] src,String filePath){
//1.创建源
File dest=new File(filePath);
//2.选择流
InputStream is=null;
OutputStream os=null;
try{
os=new FileOutputStream(dest);
is=new ByteArrayInputStream(src);
//3.操作
byte[] bytes=new byte[5];
int len=-1;
while((len=is.read(bytes))!=-1){
os.write(bytes);
}
baos.flush();
//获取数据
}catch(IOException e){
e.printStackTrace();
}finally{
try{
if(os!=null){
os.close();
}
}catch(){
e.printStackTrace();
}
}
}
}
IO工具类
/**
封装拷贝
封装释放资源
*/
public class Utils{
//拷贝,输入流输出流的对接
public static void copy(InputStream is, OutputStream os){
try{
byte[] flush=new byte[1024];
int len=-1;
while((len=is.read(flush))!=-1){
os.write(flush,0,flush.length);
}
os.flush();
}finally{
close(is,os);
}
}
//释放资源
public static void close(InputStream is, OutputStream os){
try{
if(is!=null){
is.close();
}
}catch(){
e.printStackTrace();
}
try{
if(os!=null){
os.close();
}
}catch(){
e.printStackTrace();
}
}
//释放资源
public static void close(Closeable... ios){
for(Closeable io:ios){
try{
if(io!=null){
io.close();
}
}catch(){
e.printStackTrace();
}
}
}
}
jdk1.7开始使用try …wirh …resource,将流的声明加入到try()中
try(InputStream is=new FileInputStream;
OutputStream os=new FileOutputStream;){
byte[] flush=new byte[1024];
int len=-1;
while((len=is.read(flush))!=-1){
os.write(flush,0,flush.length);
}
os.flush();
}
IO原理剖析—装饰设计模式
字节缓冲流
BufferedInputStream、BufferedOutputStream
缓冲流提高了操作读写的性能,因为IO的操作是影响系统的瓶颈,缓冲流内部使用缓冲区,默认8k,提高读写操作。
(1)提高性能
(2)底层仍然使用节点流
(3)内部自动释放节点流
//加入缓冲流
public class BufferedTest01{
public static void main(String[] args){
File file=new File("D:/1.txt");
InputStream is=null;
BufferedInputStream bis=null;
try{
is=new FileInputStream(file);
bis=new BufferedInputStream(is);
byte[] flush=new byte[1024];
int len;
while((len=bis.read(flush))!=-1){ //一个字节的读,也可以一段一段的读
String str=new String(flush,0,flush.length);
System.out.println(str);
}
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}finally{
try{
if(bis!=null){
bis.close();
}
}catch(){
e.printStackTrace();
}
}
}
}
public class BufferedTest02{
public static void main(String[] args){
File file=new File("D:/2.txt");
OutputStream os=null;
try{
os=new BufferedOutputStream(new FileOutputStream(file,true)); //true表示文件内容追加
String msg="IO IS EASY";
byte[] bytes=msg.getByts();
os.write(bytes,0,bytes.length);
os.flush();
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}finally{
try{
if(is!=null){
is.close();
}
}catch(){
e.printStackTrace();
}
}
}
}
字符缓冲流
BufferedReader 、 BufferedWriter
public class BufferedTest03{
public static void main(String[] args){
File file=new File("abc.txt");
Reader reader=null;
try{
reader=new BufferedReader(new Reader(file));
String line=null;
while((line=reader.readerLine())!=null){ //逐行读取
System.out.println(line);
}
}
}
}
public class BufferedTest04{
public static void main(String[] args){
File file=new File("abc.txt");
Writer writer=null;
try{
writer=new BufferedWriter(new Writer(file));
writer.append("IO IS EASY");
writer.newLine();
writer.append("海信大厦");
}
}
}
纯文本拷贝:
public class BufferedTest05{
public static void main(String[] args){
File file=new File("abc.txt");
File file=new File("abc2.txt");
Reader reader=null;
Writer writer=null;
try{
reader=new BufferedReader(new Reader(file));
writer=new BufferedWriter(new Writer(file));
String line=null;
while((line=reader.readerLine())!=null){ //逐行读取
writer.writer(line);
writer.newLine();
}
bw.flush();
}
}
}
转换流
InputStreamReader 、 OutputStreamWriter
是字符流和字节流之间的桥梁,能将字节流转换为字符流,并且能为字节流提供字符集,可处理一个个的字符。(字符流必须为纯文本)
//以字符流的形式操作字节流
public class ConvertTest01{
public static void main(String[] args){
//操作System.in和System.out
try{
BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(System.out));
//循环获取键盘的输入,输出此内容
String msg="";
while(!msg.equals("exit")){
msg=reader.readLine();
writer.writer(msg);
writer.newLine();
writer.flush();
}
}catch(IOException e){
System.out.println("操作异常");
}
}
public class ConvertTest01{
public static void main(String[] args){
//操作System.in和System.out
try{
InputStream is=new URL("www.baidu.com").openStream();
BufferedReader reader=
new BufferedReader(
new InputStreamReader(is,"UTF-8"));
String msg=null;
while((msg=reader.readLine())!=null){
System.out.println(msg);
}
}catch(IOException e){
System.out.println("操作异常");
}
}
数据流
DataInputStream 、 DataOutputStream
数据流:
1、写出后读取
2、读取的顺序与写出保持一致
public class DataTest01{
public static void main(){
//写出
ByteArrayOutputStream baos=new ByteArrayOutputStream();
DataOutputStream() dos=new DataOutputStream(new BufferedOutputStream(baos));
dos.writeUTF("一把心酸泪");
dos.writeInt(60);
dos.writeBoolean(false);
dos.writeChar('a');
dos.flush();
byte[] bytes=baos.toByteArray();
//读入
ByteArrayInputStream baos=new ByteArrayInputStream(bytes);
DataInputStream dis=new DataInputStream(new BufferedInputStream(baos));
//读入的顺序要与写出保持一致
String ms=dis.readUTF();
int i=dis.readInt();
Boolean flag=dis.readBoolean();
Char c=dis.readChar();
System.out.println(...);
}
IO对象流
ObjectInputStream 、 ObjectOutputStream
对象经过序列化转换为流
流经过反序列化转换为对象
transient关键字修饰的属性不需要序列化。
序列化又叫持久化。
不是所有的对象都可以序列化,实现Serializable接口
public class ObjectTest01{
public static void main(String[] args){
//写出
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream() dos=new ObjectOutputStream(new BufferedOutputStream(baos));
dos.writeUTF("一把心酸泪");
dos.writeInt(60);
dos.writeBoolean(false);
dos.writeChar('a');
dos.writeObject("满纸荒唐言");
dos.writeObject(new Date());
dos.flush();
byte[] bytes=baos.toByteArray();
//读入
ByteArrayInputStream baos=new ByteArrayInputStream(bytes);
ObjectInputStream dis=new ObjectInputStream(new BufferedInputStream(baos));
//读入的顺序要与写出保持一致
String ms=dis.readUTF();
int i=dis.readInt();
Boolean flag=dis.readBoolean();
Char c=dis.readChar();
Object str=dis.readObject();
Object date=dis.readObject();
if(str instanceof String){
String str=(String)str;
}
if(date instanceof Date){
Date date=(String)date;
}
System.out.println(...);
}
}
IO打印流
PrintStream 、PrintWriter
public class PrintTest01{
public static void main(String[] args){
//打印流System.out
PrintStream ps=System.out;
ps.println("打印流");
ps=new PrintStream(new BufferedOutputStream(new FileOutputStream("print.txt")));
ps.println("打印流");
ps.flush();
}
}
IO 文件分割
RandomAccessFile 支持读取和写入随机访问文件
public class RandomTest01{
public static void main(String[] args){
RandomAccessFile raf=new RandomAccessFile("copy.java", "r");
//随机读取
raf.seek(2); //从第二个字节开始读取
byte[] flush=new byte[1024];
int len=-1;
while((len=raf.read(flush))!=-1){
System.out.println(new String(flush,0,flush.length));
}
raf.close();
}
public static spilt(int i,int beginPos,int actualSize){
RandomAccessFile raf=new RandomAccessFile("copy.java", "r");
RandomAccessFile raf2=new RandomAccessFile("/"+i+"/copy2.java", "rw");
raf.seek(beginPos);
byte[] flush=new byte[1024];
int len=-1;
while((len=raf.read(flush))!=-1){
if(len<actual){
System.out.println(new String(flush,0,flush.length));
raf2.write(flush,0,flush.length);
actual-=len;
}else{
raf.write(flush.0,actualSize);
System.out.println(new String(flush,0,flush.length));
break;
}
}
raf.close();
}
public static void test2(){
File file=new File("copy.txt");
long len=file.length();
int blockSize=1024;
int size=(int)Math.ceil(len*1.0/blockSize);
//起始位置和实际大小
int beginPos=0;
int actualSize=(int)blockSize>size?len:blockSize;
for(int i=0;i<size;i++){
blockSize=i*blockSize;
if(i==(size-1)){
actualSize=(int)len;
}else{
actualSize=blockSize;
len=len-actualSize;
}
spilt(i,beginPos,actualSize);
}
}
}
面向对象思想封装: 分割
public class SplitFile{
//源头
private File src;
//目的地
private String destDir;
//所有分割后的文件存储路径
private List<String> destPaths;
//每块大小
private long blockSize;
//块数:多少块
private int size;
//文件大小
private long len; public SplitFile(String srcPath,String destDir,int blockSize){
this.src=new File(srcPath);
this.destDir=destDir;
this.blockSize=blockSize;
this.destPaths=new ArrayList<String>();
this.len=this.src.length();
init();
}
//初始化
public void init(){
size=(int)Math.ceil(len*1.0/blockSize);
//路径
for(int i=0;i<size;i++){
this.destPaths.add(this.destDir+"/"+i+"-"+this.src.getName());
}
}
//计算每一块的起始位置和大小
public void split() throws IOException{
//起始位置和实际大小
int beginPos=0;
int actualSize=(int) (blockSize>len?len:blockSize); for(int i=0;i<size;i++){
beginPos=(int) (i*blockSize);
if(i==(size-1)){
actualSize=(int)len;
}else{
actualSize=(int) blockSize;
len=len-actualSize;
}
spilt(i,beginPos,actualSize);
}
}
public void spilt(int i,int beginPos,int actualSize) throws IOException{
RandomAccessFile raf=new RandomAccessFile(this.src, "r");
RandomAccessFile raf2=new RandomAccessFile(this.destPaths.get(i), "rw");
raf.seek(beginPos);
byte[] flush=new byte[1024];
int len=-1;
while((len=raf.read(flush))!=-1){
if(len<=actualSize){
raf2.write(flush,0,len);
actualSize-=len;
}else{
raf.write(flush,0,actualSize);
break;
}
}
raf.close();
}
public static void main(String[] args) throws IOException{
SplitFile sf=new SplitFile("p.jpg","dest",1024*10);
sf.split();
}
}
文件合并
public void merge(String destPath){
//输出流
OutputStream os=new BufferedOutputStream(new OutputStream(destPath));
//输入流
for(int i=0;i<destPaths.size;i++){
InputStream is=new BufferedInputStream(new InputStream(destPaths.get(i)));
byte[] flush=new byte[1024];
int len=-1;
while((len=os.read(flush))!=-1){
os.write(flush);
}
os.flush();
is.close();
}
os.close();
}
SequenceInputStream类
public void merge(String destPath){
//输出流
OutputStream os=new BufferedOutputStream(new OutputStream(destPath));
Vector<InputStream> vi=new Vector<InputStream>();
SequenceInputStream sis=null;
//输入流
for(int i=0;i<destPaths.size;i++){
vi.add(new BufferedInputStream(new InputStream(destPaths.get(i))));
}
sis=new SequenceInputStream(vi.elements);
byte[] flush=new byte[1024];
int len=-1;
while((len=sis.read(flush))!=-1){
os.write(flush);
}
os.flush();
sis.close();
os.close();
}
CommonsIO类
环境搭建
多个jar放到一起,简称组件!
CommonsIO是对IO的封装。
commons-io-2.6.jar
文件大小
public class CIOTest01{
public static void main(String[] args){
//文件大小
long len=FileUtils.sizeOf(new File("a.png"));
//目录大小
len =FileUtils.sizeOf(new File("c"));
}
}
读取目录
public class CIOTest02{
public static void main(String[] args){
Collection<File> files=FileUtils.list(new File("c"),
EmptyFileFilter.NOT_EMPTY,
null);//非空目录
Collection<File> files=FileUtils.list(new File("c"),
EmptyFileFilter.NOT_EMPTY,
DirectoryFileFilter.INSTANCE); //所有子孙集
Collection<File> files=FileUtils.list(new File("c"),
new SuffixFileFilter("java"),
DirectoryFileFilter.INSTANCE); //所有java后缀文件
Collection<File> files=FileUtils.list(new File("c"),
FileFilterUtils.or(new SuffixFileFilter("java"),new SuffixFileFilter("class")),
DirectoryFileFilter.INSTANCE); //所有java和class后缀文件
Collection<File> files=FileUtils.list(new File("c"),
FileFilterUtils.or(new SuffixFileFilter("java"),
new SuffixFileFilter("class"),
EmptyFileFilter.EMPTY),
DirectoryFileFilter.INSTANCE); //所有java和class后缀或空文件
Collection<File> files=FileUtils.list(new File("c"),
FileFilterUtils.and(new SuffixFileFilter("java"),
EmptyFileFilter.NOT_EMPTY),
DirectoryFileFilter.INSTANCE); //所有java并且非空后缀文件
}
}
读取文件
public class CIOTest03{
public static void main(String[] args){
//读取文件
String msg=FileUtils.readFileToString(new File("a.txt"),"utf-8"); //读取成字符串
System.out.println(msg);
byte[] bytes=FileUtils.readFileToByteArray(new File("a.txt")); //读取成字节数组
System.out.println(bytes.length);
List<String> msgs=FileUtils.readLines(new File("a.txt"),"utf-8")); //逐行读取
for(String str: msgs){
System.out.println(str);
}
LineIterator it =FileUtils.lineIterator(new File("a.txt"),"utf-8")); //逐行读取
while(it.hasNext()){
System.out.println(it.nextLine());
}
}
}
写出内容
public class CIOTest04{
public static void main(String[] args){
//写出文件
FileUtils.write(new File("b.txt"),"都云作者痴,谁解其中味","UTF-8",true);
FileUtils.writeStringToFile(new File("b.txt"),"都云作者痴,谁解其中味","UTF-8",true);
FileUtils.writeByteArrayToFile(new File("b.txt"),"都云作者痴,谁解其中味".getBytes("UTF-8"),true);
//写出列表
List<String> list=new ListArray<String>();
list.add("元春");
list.add("惜春");
list.add("探春");
FileUtils.writeLines(new File("b.txt"),list,"...",true);
}
}
拷贝
public class CIOTest05{
public static void main(String[] args){
//文件复制
FileUtils.copyFile(new File("c.png"), new File("c-cp.png"));
//复制文件到目录
FileUtils.copyFileToDirectory(new File("c.png"), new File("d"));
//复制目录到文件夹
FileUtils.copyDirectoryToDirectory(new File("d"), new File("e"));
//直接复制目录
FileUtils.copyDirectory(new File("d"), new File("f"));
//拷贝URL内容至文件
FileUtils.copyURLToFile(new URL("www.baidu.com"), new File("a.txt"));
//将URL转换为字符串
String datas=IOUtils.toString(new URL("http://www.baidu.com"),"UTF-8");
System.out.println(datas);
}
参考视频:https://www.bilibili.com/video/av31433959/?p=1
---------------------完结---------------------------