引入:生活中我们下载/上传就是IO操作的过程。这就是IO流,其实就是一连串动态数据的集合。
前提知识:
必须先说明IO理解必须分为网络IO和磁盘IO
网络IO的理解:
关于BIO、NIO、AIO的理解参考:https://www.cnblogs.com/barrywxx/p/8430790.html
以下的单纯是IO磁盘的理解
数据源(data source)的理解:提供原始数据的原始媒介,常见的:数据库、文件、其他程序、内存、网络连接、IO设备。
在整个java.IO包中最后重要的5个类:File,文件类;InputStream,字节输入流;OutputStream,字节输出流;Reader,字符输入流;Writer,字节输出流;
3个接口:Closeable,关闭流接口;Flushable,刷新流接口;Serializeable,序列化接口。
上面就提出两个概念:
字节流:按照字节读取数据,如InputStream,OutputStream;适合音频、视频、execl等文件必须用这个
字符流:按照字符读取数据,如:Reader,Writer;这是因为文件的编码不同,从而有了对字符进行高效操作的的字符流对象。但是说到底原理还是字节流。能用字符流的都可以用字节流。这个字符流仅仅适合字符文件
java.IO包下的内容:(上面的只是一部分,有时间得去研究更多)
File路径构建的方式:(三种常见方式)
package com.stu.io;
import java.io.File;
public class Mytest1 {
public static void main(String[] args) {
String path = "E:/ownStudy/IOStudy/IO.PNG";
// 1,构建file对象
File src = new File(path);
System.out.println(src);
// 2,构建file对象
src = new File("E:/ownStudy/IOStudy","IO.PNG");
System.out.println(src);
// 3,构建file对象
src = new File(new File("E:/ownStudy/IOStudy"),"IO.PNG");
System.out.println(src);
}
}
运行结果:
File的源码有700多行,这里实现不好拿出来说,建议看着的时候去打开File.class查看源码;
这里介绍起其中的方法:
getName : 获取file的名称;
getPath:获取file路径(这里的路径取决于你构建的路径)
getAbsolutePath:返回绝对路径。
getParent:返回父路径
exists:判断是否存在
isFile:判断是否是一个文件。
isDirectory:是检查一个对象是否是文件夹;
createNewFile:不存在下,创建文件
delete:删除已经存在的文件等等;
length:返回文件的情况下文件字节数
package com.stu.io;
import java.io.File;
public class Mytest1 {
public static void main(String[] args) {
String path = "E:/ownStudy/IOStudy/IO.PNG";
File src = new File(path);
System.out.println("名称: " + src.getName());
System.out.println("绝对路径:" + src.getAbsolutePath());
System.out.println("路径: " + src.getPath());
System.out.println("父对象: " + src.getParentFile());
System.out.println("存在是否?: " + src.exists());
System.out.println("文件是否?:" + src.isFile());
System.out.println("目录是否?:" + src.isDirectory());
// 通常操作逻辑
if(!src.exists()) {
System.out.println("文件不存在");
} else {
if (src.isFile()) {
System.out.println("执行文件操作");
} else {
System.out.println("执行文件夹操作");
}
}
}
}
运行结果:
创建目录
这里改了风格,改用IDEA编辑软件;
package com.bytecode.stu;
import java.io.File;
public class Main {
public static void main(String[] args) {
// 创建目录mkdir,mkdirs创建目录一个是存在路径下目录,一个是不存在父目录也可以创建父目录及创建目录。
// list 下级名称,listFiles 下级File,listRoots 根路径
File dir = new File("E:/ownStudy/dir/test"); // 路径下没有dir
boolean fflag = dir.mkdir();
boolean flag = dir.mkdirs();
System.out.println(fflag);
System.out.println(flag);
}
}
运行结果:
import java.io.File;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
// 创建目录mkdir,mkdirs创建目录一个是存在路径下目录,一个是不存在父目录也可以创建父目录及创建目录。
// list 下级名称,listFiles 下级File,listRoots 根路径
File dir = new File("E:/ownStudy");
String[] strs = dir.list();
Arrays.asList(strs).forEach(t->{System.out.println(t);});
System.out.println("------------------");
File[] files = dir.listFiles();
Arrays.asList(files).forEach(t->{System.out.println(t);});
}
}
运行结果:(如果是深层次目录利用递归找到即可)
流的操作过程(重要)–字节流
创建源 - 》 选择流 - 》 操作 (读写)- 》 释放。
读操作的体现
package com.ss.nn;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class JStest {
public static void main(String[] args) throws IOException {
// 创建源 - > 选择流 - > 操作 (读写)- > 释放。
// 创建源
File src = new File("aa.txt");
// 选择流
InputStream ism = null;
try {
ism = new FileInputStream(src);
// 读操作
int temp = 0;
while ((temp = ism.read()) != -1) { // read(),返回单个字符
System.out.print((char)temp + " "); // 强转为字符
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (null != ism) {
// 关闭流
ism.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
运行结果:(可见这一个一个的读取,效率是不高的)
由上面可以,我们利用byte[] 缓冲来解决。
package com.ss.nn;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class JStest {
public static void main(String[] args) throws IOException {
// 创建源 - > 选择流 - > 操作 (读写)- > 释放。
// 创建源
File src = new File("aa.txt");
// 选择流
InputStream ism = null;
try {
ism = new FileInputStream(src);
// 读操作(分段读取)
int len = -1; // 接收到的长度
byte[] bytes = new byte[4]; // 缓存中放四个
while ((len = ism.read(bytes)) != -1) {
String strs = new String(bytes,0,len);
System.out.println(strs);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (null != ism) {
// 关闭流
ism.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
运行结果:
写操作的体现:
package com.ss.nn;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class JStest {
public static void main(String[] args) throws IOException {
// 创建源 - > 选择流 - > 操作 (读写)- > 释放。
// 创建源
File src = new File("bb.txt");
// 选择流
OutputStream osm = null;
try {
osm = new FileOutputStream(src,true); // 设置为真,保证可以对文件内容的追加,不会覆盖原有的数据。
String aha = "nihao,shahahah";
// 假写一个读的过程
byte[] bytes = aha.getBytes();
// 写操作
osm.write(bytes, 0, aha.length());
osm.flush(); // 冲刷保证数据完全写入
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (null != osm) {
// 关闭流
osm.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
运行结果:
上面整合(就是我们常见的文件copy,)–利用递归做文件夹的拷贝。
package com.ss.nn.mm;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class OperateFile {
/**
* 文件拷贝
* @param srcPath 被拷贝文件
* @param destPath 拷贝至该目标
* @throws zhouyi
*/
public void fileCopy(String srcPath,String destPath) throws IOException {
InputStream ism = null;
OutputStream os = null;
try {
ism = new FileInputStream(new File(srcPath));
os = new FileOutputStream(new File(destPath));
int len = -1;
byte[] bytes = new byte[1024];
while ((len = ism.read(bytes)) != -1) {
os.write(bytes, 0, bytes.length);
}
os.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (null != os) {
os.close();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (null != ism) {
ism.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
上面这个方法,由于是字节流的,可以copy任何东西,图片,电影等。
流的操作过程(重要)–字符流
好处是不用转换,也能很好避免编码乱码的的问题。
package com.ss.nn.mm;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
public class OperateFile {
/**
* 文件拷贝:上面的字节流,当内容中英文时会乱码,这就需要字符流来操作。
* 局限:只能应用于字符文件,不能是图片等。
* @param srcPath 被拷贝文件
* @param destPath 拷贝至该目标
* @throws zhouyi
*/
public void fileCopy(String srcPath,String destPath) throws IOException {
Reader reader = null;
Writer writer = null;
try {
reader = new FileReader(new File(srcPath));
writer = new FileWriter(new File(destPath));
int len = -1;
char[] bytes = new char[1024];
while ((len = reader.read(bytes)) != -1) {
writer.write(bytes, 0, bytes.length);
}
writer.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (null != reader) {
reader.close();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (null != writer) {
writer.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
ByteArrayOutputStream/ ByteArrayInputStream 字节数组(底层框架经常用)
1,不需要关闭,因此不要太大(最好还是关闭的好);可以操作任何文件(因为是二进制)
package com.ss.nn.mm;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class OperateFile {
/**
* 文件转成字节流
* @param srcPath 被拷贝文件
* @param destPath 没有意义
* @throws zhouyi
*/
public byte[] fileToByteArray(String srcPath,String destPath) throws IOException {
InputStream bais = null; // 也是可以的
ByteArrayOutputStream baos = null;
try {
bais = new FileInputStream(new File(srcPath));
//不需要dest 需要使用toByteArray()去获得字节数组或者toString得到字符串
baos = new ByteArrayOutputStream();
int len = 0;
byte[] bytes = new byte[1024];
while ((len = bais.read(bytes)) != -1) {
baos.write(bytes, 0, len);
}
baos.flush();
byte[] data = baos.toByteArray();
return data;
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (null != bais) {
bais.close();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (null != baos) {
baos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
/**
* 字节流转成文件
* @param data 字节数组
* @param srcPath 写入路径
*/
public void byteArrayToFile(byte[] data,String srcPath) {
InputStream is = null;
OutputStream os = null;
try {
is = new ByteArrayInputStream(data);
os = new FileOutputStream(srcPath);
byte[] bytes = new byte[1024];
int len = -1;
while ((len = is.read(bytes)) != -1) {
os.write(bytes, 0, len);
}
os.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != os) {
os.close();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (null != is) {
is.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
package com.ss.nn;
import java.io.IOException;
import java.util.Arrays;
import com.ss.nn.mm.OperateFile;
public class JStest {
public static void main(String[] args) throws IOException {
OperateFile tt = new OperateFile();
byte[] data = tt.fileToByteArray("bb.txt", "zhouyi.txt");
System.out.println(Arrays.toString(data));
tt.byteArrayToFile(data, "zhouyi.txt");
}
}
以上都是成功运行了的。接下来是学习common_IO的中介过程,理解他是怎么来的。
package com.ss.nn.mm;
import java.io.ByteArrayInputStream;
import java.io.Closeable;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 封装
* @author zhouyi
*
*/
public class FileUtils {
/**
* 对接输入输出流
* @param is
* @param os
* @throws IOException
*/
public void fileCopy(InputStream is,OutputStream os) throws IOException {
try {
int len = -1;
byte[] bytes = new byte[1024];
while ((len = is.read(bytes)) != -1) {
os.write(bytes, 0, bytes.length);
}
os.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
/**
* 关闭流
* @param ios
*/
public void close(Closeable... ios) { // 可变参数
for(Closeable io : ios) {
try {
if (null != io) {
io.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
package com.ss.nn;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import com.ss.nn.mm.FileUtils;
public class JStest {
public static void main(String[] args) throws IOException {
FileUtils fileUtils = new FileUtils();
InputStream is = new FileInputStream("bb.txt");
OutputStream os = new FileOutputStream("zhouyi.txt");
fileUtils.fileCopy(is, os);
fileUtils.close(is,os);
}
}
上面这种封装思想就是common_IO包的来由。
BufferedInputStream/BufferedOutputStream
package com.ss.nn;
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;
/**
* BufferedInputStream/BufferedOutputStream
* 这是缓冲流,有一定缓冲内存,当满了的时候才会一次性写出,提高了速度和性能
* 需要使用InputStream/OutputStream来过渡。即是需要套嵌节点流
* @author zhouyi
*
*/
public class MyTest1 {
/**
* 文件拷贝
* @param srcPath 被拷贝文件
* @param destPath 拷贝至该目标
* @throws zhouyi
*/
public void fileCopy(String srcPath,String destPath) throws IOException {
BufferedInputStream is = null;
BufferedOutputStream os = null;
try {
is = new BufferedInputStream(new FileInputStream(new File(srcPath)));
os = new BufferedOutputStream(new FileOutputStream(new File(destPath)));
int len = -1;
byte[] bytes = new byte[1024];
while ((len = is.read(bytes)) != -1) {
os.write(bytes, 0, bytes.length);
}
os.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (null != os) {
os.close();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (null != is) {
is.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
BufferedReader/BufferedWriter
相同操作。
BufferedReader reader = null;
BufferedWriter writer = null;
try {
reader = new BufferedReader(new FileReader(new File(srcPath)));
writer = new BufferedWriter(new FileWriter(new File(destPath)));
String line = null;
while ((line = reader.readLine()) != null) { // 逐行读入
writer.write(line, 0, line.length());
}
writer.flush();
转换流OutputStreamWriter/InputStreamReader
字符流和字节流的转换桥梁。
public class JStest {
public static void main(String[] args) throws IOException {
try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));) { // 这是java7的写法
//获取键盘输入
String str = "";
while (!str.equals("exit")) {
str = reader.readLine();// 读入一行
writer.write(str); // 写出一行
writer.newLine(); // 写出为新行
writer.flush();// 这是为了防止较小时,没有满足缓存大小,而不写出。
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
下载网络流:
public class JStest {
public static void main(String[] args) throws IOException {
// BufferedReader is = new BufferedReader(new InputStreamReader(new URL("http://www.baidu.com").openStream(),"UTF-8"));最好的写法
try(InputStreamReader is = new InputStreamReader(new URL("http://www.baidu.com").openStream(),"UTF-8");) { // 这是java7的写法
int temp = 0; // 上面不写成InputStreamReader,并不设置UTF-8就有乱码问题
while ((temp = is.read()) != -1) {
System.out.print((char)temp);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
数据流 DataOutputStream/DataInputStream
注意点:写出后读取,必须保证写出和读取的顺序一致。代码和上面的差不多,不给出。
对象流-ObjectOutputStream/ObjectInputStream(序列化的对的想才能支持对象流)
使用和 数据流的注意事项一样,除了序列化要求。
打印流 --PrintStream或者PrintWriter
上面的所有就是为了建立思维。真正应用还是下面。commonIO工具包。