IO介绍
以程序为中心,文件、内存、网络连接、数据库、设备将流输入到程序叫输入流。反之将程序的内容输出到文件等叫输出流。
举个例子:你阅读一本书写了一篇观后感,阅读书就是讲只是输入到大脑,写观后感就是将大脑的存储的知识进行输出。
核心类:
类 | 说明 |
---|---|
File | 文件类 |
InputStream | 字节输入流 |
OutputStream | 字节输出流 |
Reader | 字符输入流 |
Writer | 字符输出流 |
Closeable | 关闭流接口 |
Flushable | 输出流接口 |
Serializable | 序列化接口 |
File
基本语法
路径的写法
String path= "D:\\Program Files\\JetBrains";
(建议写法)
String path= "D:/Program Files/JetBrains";
构建File对象
public class FileDemo {
public static void main(String[] args) {
//1
String path = "D:/file/csdn-logo.png";
File file = new File(path);
System.out.println(file.length());
//2
File file1 = new File("D:/file","csdn-logo.png");
File file2 = new File("D:","file/csdn-logo.png");
System.out.println(file1.length());
System.out.println(file2.length());
//3
File file3 = new File(new File("D:/file"),"csdn-logo.png");
File file4 = new File(new File("D:"),"file/csdn-logo.png");
System.out.println(file3.length());
System.out.println(file4.length());
//4
File file5 = new File("https://csdnimg.cn/cdn/content-toolbar/csdn-logo.png?v=20200416.1");
System.out.println(file5.length());
}
}
运行结果:
4990
4990
4990
4990
4990
0
常用文件操作方法
常用文件夹操作方法
遍历文件
/**
* 递归循环遍历文件夹
*/
class FileDemo2{
public static void main(String[] args) {
String path = "E:/woody/spring1";
printFileName(new File(path));
}
public static void printFileName(File src){
if(null == src || !src.exists()){
return;
}
if(!src.isDirectory()){
System.out.println(src.getName());
}else{
File[] files = src.listFiles();
for (File f: files) {
printFileName(f);
}
}
}
}
文件编码
字符集
各种字符集实际上就是不同的字典。
编码:字符转换成字节的过程
解码:字节转换成字符的过程
乱码原因
- 字节数组给的不够,比如“你好”,使用utf-8编码后的字节长度是6,解码的时候入参长度传5,那么“好”字就会乱码
- 使用的字符集不一致,比如“你好”,使用utf-8编码后的字节长度是6,解码的时候使用UTF-16LE,因为UTF-16LE是定长2字节的,所以解码的时候会解析三次导致乱码。
IO流
整体概况
关键的四个类
PS:音频、视频、Excel等只能使用字节流。
Closeable接口
inputstream、outputstream类实现了Closeable接口,Java操作文件的时候不能直接操作文件,而是通过操作系统进一步操作文件的,此处的closeable接口不是Java直接释放资源,而是通知操作系统可以释放资源,真正的释放资源是操作系统执行的。
Flushable接口
outputstream类实现了flushable接口,写文件时候操作系统的计数器有一定的规则,比如达到8k才输出出去,如果没有达到则注入到内存中,所以flushable能避免数据注入到内存中,当然close的时候也是会强制刷新的。
字节流
InputStream操作
public class IODemo {
public static void main(String[] args) {
//1、创建源 abc.txt 里面的内容为sex
File src = new File("E:/woody/abc.txt");
//2、选择流
try {
InputStream is = new FileInputStream(src);
//3、操作
int data1 = is.read();
int data2 = is.read();
int data3 = is.read();
int data4 = is.read();//不是数据,文件的末尾返回-1
System.out.println((char)data1);
System.out.println((char)data2);
System.out.println((char)data3);
System.out.println(data4);
//4、释放
is.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出结果:
s
e
x
-1
class IODemo1 {
public static void main(String[] args) {
//1、创建源 abc.txt 里面的内容为sex
File src = new File("E:/woody/abc.txt");
//2、选择流
InputStream is = null;
try {
is = new FileInputStream(src);
//3、操作
int temp;
while ((temp = is.read()) != -1){
System.out.println((char)temp);
}
//4、释放
is.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(null != is){
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
输出结果:
s
e
x
通过读取数据到缓冲数组方式:
//3、操作
byte[] flush = new byte[1024];
int len;
while ((len = is.read(flush)) != -1){
System.out.println(new String(flush,0,len));
}
OutputStream操作
class IODemo3 {
public static void main(String[] args) {
//1、创建源
File dest = new File("E:/woody/dest.txt");
OutputStream os = null;
try {
//2、选择流
os = new FileOutputStream(dest);
//os = new FileOutputStream(dest,true);//追加模式,在文本后面继续追加内容,默认为false
String msg = "i love you";
byte[] bytes = msg.getBytes();
//3、操作
os.write(bytes,0 , bytes.length);
os.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//4、释放资源
if(null != os){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
字符流
FileReader
通过字符的方式读取文件,仅适合字符文件。
/**
* 字符输入流
*/
class IODemo4 {
public static void main(String[] args) {
//1、创建源 abc.txt 里面的内容为sex
File src = new File("E:/woody/abc.txt");
//2、选择流
Reader reader = null;
try {
reader = new FileReader(src);
//3、操作
char[] flush = new char[1024];
int len;
while ((len = reader.read(flush)) != -1){
System.out.println(new String(flush,0,len));
}
//4、释放
reader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(null != reader){
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
输出结果:sex
FileWriter
通过自己的方式写出或追加到文件中,仅适合字符文件。
/**
* 字符输出流
*/
class IODemo5 {
public static void main(String[] args) {
//1、创建源
File dest = new File("E:/woody/dest.txt");
Writer writer = null;
try {
//2、选择流
writer = new FileWriter(dest);
String msg = "i love 妈妈啊";
String msg1 = "i love 爸爸啊";
//3、操作(方法一)
//char[] bytes = msg.toCharArray();
//writer.write(bytes,0 , bytes.length);
//3、操作(方法二)
//writer.write(msg);
//3、操作(方法三)
writer.append(msg).append(msg1);
writer.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//4、释放资源
if(null != writer){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
字节数组流
字节数组流与前面提到的FileXXX的区别是,FileXXX的是操作的是存储硬盘中的,需要通过操作系统来操作文件,释放资源是通知操作系统进行释放。而字节数组流操作流是存放在内存中的,因此释放是由jvm 的垃圾回收操作的,因此不需要手动释放。
ByteArrayInputStream
/**
* 字节数组输入流
*/
class IODemo6 {
public static void main(String[] args) {
//1、创建源
byte[] src = "i love you".getBytes();
InputStream is = null;
try {
//2、选择流
is = new ByteArrayInputStream(src);
//3、操作
byte[] flush = new byte[1024];
int len = -1;
while((len = is.read(flush,0,flush.length)) != -1){
System.out.println(new String(flush));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出结果:i love you
ByteArrayOutputStream
/**
* 字节数组输出流
*/
class IODemo7 {
public static void main(String[] args) {
ByteArrayOutputStream baos = null;
try {
//2、选择流
baos = new ByteArrayOutputStream();
String msg = "i love you";
byte[] datas = msg.getBytes();
//3、操作
baos.write(datas,0 , datas.length);
baos.flush();
//4、获取数据
System.out.println(baos.toByteArray());
System.out.println(baos.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出结果:
[B@610455d6
i love you
缓冲流
增加了缓存机制,使用的是装饰模式实现的。
- 目的是为了提升性能
- 底层一定是节点流
- 关闭的时候由里到外关闭,实际上装饰流在关闭的时候会自动关闭内部的节点流
- 默认缓存8K
字节缓冲流
BufferedInputStream
BufferedOutbputStream
/**
- 字节装饰输入流
*/
class IODemo8 {
public static void main(String[] args) {
//1、创建源 abc.txt 里面的内容为sex
File src = new File("E:/woody/abc.txt");
//2、选择流
InputStream is = null;
try {
//关键
is = new BufferedInputStream(new FileInputStream(src));
//3、操作
byte[] flush = new byte[1024];
int len;
while ((len = is.read(flush)) != -1){
System.out.println(new String(flush,0,len));
}
//4、释放
is.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(null != is){
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
字符缓冲流
BufferedReader
新增了readLine()逐行读取方法。
BufferedWriter
新增了newLine()方法
BufferedReader示例:
/**
* 字符缓冲输入流
*/
class IODemo9 {
public static void main(String[] args) {
//1、创建源 abc.txt 里面的内容为sex
File src = new File("E:/woody/abc.txt");
//2、选择流
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(src));
//3、操作
String line = null;
while ((line = reader.readLine()) != null){
System.out.println(line);
}
//4、释放
reader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(null != reader){
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
BufferedWriter实例:
/**
* 字符缓冲输出流
*/
class IODemo10 {
public static void main(String[] args) {
//1、创建源
File dest = new File("E:/woody/dest.txt");
BufferedWriter writer = null;
try {
//2、选择流
writer = new BufferedWriter(new FileWriter(dest));
String msg = "i love 妈妈啊";
String msg1 = "i love 爸爸啊";
writer.append(msg);
writer.newLine();
writer.append(msg1);
writer.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//4、释放资源
if(null != writer){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
转换流
- 以字符流的方式操作字节流
- 指定字符集
InputStreamReader
OutPutStreamWriter
转换流示例:
/**
* 转换流
*/
class IODemo11 {
public static void main(String[] args) {
try{
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
String line = "";
while(!line.equals("exit")){
line = reader.readLine();
writer.write(line);
writer.newLine();
writer.flush();
}
}catch(IOException e){
e.printStackTrace();
}
}
}
转换流指定字符集示例:爬取网页保存为文件
class IODemo12 {
public static void main(String[] args) {
BufferedReader reader = null;
BufferedWriter writer = null;
try{
reader = new BufferedReader(new InputStreamReader(new URL("https://www.baidu.com/").openStream(),"utf-8"));
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("E:/woody/baidu.html"),"utf-8"));
String msg;
while((msg = reader.readLine()) != null){
writer.write(msg);
writer.newLine();
writer.flush();
}
}catch (MalformedURLException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}finally {
if(reader != null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(writer != null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
数据流
保留了数据类型,方便后期的处理,读写顺序必须保持一致
DataInputStream
DataOutputStream
对象流
必须实现序列化接口的才能用
ObjectInputStream
ObjectOutputStream
打印流
PrintStream
System.out.print就是一个打印流
CommonsIo
常用方法
FileUtils.sizeOf()
计算文件或者文件夹的大小
long len = FileUtils.sizeOf(new File("E:/woody/baidu.html"));
FileUtils.listFiles()
遍历子孙集,第二个参数过滤文件,比如可以设置后缀名或者非空等等,第三个参数控制目录
Collection<File> files = FileUtils.listFiles(new File("E:/woody/"), EmptyFileFilter.NOT_EMPTY, DirectoryFileFilter.INSTANCE);
for (File file:files) {
System.out.println(file.getAbsoluteFile());
}
FileUtils.readFileToString
读取文件
String msg = FileUtils.readFileToString(new Filee("E:/woody/baidu.html"),"utf-8");
FileUtils.readLines
//逐行读取
List<String> msgs = null;
try {
msgs = FileUtils.readLines(new File("E:/woody/baidu.html"),"utf-8");
} catch (IOException e) {
e.printStackTrace();
}
for(String str :msgs){
System.out.println(str);
}
FileUtils.lineIterator
//迭代器逐行读取
try {
LineIterator it = FileUtils.lineIterator(new File("E:/woody/baidu.html"),"utf-8");
while (it.hasNext()){
System.out.println(it.nextLine());
}
} catch (IOException e) {
e.printStackTrace();
}
写文件
//写文件,最后一个参数表示是否追加
try {
FileUtils.write(new File("E:/woody/commonsio.txt"),"生命诚可贵\n","utf-8",true);
FileUtils.writeStringToFile(new File("E:/woody/commonsio.txt"),"爱情价更高\n","utf-8",true);
FileUtils.writeByteArrayToFile(new File("E:/woody/commonsio.txt"),"若为自由故\n".getBytes("utf-8"),true);
List<String> list = new ArrayList<String>();
list.add("窗前明月光\n");
list.add("疑是地上霜\n");
list.add("举头望明月\n");
FileUtils.writeLines(new File("E:/woody/commonsio.txt"),list,",",true);
} catch (IOException e) {
e.printStackTrace();
}
文件拷贝
//拷贝文件
try {
//拷贝文件
FileUtils.copyFile(new File("E:/woody/commonsio.txt"),new File("E:/woody/commonsio-copy.txt"));
//拷贝文件至目录下
FileUtils.copyToDirectory(new File("E:/woody/commonsio.txt"),new File("E:/woody/sub/"));
//拷贝目录至目录下
FileUtils.copyDirectoryToDirectory(new File("E:/woody/"),new File("E:/woody/sub/"));
//拷贝目录
FileUtils.copyDirectoryToDirectory(new File("E:/woody/"),new File("E:/woody2"));
//拷贝URL内容
String url = "https://csdnimg.cn/cdn/content-toolbar/csdn-logo.png";
FileUtils.copyURLToFile(new URL(url),new File("E:/woody/csdn-logo.png"));
//拷贝URL文本
String datas = IOUtils.toString(new URL("https://www.baidu.com"),"utf-8");
} catch (IOException e) {
e.printStackTrace();
}