IO流
IO流用来处理设备之间的数据传输
Java对数据的操作是通过流的方式
Java用于操作流的类都在IO包中
IO流常用父类
字节流的抽象父类:
InputStream
outputStream
字符流的抽象父类
Reader
Writer
IO程序书写
使用前,导入IO包中的类
使用时.进行IO异常处理
使用后,释放资源
流按流向分为:输入流FileInputStream,输出流FileOutStream
流按操作类型分为:
字节流: 字节流可以操作任何数据,因为任何数据都是以字节的形式存储
字符流; 字符流只能操作纯字符数据,比较方便
字符流
FileInputStream fis = new FileInputStream("文件名"); //创建IO流对象
int x = fis.read(); //硬盘上读取一个字节 --> 若读完所有字节,则返回-1
sout(x); //输出文件字节
files.close(); //关流释放资源
构造方法
File InpuStream(String name)
File InpuStream(File file)
方法
read() --> 读取一个字节数据,返回这个字节,结束 返回-1
read(byte[] b) --> 读取一个字节数组 ,返回该数组.结束返回-1
将数据读取到字节数组里面,字节数组长度是几,一次就读取几个
close()
--> 为什么返回值用int接受?
因为,字节输入流可以操作任意类型的文件,若每次都返回byte,有可能在读到中间的时候遇到11111111,即 -1 -->所以int接受,在前面补上24个0满足4字节,那么结束标记的-1就为int型
FileOutputStream fos = new FileOutputStream("文件名/或者File类型的文件"); //创建字节输出流对象
fos.write(97); //虽然写出的是int数,但是到文件上的是一个字节,自动取出前三个8位
FileOutputStream ==> 在创建对象的时候如果没有这个文件,会帮创建出来
--> 如果有,就会将文件清空,重写写入新的内容
--> 如果想续写,就在第二个参数中添加true
--> 将这个文件绑定到这个输出流中,以后通过这个输出流操作的就是这个文件了
--> 写入到文件中的是数字对应的ASC码值
在java中,一个字符占2个字节,但若该字符在ascii码中,是占一个字符的
中文在操作系统中占多个字节 --> GBK中2个字节 UTF-8中占3个字节
构造方法
FileOutpuStream(String name)
FileOutpuStream(File file)
FileOutpuStream(File file,boolean append) --> 不改变内容,续写
FileOutpuStream(String str , boolean append) --> ...
方法
write(int b)
write(byte[] b)
--> getBytes()使用平台默认的编码方式转成字节数组
--> String(byte[] bytes) 字节数组转字符串
--> String(byte[] int offset , int length) 将字节数组的一部分转成String
byte[] bArr = "戳文能啊开开阿帆鄂城啊".getBytes();
fos.write(bArr);
write(byte[] , int off , int end)
close()
核心代码:(多次)
FileInputStream fis = new FileInputStream("双源.jpg");==>创建输入流对象,关联双源.jpg
FileOutputStream fos = new FileOutputStream("copy.jpg");==>创建输出流,copy.jpg
int b ;(效率太低)
while((b = fis,read()) ! = -1 ){ ==>不断读取每个字节
fos.write(); ==> 将每个字节取出
}
第二种方法(不推荐使用,因为有可能导致内存溢出)
byte[] arr = new byte[fis.available()];
fis.read(arr); //将文件的字节读取到内存中
fos.write(arr); //将内存的字节撰写到文件上
第三种copy(小数组)
byte[] arr = new byte[2];
while(int len = fis.read(arr) != -1){ //将文件上的字节读取到字节数组中
fos.write(arr,0,len)
}
fis.close();//==>关闭资源
fos.close();
定义小数组的标准格式
byte[] arr = new byte[1024*8];
while(int len = fis.read(arr) != -1){
fos.write(arr,0,len)
}
-->如果忘记加arr,返回的就不是读取字节个数,而是返回的码表值
缓冲流
四种
字节缓冲流: BufferedInputStream / BufferedOutputStream
字符缓冲流: BufferedReader / BufferedWriter
--> 在创建流对象时,会创建一个车内置的默认大小的缓冲区数组,通过缓冲区的读写,减少系统IO次数
--> 缓冲流其实本身并不具备读写功能,它的作用其实是为了其他流加速
构造方法
BufferedInputStream(InputStream in) --> 创建一个新的缓冲输入流
BufferedOutputStream(OutputStream out) --> 创建一个新的缓冲输出流
BufferedReader br = new BufferedReader(new FileReader(...))
BufferedWriter bw = new BufferedWriter(new FileWriter(...))
缓冲区特有方法
public String readLine() --> 读一行文字
pubilc void newLine() --> 写一行分隔符,由系统属性定义符号
FileInputStream fis = new FileInputStream();
--> 创建输入流对象,关联文件
FileOutputStream fos = new FileOutputStream();
--> 创建输出流对象,关联文件
BufferedInputStream bis = new BufferedInputStream(fis);
--> 创建缓冲区对象,对输入流进行包装让其变得更加强大
BufferedOutputStream bos = new BufferedOutputStream(fos);
int b ;
while(b = bis.read() != -1){
bos.write(b);
}
bis.close();
bos.close();
缓冲区思想
小数组合buffer的对比
读写中文
代码块
--> 一下方法有可能出现问题,有可能读到半个中文字节的情况
FileInputStream fis = new FileInputStream();
--> 创建输入流对象,关联文件
byte[] arr = new byte[3];
int len;
while((len = fis.read()) ! = -1){
sout(new String(arr,0,len));
}
fis.close;
异常处理
标准异常处理1.7版本
代码块
FileInputStream fis = null ;
--> 创建输入流对象,关联文件
FileOutputStream fos = null;
--> 创建输出流对象,关联文件
try{
fis = new FileInputStream();
fos = new FileOutputStream();
int b;
while((b = fis.read()) != -1){
fos.write();
}
}finally{
try{
if(fis != null){
fis.close();
}finally{
if(fos != null){
fos.close();
}
}
标准异常处理1.6版本
JDK7的处理
DK7优化后的try-with-resource 语句,该语句确保了每个资源在语句结束时关闭。所谓的资源(resource)是指在程序完成后,必须关闭的对象。
try (创建流对象语句,如果多个,使用';'隔开) {
// 读写数据
} catch (IOException e) {
e.printStackTrace();
}
例
// 创建流对象
try ( FileWriter fw = new FileWriter("fw.txt"); ) { --> ()内必须放的是AutoCloseable的实现类
// 写出数据
fw.write("黑马程序员"); //黑马程序员
} catch (IOException e) {
e.printStackTrace();
}
--> 不管程序结果如何,都会调用在try中创建的close方法
--> 这个close方法,不需要我们手动去调用,系统会帮我们去调用
JDK9的改进(了解内容)
try-with-resource 的改进,对于引入对象的方式,支持的更加简洁。被引入的对象,同样可以自动关闭,无需手动close
// 创建流对象
final FileReader fr = new FileReader("in.txt");
FileWriter fw = new FileWriter("out.txt");
// 引入到try中
try (fr; fw) {
// 定义变量
int b;
// 读取数据
while ((b = fr.read())!=-1) {
// 写出数据
fw.write(b);
}
} catch (IOException e) {
e.printStackTrace();
}
字符流
Reader
--> 字符输入流的顶层父类,抽象类 常用子类FileReader
--> 以字符为单位进行读取
构造方法
FileReader(File file)
FileReader(String fileName)
方法
int read()
int read(char[] cbuf) --> 返回读取到的有效个数
Writer
--> 字符输出流的顶层父类,抽象类 常用子类FileWriter
--> 以字节为单位进行读取
构造方法
FileWriter(File file)
FileWriter(String FileName)
方法
void write(String str) 写入字符串
void write(char[] cbuf , int off , int len)
void write(int c)
void write(String str , int off , int len)
--> write方法将写入的数据放入到了内存缓冲区,必须flush一下
flush() 刷新(字节流写入的时候必须注意)
flush和close方法的区别
close --> 具备刷新的功能,在关闭流之前,就会先刷新一次缓冲区,将缓冲区的字节全都刷新到文件上再关闭,刷新完后不能继续写
flush --> 具备刷新功能 , 刷完后可以继续写,需要实时刷新的
读取字符
FileReader fr = new FileReader(" ");
int c;
while((c = fr.read()) != -1){// ==> 通过项目默认的码表一次读取一个字符
sout((char) c );
}
写入字符
FileWriter fw = new FileWriter(" ");
fw.write(" ... ");
fw.write(97);
fw.close();
字符流的拷贝
FileReader fr = new FileReader(" ");
FileWriter fw = new FileWriter(" ");
int c;
while(( c = fr.read()) != -1){
fw.write();
}
fr.close();
fw.close();// ==> write内容有一个2k的缓冲区,如果不关流,就会将内容写到缓冲区里,关流会将内容写出,并关闭(刷洗缓冲区)
字符流的使用场景
字符流可以拷贝文件,但不推荐使用
--> read时将字节转换为字符,.write时将字符转换为字节
--> 程序需要读取一段文本,或者写出一段文本的时候可以使用字符流
--> 读取的时候是按照字符的大小读取的,不会出现半个中文
--> 写出的时候可以直接将字符串写出,不用转换为字节数组
字符流是否可以拷贝非纯文本的文件
--> 不可以拷贝非纯文本的文件
--> 因为在读的时候会将字节转换为字符,可能找不到对应的字符,就会用?代替,写出的时候会将字符转换成字节写出去
--> 如果是?直接写出,这样,文件就乱了
自定义字符数组的拷贝
FileReader fr = new FileReader(" ...");
FileWriter fw = new FileWriter(" ");
char[] arr = new char[1024];
int len;
while((len = fr.read(arr) != -1)){
fw.writer(arr,0,len);
}
fr.close();
fw.close()
带缓冲的字符流
BufferedReader br = new BufferedReader(new FileReader());
BufferedWriter br = new BufferedWriter(new FileReader());
int c;
while(c = br.read(arr) != -1)){
bw.writer(arr,0,len);
}
br.close();
bw.close();
(BufferReader)readLine() ==> 读取文本行,通过换行/回车认为可直接终止
(BufferWriter)newLine(); ==> 写入一个行分隔符
newLine() --> 是跨平台的方法
\r\n --> 仅windows系统
文本反转
1.创建输入输出流
2.创建集合对象
3.将读到的数据存储在集合中
4.反向遍历集合写到文件上
5.关流
注意:
流对象尽量符合晚开早关
LineNumberReader
LineNumberReader linr = new LineNumberReader(" ");
String line ;
while((line = lnr.readLine()) != null){
sout(lnr.getLineNumber() + line);
}
lnr.close();
设计模式
步骤
1.获取被装饰类的引用
2.在构造方法中传入被装饰类的对象
3.对原有功能进行升级
好处
降低程序的耦合性,被装饰的类的变化,与装饰类无关
转换流图解
图片加密