目录
IO流概述
IO流也称为输入、输出流,就是用来读写数据的。
- I表示intput,是数据从硬盘文件读入到内存的过程,称之输入,负责读。
- O表示output,是内存程序的数据从内存到写出到硬盘文件的过程,称之输出,负责写。
流的四大类:
- 字节输入流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流称为字节输入流。
- 字节输出流:以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中去的流称为字节输出流。
- 字符输入流:以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入到内存中去的流称为字符输入流。
- 字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中去的流称为字符输出流。
字节流的使用
文件字节输入流:每次读取一个字节
文件字节输入流:FileInputStream
作用:以内存为基准,把磁盘文件中的数据以字节的形式读取到内存中去。
问题:慢、读取中文字符输出无法避免乱码问题。
public FileInputStream(File file) |
创建字节输入流管道与源文件对象接通 |
public FileInputStream(String pathname) |
创建字节输入流管道与源文件路径接通 |
public int read() |
每次读取一个字节返回,如果字节已经没有可读的返回-1 |
public int read(byte[] buffer) |
每次读取一个字节数组返回,如果字节已经没有可读的返回-1 |
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class InputTest1 {
public static void main(String[] args) throws IOException {
// 1、创建一个文件字节输入流管道与源文件接通。
InputStream is = new FileInputStream("D:\test\demo.txt");
int b;
//2.循环读取文本----一次读一个字节
//public int read(): 每次读取一个字节返回,读取完毕返回-1。
while (( b = is.read() ) != -1){
System.out.print((char) b);
}
}
}
-
小结: 一个一个字节读取中文数据输出其实是被淘汰的,性能极差! 一个一个字节读取中文数据输出,会出现截断中文字节的情况,无法避免读取中文输出乱码的问题。
文件字节输入流:每次读取一个字节数组
文件字节输入流:FileInputStream
作用:以内存为基准,把磁盘文件中的数据以字节的形式读取到内存中去。
问题:读取中文字符输出无法避免乱码问题。如果文件过大,定义的字节数组可能引起内存溢出。
public int read() |
每次读取一个字节返回,如果字节已经没有可读的返回-1 |
public int read(byte[] buffer) |
每次读取一个字节数组返回,如果字节已经没有可读的返回-1 |
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class InputTest2 {
public static void main(String[] args) throws IOException {
//1.创建一个文件字节输入流管道与源文件接通。
InputStream is = new FileInputStream("D:\test\demo2.txt");
//2.字节数组,读取字节数字
byte[] buffer = new byte[3]; //3个字节
int len; // 记录每次读取的字节数。
while ((len = is.read(buffer)) != -1) {
// 读取多少倒出多少
System.out.print(new String(buffer, 0, len));
}
}
}
文件字节输入流:一次读完全部字节
1.自己定义一个字节数组与文件的大小一样大,然后使用读取字节数组的方法,一次性读取完成。
public int read(byte[] buffer) |
每次读取一个字节数组返回,如果字节已经没有可读的返回-1 |
用字母打断汉字
import java.io.*;
public class InputTest3 {
public static void main(String[] args) throws IOException {
File f = new File ("D:\test\demo3.txt");
//1.创建一个文件字节输入流管道与源文件接通。
InputStream is = new FileInputStream(f);
int l = (int) f.length();
byte[] buffer = new byte[l];
int len = is.read(buffer);
System.out.println("文件大小:"+ len);
System.out.println("字节大小:"+l);
System.out.println("输出:"+new String(buffer, 0, len));
}
}
2.官方为字节输入流InputStream提供了如下API可以直接把文件的全部数据读取到一个字节数组中
public byte[] readAllBytes() throws IOException |
直接将当前字节输入流对应的文件对象的字节数据装到一个字节数组返回 |
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
public class InputTest3 {
public static void main(String[] args) throws IOException {
//byte[] buffer = Files.readAllBytes(Paths.get("D:\test\demo3.txt"));
//String s = new String(buffer, 0, buffer.length);
//System.out.println(s);
File f = new File ("D:\test\demo3.txt");
//1.创建一个文件字节输入流管道与源文件接通。
InputStream is = new FileInputStream(f);
byte[] buffer = is.readAllBytes();
String s = new String(buffer, 0, buffer.length);
System.out.println(s);
}
}
文件字节输出流:写字节数据到文件
文件字节输出流:FileOutputStream
作用:以内存为基准,把内存中的数据以字节的形式写出到磁盘文件中去的流。
public FileOutputStream(File file) |
创建字节输出流管道与源文件对象接通 |
public FileOutputStream(File file,boolean append) |
创建字节输出流管道与源文件对象接通,可追加数据 |
public FileOutputStream(String filepath) |
创建字节输出流管道与源文件路径接通 |
public FileOutputStream(String filepath,boolean append) |
创建字节输出流管道与源文件路径接通,可追加数据 |
文件字节输出流(FileOutputStream)写数据出去的API
public void write(int a) |
写一个字节出去 |
public void write(byte[] buffer) |
写一个字节数组出去 |
public void write(byte[] buffer , int pos , int len) |
写一个字节数组的一部分出去。 |
流的关闭与刷新
flush() |
刷新流,还可以继续写数据 |
close() |
关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据 |
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class OutputTest4 {
public static void main(String[] args) throws IOException {
//1.创建一个文件字节输出流管道与目标文件接通
OutputStream os = new FileOutputStream("D:\test\outputTest.txt", true);
// 2、写数据出去
// a.public void write(int a):写一个字节出去
os.write('a');
os.write(98);
os.write("rn".getBytes()); // 兼容性更强,换行
// b.public void write(byte[] buffer):写一个字节数组出去。
byte[] buffer = {'a' , 97, 98, 99};
os.write(buffer);
os.write("rn".getBytes()); // 换行
byte[] buffer2 = "我是中国人".getBytes(); //转成字节
os.write(buffer2);
os.write("rn".getBytes()); // 换行
// c. public void write(byte[] buffer , int pos , int len):写一个字节数组的一部分出去。
byte[] buffer3 = {'a',97, 98, 99};
os.write(buffer3, 0 , 3);
os.write("rn".getBytes()); // 换行
// os.flush(); // 写数据必须,刷新数据 可以继续使用流
os.close(); // 释放资源,包含了刷新的!关闭后流不可以使用了
}
文件拷贝
任何文件的底层都是字节,拷贝是一字不漏的转移字节,只要前后文件格式、编码一致没有任何问题。
import java.io.*;
public class CopyTest5 {
public static void main(String[] args) throws IOException {
//1.创建一个字节输入流管道与文件接通 --待复制文件
InputStream is = new FileInputStream("D:\test\outputTest.txt");
//2.创建一个字节输出流管道与文件接通 --目标文件
OutputStream os = new FileOutputStream("D:\test\outputTest2.txt");
//3.定义一个字节数组复制转移数据
byte[] buffer = new byte[1111];
int len; //记录字节数
while ((len = is.read(buffer)) != -1)
os.write(buffer, 0, len);
System.out.println("复制完成了!!");
os.close(); //复制完成后, 关闭流
}
}
资源释放的方式
try-catch-finally
finally:在异常处理时提供finally块来执行所有清除操作,比如说IO流中的释放资源
- 特点:被finally控制的语句最终一定会执行,除非JVM退出
- 异常处理标准格式:try….catch…finally
- finally代码块是最终一定要执行的,可以在代码执行完毕的最后用于释放资源。
import java.io.*;
public class CopyTest5 {
public static void main(String[] args) {
InputStream is = null;
OutputStream os = null;
try {
//1.创建一个字节输入流管道与文件接通
is = new FileInputStream("D:\test\outputTest.txt");
//2.创建一个字节输出流管道与文件接通
os = new FileOutputStream("D:\test\outputTest2.txt");
//3.定义一个字节数组复制转移数据
byte[] buffer = new byte[1111];
int len; //记录字节数
while ((len = is.read(buffer)) != -1)
os.write(buffer, 0, len);
System.out.println("复制完成了!!");
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
if (os != null) os.close(); //复制完成后, 关闭流
if (os != null) is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
try-with-resource
自动释放资源、代码简洁
资源都是实现了Closeable/AutoCloseable接口的类对象
- public abstract class InputStream implements Closeable {}
- public abstract class OutputStream implements Closeable, Flushable{}
//基本做法---手动释放资源
try{ 可能出现异常的代码;
}catch(异常类名 变量名){
异常的处理代码;
}finally{
执行所有资源释放操作;
}
//资源用完最终自动释放--JDK7
try(定义流对象){
可能出现异常的代码;
}catch(异常类名 变量名){
异常的处理代码;
}
//资源用完最终自动释放--JDK9
try(输入流对象;输出流对象){
可能出现异常的代码;
}catch(异常类名 变量名){
异常的处理代码;
}
import java.io.*;
public class ResourceTest6 {
public static void main(String[] args) {
//JDK7
try (
//1.创建一个字节输入流管道与文件接通
InputStream is = new FileInputStream("D:\test\outputTest.txt");
//2.创建一个字节输出流管道与文件接通
OutputStream os = new FileOutputStream("D:\test\outputTest2.txt");
AutoCloseable connection = new MyConnection(); //会自动调用资源的close方法
){ //3.定义一个字节数组复制转移数据
byte[] buffer = new byte[1111];
int len; //记录字节数
while ((len = is.read(buffer)) != -1)
os.write(buffer, 0, len);
System.out.println("复制完成了!!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
class MyConnection implements AutoCloseable{
@Override
public void close() throws Exception {
System.out.println("资源被释放成功!!!");
}
}
import java.io.*;
public class ResourceTest7 {
//JDK9----用的比较少
public static void main(String[] args) throws FileNotFoundException {
//1.创建一个字节输入流管道与文件接通
InputStream is = new FileInputStream("D:\test\outputTest.txt");
//2.创建一个字节输出流管道与文件接通
OutputStream os = new FileOutputStream("D:\test\outputTest2.txt");
try ( is ; os)
{ //3.定义一个字节数组复制转移数据
byte[] buffer = new byte[1111];
int len; //记录字节数
while ((len = is.read(buffer)) != -1)
os.write(buffer, 0, len);
System.out.println("复制完成了!!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
字符流的使用
文件字符输入流-一次读取一个字符
文件字符输入流:Reader
作用:以内存为基准,把磁盘文件中的数据以字符的形式读取到内存中去
读取中文字符不会出现乱码(如果代码文件编码一致),但性能较慢
构造器
public FileReader(File file) |
创建字符输入流管道与源文件对象接通 |
public FileReader(String pathname) |
创建字符输入流管道与源文件路径接通 |
方法
public int read() |
每次读取一个字符返回,如果字符已经没有可读的返回-1 |
public int read(char[] buffer) |
每次读取一个字符数组,返回读取的字符个数,如果字符已经没有可读的返回-1 |
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class ReaderTest1 {
public static void main(String[] args) throws IOException {
//1.创建一个字符输入流管道与文件接通
Reader f = new FileReader("D:\test\outputTest.txt");
int code;
while ((code = f.read()) != -1)
System.out.print((char)code);
}
}
文件字符输入流-一次读取一个字符数组
文件字符输入流:FileReader
作用:以内存为基准,把磁盘文件中的数据以字符的形式读取到内存中去。
读取中文字符输出不会乱码;读取的性能得到了提升
public int read() |
每次读取一个字符返回,如果字符已经没有可读的返回-1 |
public int read(char[] buffer) |
每次读取一个字符数组,返回读取的字符数,如果字符已经没有可读的返回-1 |
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class ReaderTest2 {
public static void main(String[] args) throws IOException {
//1.创建一个字符输入流管道与文件接通
Reader f = new FileReader("D:\test\outputTest.txt");
char[] buffer = new char[1111];
int len;
while ((len = f.read(buffer)) != -1)
System.out.println(new String(buffer, 0, len));
}
}
文件字符输出流
文件字符输出流:FileWriter
作用:以内存为基准,把内存中的数据以字符的形式写出到磁盘文件中去的流。
构造器 |
说明 |
public FileWriter(File file) |
创建字符输出流管道与源文件对象接通 |
public FileWriter(File file,boolean append) |
创建字符输出流管道与源文件对象接通,可追加数据 |
public FileWriter(String filepath) |
创建字符输出流管道与源文件路径接通 |
public FileWriter(String filepath,boolean append) |
创建字符输出流管道与源文件路径接通,可追加数据 |
方法名称 |
说明 |
void write(int c) |
写一个字符 |
void write(char[] cbuf) |
写入一个字符数组 |
void write(char[] cbuf, int off, int len) |
写入字符数组的一部分 |
void write(String str) |
写一个字符串 |
void write(String str, int off, int len) |
写一个字符串的一部分 |
void write(int c) |
写一个字符 |
方法 |
说明 |
flush() |
刷新流,还可以继续写数据 |
close() |
关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据 |
import java.io.FileWriter;
import java.io.Writer;
public class WriterTest3 {
public static void main(String[] args) throws Exception {
//1.创建一个字符输出流管道与目标接通
// 覆盖管道,每次启动都会清空文件之前的数据
Writer f = new FileWriter("D:\test\outputTest2.txt", true);
//true---追加数据,不覆盖
//1.写一个字符 public void write(int c)
f.write('符');
f.write('a');
f.write(55);
f.write("rn"); //换行,兼容性强
//2.写一个字符串 public void write(String c)
f.write("我爱中国!");
f.write("rn");
//3.写一个字符数组 public void write(char[] buffer)
char[] chars = "我爱我的祖国!".toCharArray(); //转换为字符数组
f.write(chars);
f.write("rn");
//4.写字符数组的一部分
f.write(chars, 4, 2);
f.write("rn");
// f.flush();// 刷新后流可以继续使用
f.close(); // 关闭流,之后不能使用
}
}
小结
- 字节流适合做一切文件数据的拷贝(音视频,文本)
- 字节流不适合读取中文内容输出
- 字符流适合做文本文件的操作(读,写)
下篇请看:
JAVA输入输出流(IO流)下篇_代码不会敲的博客-CSDN博客