IO流(Input&Output Stream)
IO流用来处理设备间的数据传输,Java语言用IO流技术来处理设备上已有的数据(包括硬盘文件,内存中的数据等),java 用于操作流的对象都存放在IO包中(java.io.*)。
流按照流向分为:输入流和输出流
按照操作数据分为:字节流和字符流
早期计算机操作数据都使用字符流,因为数据在计算机中都是以二进制存在的。而文本数据在数据操作中是很常见的,为了方便操作文本数据,单独分离出字符流,字符流在内部融合了编码表,字符流基于字节流
IO流常用的基类
IO体系中一共有四个基类
字节流的抽象基类:
InputStream,OutputStream
字符流的抽象基类
Reader,Writer
这四个基类都是抽象的,类中有抽象的方法,由其子类来实现,由这四个基类派生出来的子类都是以其父名作为类名的后缀
字符流
I
O 流逝操作数据的,数据最常见的表现形式是文件
Writer 写入字符流的抽象类,操作文件的子类是FileWriter ,用来写入文件的便捷类。
FileWriter 构造方法:
该流对象一被创建就要有被操作的文件存在
常用方法:
write(int c)
写入单个字符。write(char[] cbuf)
写入字符数组。flush()
刷新该流的缓冲。close()
关闭此流,但要先刷新它。import java.io.*;//第一步,导入io包
class FileWriterDemo
{
public static void main(String[] args) throws Exception//将异常抛出
{
FileWriter fw=new FileWriter("demo.txt");//第二步,创建对象并初始化对象(明确文件存放目的地)
fw.write("abcde");//第三步,调用write方法将字符串写入到流中
fw.flush();//第四步,刷新流对象缓冲中的数据,将数据刷新到目的地中
//fw.close();//关闭流资源,关闭前会刷新内部缓冲区的数据,将数据刷到目的地中,刷新后将流关闭
//flush 与close 区别,都会刷新缓冲区的数据将数据刷到目的地,刷新后,flush 不关闭流流可以继续写入,close 关闭流
}
}
IO 异常的处理方式
对抛出异常的语句进行try catch 处理
class FileWriterDemo2
{
public static void main(String[] args)
{
FileWriter fw = null;//方便调用close ,将fw定义在try代码块外
try
{
fw = new FileWriter("demo.txt");//会抛出异常
fw.write("abcdekkkk");//会抛出异常
}
catch (IOException e)
{
System.out.println(e.toString());//异常处理语句
}
finally
{
try
{
if(fw!=null)//判断fw是否为空,如果不是null就关闭流,提高代码健壮性
fw.close();//关闭资源
}
catch (IOException e)
{
System.out.println(e.toString());
}
}
}
}
FileReader
构造方法
一构造的时候就要指定文件
常用的方法
字符流读取方式一:
import java.io.*;
class FileReaderDemo1
{
public static void main(String[] args) throws Exception//记得会发生异常,对异常处理
{
FileReader fr=new FileReader("demo.txt");//创建read流对象与已经存在的文本文件相关联//!!!!!加双引号
//如果文件不存在会发生FileNotFoundException
int ch=0;
while((ch=fr.read())!=-1)//括号括号!!!!
{
System.out.print((char)ch);//将int型强转成char型
}
fr.close();//关闭流
//fr.read()//调用读取流的read方法读取一个字符
}
}
字符流读取方式二
用read(char[])将字符存入数组,(返回数组中字符个数),将数组转换成字符串,获取数据
import java.io.*;
import java.util.*;
class FileReaderDemo2
{
public static void main(String[] args) throws Exception
{
FileReader fr=new FileReader("demo.txt");
char[] arr=new char[1024];//通常定义1024
int ch=0;
while((ch=fr.read(arr))!=-1)//将数据存入数组
{
// System.out.println("num="+ch+Arrays.toString(arr,0,num));//Arrays 的toString方法将数组转换为字符串
System.out.println("num="+ch+"````"+new String(arr,0,ch));//获取数组中从0角标开始的ch个字符
}
fr.close();//循环结束要关闭流
}
}
字符流缓冲区
IO流在读写中需要提高读写效率,读写效率的提高有助于优化程序,缓冲区要结合流使用,在流的基础上对流的功能进行增强
对应类
BufferedWriter:
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
构造方法
特有方法
newLine()
写入一个行分隔符。是一个跨平台的换行符
//创建一个流字符写入对象
FileWriter fw=new FileWriter("buf.txt");
//提高流写入效率,加入缓冲技术,将流对象作为参
//数传递给缓冲区的构造函数
BufferedWriter bufw=new BufferedWriter(fw);
for(int i=0;i<5;i++)
{
bufw.write("abcde");
//缓冲区中提供跨平台换行操作:newLine ()
bufw.newLine();//写入换行分隔符
//用到缓冲区就要用刷新
bufw.flush();
}
//关闭缓冲区就是关闭缓冲区中的流对象,所以流对象的close 不用写
bufw.close();
BufferedReader
构造方法
特有方法
readLine()
读取一个文本行。返回String类型//创建流读取对象与文件相关联
FileReader fr=new FileReader("buf.txt");
//创建缓冲区,将字符读取流对象传递给缓冲区的构造函数
BufferedReader bufr=new BufferedReader(fr);
String line=null;
while((line=bufr.readLine())!=null)//readLine()是缓冲区的方法
{
System.out.println(line);
}
ReadLine()方法的原理:
无论是读一行还是读取多个字符,都是在硬盘一个一个的读取最终使用Read ()方法一次读取一个
装饰设计模式
当想对已有对象进行功能增强时,定义一个类,将已有对象传入,基于已有的功能,提供加强功能,那么定义的类称为装饰类。
装饰类会通过构造方法接收已有的被装饰对象,并基于被装饰类对象的功能,提供更强的功能
装饰设计模式与继承
和继承相比,装饰设计模式更灵活,避免了体系的臃肿,降低了类之间的关系
装饰类示例:
import java.io.*;
class MyBufferedReader//定义一个装饰类
{
private FileReader r;
MyBufferedReader(FileReader r)//构造函数中传入被装饰的对象
{
this.r=r;
}
public String MyreadLine() throws IOException//基于read()方法,定义MyreadLine方法实现读取一行的功能
{
StringBuffer sb=new StringBuffer();
int ch=0;
while((ch=r.read())!=-1)
{
if(ch=='\r')//如果读到‘r’
continue;//继续
if(ch=='\n')//如果读到‘n’
return sb.toString();//字符串形式返回读取到并存入缓冲区的数据
else
sb.append((char)ch);//否则向缓冲区添加字符
}
//if (sb!=null)条件错误
if(sb.length()!=0)
return sb.toString();//如果缓冲区中还有数据,将数据以字符串返回
return null;
}
public void MyClose() throws IOException
{
r.close()//;关闭流资源
}
}
class MyBufferedReaderDemo
{
public static void main(String[] args) throws IOException
{
FileReader fr=new FileReader("buf.txt");//加双引号
MyBufferedReader mbfr=new MyBufferedReader(fr);//创建自定义缓冲区
String line=null;
while((line=mbfr.MyreadLine())!=null)//调用MyreadLine方法,读取一行数据
{
System.out.println(line);
}
mbfr.MyClose();//关闭流
}
}
LineNumberReader
LineNumberReader 是BufferedReader 的子类,跟踪行号的缓冲字符输入流。此类定义了方法
setLineNumber(int)
和
getLineNumber()
,它们可分别用于设置和获取当前行号。
构造方法
特有方法
setLineNumber(int lineNumber)
设置当前行号。getLineNumber()
获得当前行号。public static void main(String[] args) throws Exception
{
FileReader fr=new FileReader("BufferRWTest.java");
LineNumberReader lnr=new LineNumberReader(fr);
String line=null;
lnr.setLineNumber(20);//设置行号,从第21 行开始打印
while ((line=lnr.readLine())!=null)
{
System.out.println(lnr.getLineNumber()+":"+line);//获取行号
}
}
字节流
要操作图片数据就要用到字节流,图片是文件,就要使用字节流中操作文件的子类
FileOutputStream
构造方法
常用方法
write(byte[] b)
将b.length
个字节从指定 byte 数组写入此文件输出流中。write(int b)
将指定字节写入此文件输出流
代码示例
public static void write() throws IOException//写入文件
{
FileOutputStream fos=new FileOutputStream("fos.txt");
fos.write("abcdefg".getBytes());//这个write方法的参数为byte型 需要将String类型转换成byte型,用getBytes()方法
fos.close();//关闭流
注意:字符流底层使用的是字节流的数组缓冲区,将读取到的字节临时存储,再查找编码表,获取字符,需要将字符刷新到目的地,字节流可以直接输入数据,不需要刷新,所以没有Flush 方法。
FileInputStream
构造方法
常用方法
read()
从此输入流中读取一个数据字节。
read(byte[] b)
从此输入流中将最多b.length
个字节的数据读入一个 byte 数组中。
close()
关闭此文件输入流并释放与此流有关的所有系统资源。
available()
返回文件的字符数,可以用来定义刚刚好的字符数组缓冲区。
字节流读取方式一:
用Read()方法读取文件字节
public static void read_1() throws IOException//读取文件fos.txt 数据方法一
{
FileInputStream fis=new FileInputStream("fos.txt");
int ch=0;
while ((ch=fis.read())!=-1)
{
System.out.print((char)ch);
}
fis.close();//关闭资源
}
字节流读取方式二
用Read(bytes[] buf) 方法将文件读取到缓冲区数组中
public static void read_2() throws IOException
{
FileInputStream fis=new FileInputStream("fos.txt");
int ch=0;
byte[] b=new byte[1024];//定义1024 长度的字节数组
while ((ch=fis.read(b))!=-1)
{
//System.out.println(b.toString());//打印的是引用地址,不对!
System.out.println(new String(b,0,ch));//new 字符串对象,byte数组直接作为参数传进去,从0角标开始,打印ch个
}
fis.close();
}
字节流读取方式三
用available()方法定义大小刚好的字节数组缓冲区,将文件读到缓冲区
public static void read_3() throws IOException//如果文件过大,慎用此方法,因为如果数据过大,
//需创建一个相当的字节数组,内存可能会溢出
{
FileInputStream fis=new FileInputStream("fos.txt");
//int ch=0;
byte[] b=new byte[fis.available()];//定义一个长度刚好的缓冲区
//因为已知长度了就不需要在循环了
fis.read(b);
System.out.println(new String (b));
}
字节流的缓冲区
IO字节流在读写操作中,为了提高效率,用到字节流缓冲区,该缓冲区封装了缓冲数组,因此直接调用读写方法即可,而不需要定义缓冲区
代码示例:用字节流缓冲区复制。MP3文件
public static void copy_1() throws IOException
{
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("周杰伦 - 稻香.mp3"));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("稻香2.mp3"));
int ch=0;//字节的数值数值
while ((ch=bis.read())!=-1)
{
bos.write(ch);
}
//关闭资源
bis.close();
bos.close();
}