输入输出流

1、流模型
流就是对输入输出的一个封装,用于屏蔽具体物理目标的差异性
在Java程序中,对于数据的输入输出操作以流Stream方式进行,JavaSE提供各种各样的类用于使用相同的方法获取不同类型的数据
java.io包通过数据流、序列化和文件系统为用户提供一种完成I/O操作的输入/输出流
流的分类
操作方式
BIO同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成
NIO即同步非阻塞,一个线程不断的轮询每个输入输出的状态改变,如果有状态发生了改变,则进行下一步的操作
AIO即异步非阻塞I/O模型,无需一个线程去轮询所有IO操作的状态改变,在相应的状态改变后,系统会通知对应的线程来处理
流向
输入流
输出流
传输单位
字节流从InputStream/OutputStream派生出来,以字节为基本处理单位,一般用于操作二进制数据,字节次序是有意义的
字符流从Reader/Writer派生出来的,以16位的Unicode码表示字符为基本处理单位,一般用于操作字符数据
桥接流可以实现两个流之间的转换
功能
节点流对特定的地方读写,例如针对特定文件的读写
过滤流用于给节点增加功能,过滤流使用结点流进行输入/输出并添加附加功能,例如打印流主要用于添加println和print两个方法
针对对象进行功能扩展最直接的方式是继承,最大的缺陷是耦合
具体实现采用的是装饰模式
用途:允许向一个现有的对象添加新的功能,同时又不改变其结构
优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能
缺点:多层装饰比较复杂
具体实现
I/O流是一类很宝贵的资源,使用完后必须调用close()方法关闭流并释放资源。在关闭流时只用关闭最外层的流

2、文件系统File
java.io.File是针对操作系统中的文件系统的封装,可以用于以平台无关的方式表示文件或者文件夹
构造器
File(String pathName)以path为路径创建File对象,可以使用相关路径或者绝对路径两种方式。如果pathname是相对路劲,则默认的当前路径在系统属性user.dir中存储
相对路径和绝对路径
在windows下以盘符开头的路径,在其它系统中以/开头的路径就是绝对路径,针对一个文件或者文件夹写法唯一
相对于当前默认位置的写法,这个写法针对一个文件或者文件夹不唯一,具体写法取决于当前位置
new File(“c:/abc.txt”);这里的分割符可以使用\或者/
new File(“abc.txt”)相对当前位置的路径,用于指代项目根目录
File(String parent,String child) 这里文件对象的路径为相对于parent路径的child路径
new File(“c:/abc”,“bbb.txt”)表示c:/abc目录下的bbb.txt文件
new File(file对象,“abc.txt”)
常见方法
ff.getAbsolutePath():String 用于获取文件对象的绝对路径
ff.exists():booean 是否存在对应的文件对象,返回true则表示存在
ff.length():long 获取指定文件对象的字节数,单位为字节
判断文件还是文件夹
ff.isDirectory()):boolean 用于判断当前文件对象是否为文件夹
ff.isFile():boolean 用于判断当前文件对象是否为文件
ff.delete():boolean 删除文件或者文件夹,注意Java并不能保证删除一定成功
ff.mkdirs() 创建多级文件夹,而使用mkdir只能创建一层文件夹
实际编程中很少使用的方法
listFiles():File[]//获取当前文件夹的所有子文件或者子文件夹的信息,子文件或者子文件夹为File对象
FilenameFilter接口用于在获取子文件夹或者子文件时对名称进行过滤,属于函数式接口,可以使用lambda表达式以简化内部类的写法
写法1:采用内部类的方式进行定义f.listFiles(new MyFilter())
写法2:使用匿名内部类的方式进行定义f.listFiles(new FilenameFilter() {})
写法3:使用lambda表达式的方式进行定义–语句糖,File[] fs = f.listFiles((dir,name) -> name!=null && name.endsWith(".ini"));
(File dir,String name)->{}
(dir,String)->{}
省略{}的写法

3、字节流
顶层有两个抽象类InputSream和OutputStream
InputStream字节输入流- read
public abstract int read() throws IOException读取一个字节并以整数的形式返回,0-255。如果返回-1已到输入流的末尾
public int read(byte b[]) throws IOException读取一系列字节并存储到一个数组,返回实际读取的字节数。如果已经读到输入流的末尾则返回-1
OutputStream字节输出流write
public abstract void write(int b)向输入流写入一个字节数据,该字节为参数的低8位
public void write(byte b[],int offset,int length)将一个字节类型的数组中的从指定位置offset开始的length个字节写入到输出流
close()关闭流
文件字节流
用于封装文件的读写操作,具体实现类为FileInputStream用于读取文件内容,FileOutputStream用于写入数据到文件中,都是属于属于节点流
read():int 从指定的输入流中按字节读取数据,如果读到流的末尾则返回-1,否则返回读取到的数据。如果文件不存在则异常FileNotFoundException【IOException的子类】,读取返回值为int类型,这里实际就是读取的字节数据,系统返回值是默认追加3个字节
字节流是按照字节读取数据,如果读取英文信息则没有任何问题;如果读取多字节的数据,要么进行组装,要么就会出现不能显示数据的问题
InputStream is=new FileInputStream(f);
int kk;
while((kk=is.read())!=-1) { //每次读取一个字节的数据0-255,返回的是整数,自动添加高3个字节
System.out.print((char)kk);//将读取到的字节数据转换为字符
}
is.close();
InputStream is=new FileInputStream(f);
int len=0;
byte[] buffer=new byte[8192];
while((len=is.read(buffer))>0) { //读取一个批量最大为8192个字节的数据,将读取的数据存储到byte数组中,返回的是读取的字节数
System.out.print(new String(buffer,0,len));//将字节数组中指定范围的数据转换为字符串,—中文乱码问题
}
is.close();
write方法将输出数据按字节写入到输出流中。如果指定的文件不存在则自动进行创建。默认采用的是覆盖的写法,如果需要使用追加,则必须构建输出流时进行指定
try(
InputStream is=new FileInputStream(f);
OutputStream os=new FileOutputStream(“c:/a.ini”);
){
//所谓的文件拷贝就是从is中读取一个字节的数据,然后写入到os中,执行直到is读取为-1表示文件读取结束
int kk;
while((kk=is.read())!=-1) {
os.write(kk); //参数kk为int类型,实际上执行写出操作时会自动剔除kk的高3字节数据,然后进行写出
}
}
try(
InputStream is=new FileInputStream(f);
OutputStream os=new FileOutputStream(“c:/bb.log”,true);//如果没有true,则表示采用文件覆盖的操作方式,true表示采用的文件追加方式
){
byte[] buffer=new byte[8192];
int len=0;
while((len=is.read(buffer))>0) {
os.write(buffer,0,len);//将字节数组中的指定范围的数据写出到输出流中,从0开始,共写出len个字节
}
}

4、字符流
顶层有两个抽象类:Reader和Writer。Reader和Writer中定义了read()和write()方法,它们被派生流类重载
Reader抽象类的定义
public int read() throws IOException读取一个有效的字符,返回值为0到65535的整数,如果到达流的末尾则返回-1
public int read(char cbuf[]) throws IOException读取字符存储到char数组中,返回读取的字符个数,流结束则返回-1
abstract public void close() throws IOException关闭流,同时释放资源
Writer抽象类的定义
public void write(int c) throws IOException写出一个字符到字符流,要写的字符包含在给定整数值的16个低位;16个高位被忽略
abstract public void write(char cbuf[], int off, int len) throws IOException将字符数组中的指定部分内容压入到字符流,从off开始共len个字符
void write(String str) 将字符串中的内容压入到字符流中
abstract public void close() throws IOException关闭流,同时释放资源
FileReader、FileWriter文件流
用于实现针对文本文件的读写操作
FileWriter(“file-name”) FileWriter(“file-name”,true) 默认文件覆盖,如果参数true表示追加
操作方法和FileInputStream、FileOutputStream一致,区别在于读写时是一字节还是一字符
针对二进制文件不建议使用字符流,建议使用字节流进行操作,否则有可能拷贝文件出现问题
如果针对文本文件则建议使用字符流,因为编码使用比较方便

5、节点流
具体类
针对文件操作:FileReader、FileWriter和FileInputStream、FileOutputStream
针对内存数组操作:CharArrayReader、 CharArrayWriter和ByteArrayInputStream、 ByteArrayOutputStream
针对内存字串操作:StringReader、 StringWriter,没有对应的字节流
管道流用于线程通信操作:PipedReader、 PipedWriter和PipedInputStream、 PipedOutputStream
文件节点流
FileInputStream和FileOutputStream是文件字节流
FileReader和FileWriter是文件字符流
内存数组节点
如果文本则使用char[],如果二进制则使用byte[]
char[] arr=“中国人民解放军abc”.toCharArray();
Reader r=new CharArrayReader(arr);
int cc;
while((cc=r.read())!=-1) {
System.out.print((char)cc);
}
//收集键盘录入内容,如果输入quit,则退出后显示所有的录入内容
Scanner sc=new Scanner(System.in);
Writer w=new CharArrayWriter();
while(true) {
String ss=sc.nextLine();
if(“quit”.equals(ss))
break;
w.write(ss+"\n");
}
w.close();
sc.close();
// 需要获取在CharArrayWriter对应数组中存放的内容,则需要使用CharArrayWriter特殊方法
CharArrayWriter cw=(CharArrayWriter)w;
System.out.println(cw.toCharArray()); //获取CharArrayWriter对应数组中存放的内容
内存字串流
StringReader用于从一个字串String中读取数据
StringWriter用于给一个StringBuffer中写入数据,实现一个可边长的字串
String str=“亚洲说:‘我爱阿珂’”;
StringReader sr=new StringReader(str);
int cc;
while((cc=sr.read())!=-1)
System.out.print((char)cc);
sr.close();
Scanner sc=new Scanner(System.in);
try(
StringWriter sw=new StringWriter();
Writer fw=new FileWriter(“c:/console.txt”)
){
//接收键盘录入的内容
String temp=sc.nextLine();
while(!temp.equals(“quit”)) { //如果输入的数据不是quit,则反复执行
if(temp!=null && temp.trim().length()>0)
sw.write(temp+"\n"); //将录入的字串内容写入到StringWriter中,实际上就是写入到stringWriter关联的一个可边长的字符串中
temp=sc.nextLine();
}
fw.write(sw.toString());//将可边长的字串内容写入到一个文件中
}

6、过滤流
过滤流就是在节点流的基础上附加功能
过滤流的父类FilterInputStream/FilterOutputStream和FilterReader/FilterWriter
自定义流实现循环13加密
算法:(char)((原始字符-‘a’+13)%26+‘a’)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值