-------android培训、java培训、期待与您交流! ----------
一 IO 的概述:
IO流用来处理设备之间的数据传输:java对数据的操作时通过流的方式;java用于操作流的对象都在IO包中。
流按操作数据分为两种:字节流字符流,流按流向又分为输入流和输出流(Input Output)。
二 字符流中的抽象基类 : Reader Writer
(一)Writer 的子类:public class FileWriter extends OutputStreamWriter
FileWriter:用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。可以先在 FileOutputStream 上
构造一个 OutputStreamWriter。
FileWriter类的构造方法:
FileWriter(File file) 根据给定的 File 对象构造一个 FileWriter 对象。 |
FileWriter(File file, boolean append) 根据给定的 File 对象构造一个 FileWriter 对象。 |
FileWriter(FileDescriptor fd) 构造与某个文件描述符相关联的 FileWriter 对象。 |
FileWriter(String fileName) 根据给定的文件名构造一个 FileWriter 对象。 |
FileWriter(String fileName, boolean append) 根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。 |
常用的方法有:
Writer |
append(char c) 将指定字符添加到此 writer。 |
Writer |
append(CharSequence csq) 将指定字符序列添加到此 writer。 |
Writer |
append(CharSequence csq, int start, int end) 将指定字符序列的子序列添加到此 writer.Appendable。 |
abstract void |
close() 关闭此流,但要先刷新它。 |
abstract void |
flush() 刷新该流的缓冲。 |
void |
write(char[] cbuf) 写入字符数组。 |
abstract void |
write(char[] cbuf, int off, int len) 写入字符数组的某一部分。 |
void |
write(int c) 写入单个字符。 |
void |
write(String str) 写入字符串。 |
void |
write(String str, int off, int len) 写入字符串的某一部分。 |
(二) 操作的步骤:
(1):创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件;而且该文件会被创建到制定的目录中,如果该目录下已有该同名文件
就会覆盖该同名文件;其实该步骤就是在明确数据要存放的位置;
(2) IO异常的处理
(3)调用wirter方法,将字符串写入到流中;
(4)刷新流对象中的缓冲的数据;将数据刷新到目的地中;
(5)关闭流资源,但是在关闭之前会刷新一次内部的缓冲中的数据,将数据刷新到目的地中; Close 和 flush 的区别:flush是数刷新后流可以继续使用
close 是刷新后,会将流关闭;
如示例:
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//创建FileWriter流对象
FileWriter fw=null;
try {
//这个构造方法是创建一个新的文件或如果已存在该文件就会被覆盖
//fw=new FileWriter("D:\\Test1.txt");
//这个构造方法是创建一个新的文件如果已存在该文件不会被覆盖而是在后面续写内容
fw=new FileWriter("D:\\Test1.txt",true);
fw.write("Hello\r\n world");//使用writer方法写入字符串 \r\n是在windows系统下的换行符
fw.flush();//刷新缓冲区
} catch (IOException e) {
e.printStackTrace();
}
finally{
if (fw!=null) {
try {
fw.close();//关闭FileWriter流
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
(三) Reader 类:
构造函数: FileReader(String fileName)在给定从中读取数据的文件名的情况下创建一个新FileReader。
常用方法:
read()读取单个字符。:读取的字符数,如果已到达流的末尾,则返回 -1
read(char[] cbuf) 将字符读入数组。
read(char[] cbuf, int offset, int length) 将字符读入数组中的某一部分。
read方法的参数:cbuf
- 目标缓冲区
offset
- 从其处开始存储字符的偏移量
length
- 要读取的最大字符数
close() 关闭该流并释放与之关联的所有资源。
skip(long n) 跳过字符。 ----- n - 要跳过的字符数
操作步骤:
(1)创建一个FileReader文件读取流对象,和指定的名称的文件相关联;要保证该文件是已经存在的,如果不存在就会发生异常
FileNotForundException:
(2)调用读取流对象的Read方法:
(3)关闭流资源--close();
如示例:
public static void main(String[] args) {
// TODO Auto-generated method stub
FileReader fr=null;
try {
fr=new FileReader("D:\\Test1.txt");
char c=(char)fr.read();//读取单个字符的read方法
System.out.println(c);
//定义一个字符数组,用于存储读到的字符;该read[char[]]返回的是读到的字符个数
char[] ch=new char[1024];
//定义变量来接收读取到的字符个数
int num=0;
while ((num=fr.read(ch))!=-1) {
//使用字符串的格式输出该char数组中第0个开始到接收到的个数;
System.out.println(new String(ch,0,num));
}
} catch (IOException e) {
e.printStackTrace();
}
finally {
if (fr != null) {
try {
fr.close();// 关闭FileRead流资源
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
(四)字符流的缓冲区:缓冲区要和流结合才能使用,在流的基础上对流的功能进行了增强。
创建缓冲区是为了提高流的操作效率而出现的,所以在创建缓冲区子前要先有流对象;
(1) BufferedWriter:将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。可以指定缓冲区的大小,或者接受
默认的大小。在大多数情况下,默认值就足够大了。
常用方法:
BufferedWriter(Writer out) 创建一个使用默认大小输出缓冲区的缓冲字符输出流。
BufferedWriter(Writer out, int sz) 创建一个使用给定大小输出缓冲区的新缓冲字符输出流。
newLine() 写入一个行分隔符。
flush() 刷新该流的缓冲。
(2)BufferedReader:从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。可以指定缓冲区的大小,或者可使用默认
的大小。大多数情况下,默认值就足够大了
常用方法:
BufferedReader(Reader in) 创建一个使用默认大小输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in, int sz) 创建一个使用指定大小输入缓冲区的缓冲字符输入流。
readLine() 读取一个文本行。 返回的时候只返回回车符自前的数据内容,并返回回车符;
如示例:
public static void main(String[] args) {
// TODO Auto-generated method stub
BufferedWriter bw=null;
BufferedReader bf=null;
try {
//为了提高效率,加入缓冲区技术,将字符流对象作为参数传递给缓冲区对象的构造函数。
bf=new BufferedReader(new FileReader("D:\\Reader_Test2.java"));
//为了提高字符写入流的效率,加入了缓冲技术,
//只要将需要被提高小路的流对象作为参数传递给缓冲区的构造函数就可以;
bw=new BufferedWriter(new FileWriter("D:\\Test_5.txt"));
String len=null;//创建一个变量存储读取出来的这一行数据
//使用循环来读取数据每次读取一行br.readLine();当数据读取返回空时就退出循环说明读取到了末尾
while((len=bf.readLine())!=null){
//bf.readLine()方法返回的时候只返回回车符之前的数据内容,并返回回车符;
bw.write(len);//将数据写入到文本中
bw.newLine();//调用换行的方法就如同\r\n同时newLine是一个跨平台的换行符;
bw.flush();//刷新缓冲区
}
} catch (IOException e) {
throw new RuntimeException("数据读取失败");
}finally{
if(bw!=null){
try {
bw.close();//关闭缓冲区的就可以关闭流对象了;
} catch (IOException e) {
throw new RuntimeException("写入流关闭失败");
}
}
if(bf!=null){
try {
bf.close();
} catch (IOException e) {
throw new RuntimeException("读取流关闭失败");
}
}
}
}
}
装饰设计模式:
当想要对已有的对象进行功能增强时;可以定义一个类将已有的对象传入,基于已有的功能并提供加强功能,那么自定义的该类称为装饰类;
装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能提供更强的功能;
例如:BufferedReader类中的每次读取一行的方法(readLine)就是用用装饰设计模式来进行加强的这样来提高效率;下面将使用如下示例来表明:
原来的BufferedReader类封装的是数组:这里将用StringBuilder来代替:
如示例:
public static void main(String[] args) {
// TODO Auto-generated method stub
FileReader fr=null;
SuperFileReader sfr=null;
try {
//定义一个读取流并将对象传入到装饰类的构造函数中
fr=new FileReader("D:\\凯\\T11练习\\IO流\\src\\字符流\\Test_5.txt");
sfr=new SuperFileReader(fr);
String len=null;//定义变量来接收数据
while((len=sfr.Readers())!=null){
System.out.println(len);
}
} catch (IOException e) {
throw new RuntimeException("读取异常");
}
finally{
if(fr!=null){
try {
sfr.closes();
} catch (IOException e2) {
throw new RuntimeException("关闭异常");
}
}
}
}
}
class SuperFileReader{
private Reader fr;
public SuperFileReader(Reader fr){
this.fr=fr;
}
public String Readers() throws IOException{
//定义一个容器来装读取出来的数据
StringBuilder sb=new StringBuilder();
int ch=0;
while((ch=fr.read())!=-1){
if(ch=='\r'){//当读取到换行符时'\r'就跳出本次循环
continue;
}
if(ch=='\n'){//当读取到换行符时'\n'就将数据返回
return sb.toString();
}else{
sb.append((char)ch);
}
}
//要是后面的数据没有换行符就有可能 造成最后一行数据没有返回所以还要做判断
if(sb.length()!=0){
return sb.toString();
}
return null;//最后没有数据了就放回空
}
public void closes() throws IOException{
fr.close();
}
}
装饰设计模式小结:
装饰设计模式就是在多个类中抽取了其多个类中的共性功能,而这些类都是继承同一个父类或是实现同一个接口,这样的话其子类就会特别的臃肿;
因此就抽取出一个类来为这些子类服务:将这些子类的共性功能抽取出来进行功能的增强,而这类就要传入所要修饰的类那么就把其父类传入就可以了
这样既提高了代码的扩展性而且降低了代码的耦合性,将其耦合关系变成了组合关系,这就是装饰设计模式;
三 字节流的抽象基类: InputStream ,OutputStream
(一) InputStream :此抽象类是表示字节输入流的所有类的超类。
其子类: FileInputStream
从文件系统中的某个文件中获得输入字节。哪些文件可用取决于主机环境。
(1)构造函数:
FileInputStream(File file) 通过打开一个到实际文件的连接来创建一个FileInputStream
,该文件通过文件系统中的File
对象file
指定。
FileInputStream(String name) 通过打开一个到实际文件的连接来创建一个FileInputStream
,该文件通过文件系统中的路径名name
指定。
常用的方法:
int |
available() 返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。 |
void |
close() 关闭此文件输入流并释放与此流有关的所有系统资源。 |
protected void |
finalize() 确保在不再引用文件输入流时调用其 close 方法。 |
FileChannel |
getChannel() 返回与此文件输入流有关的唯一 FileChannel 对象。 |
FileDescriptor |
getFD() 返回表示到文件系统中实际文件的连接的 FileDescriptor 对象,该文件系统正被此 FileInputStream 使用。 |
int |
read() 从此输入流中读取一个数据字节。 |
int |
read(byte[] b) 从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。 |
int |
read(byte[] b, int off, int len) 从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。 |
long |
skip(long n) 从输入流中跳过并丢弃 n 个字节的数据。 |
如示例:
public static void FoStreanm(){//写入字节流
FileOutputStream fom=null;
try {
//定义一个字节写入对象并指定文件名及目录
fom=new FileOutputStream("Text\\fis.txt");
fom.write("Hello world".getBytes());//写入的数据并转换成字节getBytes()
} catch (IOException e) {
throw new RuntimeException("输入异常");
}
finally{
if(fom!=null){
try {
fom.close();
} catch (IOException e) {
throw new RuntimeException("输入流关闭异常");
}
}
}
}
(二)OutputStream :此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器。
其子类:FilterOutputStream 类本身只是简单地重写那些将所有请求传递给所包含输出流的 OutputStream
的所有方法。
FilterOutputStream 的子类可进一步地重写这些方法中的一些方法,并且还可以提供一些额外的方法和字
(1)构造方法: FilterOutputStream(OutputStream out) 创建一个构建在指定基础输出流之上的输出流过滤器。
常用的方法有:
void |
close() 关闭此输出流并释放与此流有关的所有系统资源。 |
void |
flush() 刷新此输出流,并强制将所有已缓冲的输出字节写入该流中。 |
void |
write(byte[] b) 将 b.length 个字节写入此输出流。 |
void |
write(byte[] b, int off, int len) 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。 |
void |
write(int b) 将指定 byte 写入此输出流。 |
如示例:
public static void fiStream(){//读取字节流
FileInputStream fis =null;
try {
//定义一个字节读取对象并指定文件名及目录
fis=new FileInputStream("Text\\fis.txt");
System.out.println(fis.available());// available方法是用于获取读取文件中的字节数
//System.out.println((char)fis.read());//读取一个字节如果读取字符就会只读去到半个(?)
byte[] by=new byte[1024]; //定义一个字节数字存储读取到的数据
int len=0; //定义一个变量来接收读取到的数据
fis.skip(2);//skip方法是用来指定要跳过指定的个数字节 //将输出 llo world
while((len=fis.read(by))!=-1){
System.out.print(new String(by,0,len));
}
} catch (IOException e) {
throw new RuntimeException("输出异常");
}
finally{
if(fis!=null){
try {
fis.close();//关闭字节流
} catch (IOException e) {
throw new RuntimeException("输出流关闭异常");
}
}
}
}
(三)字节流缓冲区:
(1)BufferedInputStream:为另一个输入流添加一些功能,即缓冲输入以及支持 mark
和reset
方法的能力。在创建BufferedInputStream
时,
会创建一个内部缓冲区数组。在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。mark
操作记录
输入流中的某个点,reset
操作使得在从包含的输入流中获取新字节之前,再次读取自最后一次 mark
操作后读取的所有字节。
(2)BufferedOutputStream:该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入
调用底层系统。
(3)模拟字节流的缓冲区实现:拷贝视频文件如示例
public static void main(String[] args) {
// TODO Auto-generated method stub
BufferedOutputStream fo=null;
Buff fi=null;
try {
//创建自定义的缓冲区对象并传入读取字节流对象
fi=new Buff(new FileInputStream("Text\\1.avi"));
fo=new BufferedOutputStream(new FileOutputStream("Text\\11.avi"));
int by=0;
while((by=fi.copyAvi())!=-1){
fo.write(by);//将字节拷贝到指定目录中
}
} catch (IOException e) {
}
}
}
//自定义的缓冲区
class Buff{
private FileInputStream fis;
public Buff(FileInputStream fis){
this.fis=fis;
}
private int count=0;//定义一个变量来存储读取到的字节个数
private int len=0;//定义取出字节的下标
private byte[] by=new byte[1024];//定义字节数组将读取到的字节先存储到字节数组中
public int copyAvi() throws IOException{
if(count==0){//当读取到的字节数为空时说明字节数组中现在没有数据
count=fis.read(by);//现在就去读取数据并将读取到的字节数用count记录
if(count<0){//当count小于0时说明没有数据了
return -1;
}
len=0;//在次读取时要从0开始读取因为角标从0开始
byte b=by[len];
count--;//没读取一次说明字节数在递减
len++;//没读取一次说明字节数在递加
return b&255;
}if(count>0){
byte b=by[len];
count--;
len++;
return b&255;
}
return -1;
}
}
小结:通过以上示例可以知道IO流中:
字符流有 (FileReader 、Filewriter 、字符缓冲区 BufferedReader 、BuffereWrite )
字节流有 (FileInputStream、FileOutputStream 字节缓冲区 BufferedInputStream 、BufferedOutputStream)
四 转换流:
(一) InputStreamReader 是字节流通向字符流的桥梁:它使用指定的
读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,charset
或者可以接受平台默认的字符集。每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。
(二) OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的
将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给charset
定,否则将接受平台默认的字符集。 每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。
如示例:
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//获取键盘录入对象
InputStream fr=System.in;
//将字节流输入对象转换成字符流对象,使用InputStreamReader;
InputStreamReader isr=new InputStreamReader(fr);
//字节流转换成字符流后在使用缓冲区提高效率;
BufferedReader bi=new BufferedReader(isr);
//获取输出流的对象
OutputStream out=System.out;
////将字节流输出对象转换成字符流对象,使用InputStreamReader;
OutputStreamWriter osw=new OutputStreamWriter(out);
//字节流转换成字符流后在使用缓冲区提高效率;
BufferedWriter bw=new BufferedWriter(osw);
String len=null;
//将键盘录入的数据存入len中
while((len=bi.readLine())!=null){
if("over".equals(len)){//退出循环
break;
}
bw.write(len);//输出数据
bw.newLine();//字符流流中缓冲区的换行方法
bw.flush();//要刷新数据
}
bw.close();
bi.close();
}
小结:在这字节流和字符流中我们怎么去使用呢或区分呢:可以同过一下来明确使用哪一个对象
(一):明确--------源和目的
(1) 源:输入流:InputStream Reader;
(2) 目的:输出流 OutputStream Writer;
(二)操作的数据时文本文件还是数据文件;
(1)文本文件就是字符流了;
(2)如果是媒体文件就是字节流了;
(三)当体系明确后在明确要使用哪个具体的对象,可以通过设备区分:
(1)源设备 : 内存, 硬盘, 键盘;
(2) 目的设备 :内存 ,键盘, 控制台;
例如:
将一个文本文件中的数据复制到另一个文本文件中,复制文件:
源:使用的是读取流:就是:InputStream , Reader ;接下来要操作的是文件就用字符流对象:Reader体系中可以操文件的对象是FileReader;
如果要提高效率就在使用Reader体系中的缓冲区 BufferedReader对象;
BufferedReader br=new BufferedReader(new FileReader("要读取的文件"));
一样的可以使用BufferedWriter对象来提高效率;
BufferedWriter bw=new BuffereWriter(new FileWriter(“要输出的目的
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
如果想要把录入的数据按照指定的编码表(utf-8)在将数据存储到文件中,而此时就要有所改变使用的对象了;
目的:使用输出流: OutputStream Writer :是纯文本就用Writer对象的FileWriter对象,但是FileWriter是使用的默认编码表(GBK)但是存储时需要假如你
指定的编码表(utf-8)而指定编码表的只有转换流可以指定;所以要使用的对象是OutputStreamWriter;而该转换流对象要接收一个字节输出流,而且还可以
操作的文件字节输出流。FileOutputStream;那么就要这样操作了:
OutputStreamWriter osw= new OutputStreamWriter( new FileOutputStream("文件路径"),"UTF-8");
BufferedWriter bufw =new BufferedWriter(osw);
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
那么什么时候使用到转换流呢? 字符和字节之间的桥梁,通常涉及到字符编码转换,而这时就要用到转换流了;
五 file类---概述:
文件和目录路径名的抽象表示形式,是用来将文件或者文件夹封装成对象,方便对文件与文件夹的属性信息进行操作:
用户界面和操作系统使用与系统相关的路径名字符串 来命名文件和目录。此类呈现分层路径名的一个抽象的、与系统无关的视图。抽象路径名 有两个组件:
- 一个可选的与系统有关的前缀 字符串,比如盘符,
"/"
表示 UNIX 中的根目录,"\\\\"
表示 Microsoft Windows UNC 路径名。 - 零个或更多字符串名称 的序列。
(一)构造方法:
(1):File(String pathname) 通过将给定路径名字符串转换为抽象路径名来创建一个新File
实例。
(2):File(String parent,String child) 根据 parent 路径名字符串和 child 路径名字符串创建一个新File
实例。
(3):File(File parent,String child) 根据 parent 抽象路径名和 child 路径名字符串创建一个新File
实例。
(二)字段:该字段是用于在不同的平台中指定不同的分割符:separator :与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串。
(三):常用的方法:
(1):创建:
boolean mkdir() 创建此抽象路径名指定的目录。:只能创建一级目录,
mkdirs() 创建此抽象路径名指定的目录,包括所有必需但不存在的父目录。能创建多级目录;
boolean createNewFile():如果指定的文件不存在并成功地创建,则返回true
;如果指定的文件已经存在,则返回false
;
static File createTempFile(String prefix,String suffix) throws IOException:在默认临时文件目录中创建一个空文件,使用给定前缀
和后缀生成其名称。
static File createTempFile(String prefix,String suffix, File directory) throws IOException
在指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称。如果此方法成功返回,则可以保证:
1: 由返回的抽象路径名表示的文件在此方法被调用之前不存在。
2: 此方法及其所有变体都不会在虚拟机的当前调用中再次返回相同的抽象路径名。
(2):删除
boolean delete(): 当且仅当成功删除文件或目录时,返回true
;否则返回false
deleteOnExit() 在虚拟机终止时,请求删除此抽象路径名表示的文件或目录。
(3):判断:
boolean canExecute():测试应用程序是否可以执行此抽象路径名表示的文件。
exists() :测试此抽象路径名表示的文件或目录是否存在。
(注意):以下两个判断在判断文件对象是否是文件还是目录时:要先判断该文件或目录是否存在:使用exists();
isFile() :测试此抽象路径名表示的文件是否是一个标准文件。
isDirectory() 测试此抽象路径名表示的文件是否是一个目录。
(4):获取:
getName() 返回由此抽象路径名表示的文件或目录的名称。
getParent() 返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回null
。
getAbsolutePath() 返回此抽象路径名的绝对路径名字符串。
long lastModified() 返回此抽象路径名表示的文件最后一次被修改的时间。
long length() 返回由此抽象路径名表示的文件的长度。
renameTo(File dest) 重新命名此抽象路径名表示的文件。就如剪切,当前文件file对象.renameTo(另一个对象或是要存的位置)
File[ ] f=File.listRoots(); 获取系统的所有有效盘符:
list :该集合是获取指定目录下的当前所有文件 ---调用list方法的File对象必须是封装了一个目录,该目录还必须存在;
FilenameFilter 接口中的accpet方法是获取指定目录下指定的文件名:如要获取某一类指定的文件可以通过String类的endswith方法指定后缀名;
该方法返回值为boolean值:return name.endswrith("要或取文件的后缀名");
如示例: ----- list
public static void shows(File f){
//list返回的是当前目录下的所有名称及文件名称
String [] arr=f.list( new FilenameFilter(){
//这个接口是用于返回当前目录下的指定文件
public boolean accept(File dir, String name) {
//name.equals("软件")
//这里用String类的endswith方法获取指定后缀的文件
return name.endsWith("html");
}
});
//循环获取指定的文件
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
}
(四)示例:通过使用递归的方法获取指定目录下的所有后缀名为.java文件并存入指定目录的文本中
public static void main(String[] args) {
// TODO Auto-generated method stub
File f=new File("d:\\");//要获取java文件的路径
List<File> list=new ArrayList<File>();//创建集合
File file=new File("D:\\练习目录.txt");//要存储的路径及文件名
show(f,list);//调用要遍历的目录和存储使用的集合
readers(list,file);//调用要遍历的集合及要存储到的路径和文件名
}
//定义一个方法传入要遍历的目录和存储使用的集合
public static void show(File f,List<File> list){
//获取指定目录下的目录集合
File[] file=f.listFiles();
if(file!=null){//判断集合不能为空在遍历集合
for (int i = 0; i < file.length; i++) {
//判断是否是目录是目录在调用该方法在递归遍历该方法
if (file[i].isDirectory()) {
show(file[i],list);
}else{
//判断后缀为.java的文件在存入集合中
if(file[i].getName().endsWith(".java")){
list.add(file[i]);
}
}
}
}
}
//传入要遍历的集合及要存储到的路径和文件名
public static void readers(List<File> list,File file){
BufferedWriter bw=null;
try {
//建立字符流的缓冲区
bw=new BufferedWriter(new FileWriter(file));
//遍历集合中的数据并使用IO流的字符流来读取集合中的数据写入到指定的文本中
for(Iterator<File> it=list.iterator();it.hasNext();){
bw.write(it.next().getAbsolutePath());//获取绝对路径
bw.flush();//刷新
bw.newLine();//换行
}
} catch (IOException e) {
throw new RuntimeException("写入异常");
}
finally{
if(bw!=null){
try {
bw.close();
} catch (IOException e) {
throw new RuntimeException("写入关闭异常");
}
}
}
}
}
使用递归需注意:
1:限定条件:
2:需要注意递归的次数,避免内存溢出:
(五) 与IO技术相结合的集合容器: Properties 集合,这是hashtable的子类,也就是说他具备Map集合的特点:
(1)Properties 类表示了一个持久的属性集。Properties
可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
(2)该对象的特点是:可以用于存储键值对形式的配置文件:
(3)常用的方法:
setProperty(String key,String value) 调用Hashtable 的方法put
。
getProperty(String key) 用指定的键在此属性列表中搜索属性。
Set<String>=stringPropertyNames() 返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中未找到同名的键,
则还包括默认属性列表中不同的键。
load(InputStream inStream) 从输入流中读取属性列表(键和元素对)。
store(OutputStream out,String comments)
以适合使用 load(InputStream)
方法加载到Properties
表中的格式,将此Properties
表中的属性列表(键和元素对)写入输出流。
list(PrintStream out) 将属性列表输出到指定的输出流。
注意:该对象用于加载键值对形式的配置文件那么在加载数据时需要数据有固定的格式:键=值;
如示例:
public static void main(String[] args) {
// TODO Auto-generated method stub
show();
Properties por=new Properties();
por.setProperty("张三", "20");//设置键值属性
por.setProperty("李四", "25");
por.setProperty("王五", "22");
System.out.println(por.getProperty("李四"));//通过键获取值
//通过set集合获取Iterator迭代器
Set<String> set=por.stringPropertyNames();
//通过迭代器或键值对中的值
for (Iterator it=set.iterator();it.hasNext();) {
String key= (String) it.next();
System.out.println(key+"....."+por.getProperty(key));
}
}
public static void show(){
Properties pe=new Properties();
//创建一个字节读取流
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
try {
//创建一个字节读取流并写入要读取的文件
bis=new BufferedInputStream(new FileInputStream("Text\\配置文件.txt"));
pe.load(bis);//调用load方法将流传入
pe.list(System.out);//调用list方法传入输出流
pe.setProperty("lisi", "27");//修改文件的数据
//并将文件进行更新
bos=new BufferedOutputStream(new FileOutputStream("Text\\配置文件.txt"));
pe.store(bos, "注释信息");//通过store方法更新并加以注释
} catch (IOException e) {
throw new RuntimeException("数据异常");
}
}
}
小结: 如何写配置文件并限制程序次数:
public static void main(String[] args) {
// TODO Auto-generated method stub
Properties pop=new Properties();//创建与IO相结合的Map集合Porperties
BufferedInputStream bis=null;//创建字节读取流
BufferedOutputStream bos=null;////创建字节写入流
File file=new File("Text\\properties.ini");//创建目录文件
int count=0;//创建计数器记录程序的运行次数
try {
if(!file.exists()){//判断文件是否存在不存在就创建否则就不创建
file.createNewFile();
}
//获取要读取的文件
bis=new BufferedInputStream(new FileInputStream(file));
pop.load(bis);//调用load方法重文件中读取数据
String value=pop.getProperty("time");//获取key值
if(value!=null){//判断该key值是否为空在做判断是否超的程序运行的次数
count=Integer.parseInt(value);
if(count>=5){//如果超过就在这里处理让程序跳转到注册页面
System.out.println("拿钱来!");
return;
}
}
count++;//计数器的累加
pop.setProperty("time", count+"");//创建该键值对并赋值
//以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,
//将此 Properties 表中的属性列表(键和元素对)写入输出流。
bos=new BufferedOutputStream(new FileOutputStream(file));
pop.store(bos, "注释");
} catch (IOException e) {
throw new RuntimeException("数据异常");
}
//关闭流对象
finally{
if (bis!=null) {
try {
bis.close();
} catch (IOException e) {
throw new RuntimeException("读取关闭异常");
}
}
if (bos!=null) {
try {
bos.close();
} catch (IOException e) {
throw new RuntimeException("写入关闭异常");
}
}
}
}
}
六:字符流打印与字节流打印:
(一)printwriter: 向文本输出流打印对象的格式化表示形式。此类实现在 PrintStream
中的所有 print 方法。它不包含用于写入原始字节的方法,对于这些
字节,程序应该使用未编码的字节流进行写入。与 PrintStream
类不同,如果启用了自动刷新,则只有在调用 println、printf 或format 的其
中一个方法时才可能完成此操作,而不是每当正好输出换行符时才完成。 这些方法使用平台自有的行分隔符概念,而不是换行符。
(1) 构造函数可以接受的参数类型:
1:file对象 :File
2:字符串路径: String
3:字节输出流 :OutputStream
4:字符输出流: writer
(二)PrintStream
: 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。它还提供其他两项功能。与其他输出流不同,PrintStream
永远不会抛出 IOException
;而是,异常情况仅设置可通过 checkError
方法测试的内部标志。另外,为了自动刷新,可以创建一个
PrintStream
;这 意味着可在写入 byte 数组之后自动调用 flush
方法,可调用其中一个println
方法,或写入一个换行符或字节 ('\n'
)。
注意:PrintStream
打印的所有字符都使用平台的默认字符编码转换为字节。在需要写入字符而不是写入字节的情况下,
应该使用
类。PrintWriter
(1) 构造函数可以接受的参数类型:
1:file对象 :File
2:字符串路径: String
3:字节输出流 :OutputStream
如示例:
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
BufferedReader br=null;
try {
//获取要读取的文件
br=new BufferedReader(new FileReader("Text\\fis.txt"));
//如果为true就会自动刷新
PrintWriter pw=new PrintWriter(System.out,true);//读取到控制台;true如果没有刷新就数据就在缓冲区中
String len=null;
while((len=br.readLine())!=null){
pw.println(len);//如果没有ln 就不能刷新了,因为这是刷新的标记
//pw.flush();//上面自动刷新了就不用手动刷新了;
}
} catch (IOException e) {
// TODO: handle exception
}
br.close();
}
七 public class SequenceInputStream extendsInputStream :可将对个流对象合并 成一个流来操作
SequenceInputStream :表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个
输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。
构造方法:
(1) SequenceInputStream(Enumeration<? extendsInputStream> e)
通过记住参数来初始化新创建的 SequenceInputStream
,该参数必须是生成运行时类型为InputStream
对象的Enumeration
型参数。
(2)SequenceInputStream(InputStream s1,InputStream s2)
通过记住这两个参数来初始化新创建的 SequenceInputStream
(将按顺序读取这两个参数,先读取s1
,然后读取s2
),以提供从此
SequenceInputStream
读取的字节。
如示例:
public static void main(String[] args) throws FileNotFoundException {
// TODO Auto-generated method stub
show();
shows();
}
public static void shows() throws FileNotFoundException{
//创建集合存储多个字节流文件
ArrayList<FileInputStream> list=new ArrayList<FileInputStream>();
int count=show();
for(int i=2; i<count;i++){
//循环添加分割来的文件
list.add(new FileInputStream("Text\\"+i+".avi"));
}
//因为要使用序列流所以要使用传入Enumeration对象;而这是个枚举所以要用final修饰
final Iterator<FileInputStream> it=list.iterator();
//因为ArrayList集合中没有elements() 该方法来返回此向量的组件的枚举。所以要自己new对象来写内部类区覆盖
//里面 的两个方法并返回迭代器的的方法来获取值
Enumeration<FileInputStream> en=new Enumeration<FileInputStream>(){
public boolean hasMoreElements() {
return it.hasNext();
}
public FileInputStream nextElement() {
return it.next();
}
};
SequenceInputStream sis=new SequenceInputStream(en);//new出序列流对象并传入Enumeration对象
BufferedOutputStream bos=null;
try {//创建输出流
bos=new BufferedOutputStream(new FileOutputStream("Text\\00.avi"));
byte[] by=new byte[1024];
int len=0;
//循环序列流中的对个流对象
while((len=sis.read(by))!=-1){
bos.write(by,0,len);//将多个流的文件合成一个文件
}
} catch (IOException e) {
throw new RuntimeException("读取异常");
}
finally{
if (bos!=null) {
try {
bos.close();
} catch (IOException e) {
throw new RuntimeException("关闭异常");
}
}
if (sis!=null) {
try {
sis.close();
} catch (IOException e) {
throw new RuntimeException("关闭异常");
}
}
}
}
public static int show(){
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
int count=2;
try {//创建读取流
bis=new BufferedInputStream(new FileInputStream("Text\\1.avi"));
byte[] by=new byte[1024*1024*8];//设置缓冲区的大小
int len=0;
while((len=bis.read(by))!=-1){
//循环读取数据并将每次读取的数据输出一个新的文件中通过count改变文件名
bos=new BufferedOutputStream(new FileOutputStream("Text\\"+count+".avi"));
bos.write(by,0,len);//向文件中写入数据
count++;
if (bos!=null) {
try {
bos.close();//当数据输出完后就关闭流重新new一个新的文件
} catch (IOException e) {
throw new RuntimeException("关闭异常");
}
}
}
} catch (IOException e) {
throw new RuntimeException("读取异常");
}
finally{
if (bis!=null) {
try {
bis.close();
} catch (IOException e) {
throw new RuntimeException("关闭异常");
}
}
}
return count;
}
}
八: ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。
(1)ObjectInputStream对象:
ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,可以为应用程序提供对对象图形的持久
存储。ObjectInputStream 用于恢复那些以前序列化的对象。
主意:只有支持 java.io.Serializable 或 java.io.Externalizable 接口的对象才能从流读取。
Serializable接口:类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。
可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。
readObject 方法用于从流读取对象;
序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送
者和接收者是否为该对象加载了与序列化兼容的类。
如果要自定义序列号可以使用该方法来自定义: ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
(2):ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中
使用文件可以实现对象的持久存储。
每个 serializable 对象的类都被编码,编码内容包括类名和类签名、对象的字段值和数组值,以及从初始对象中引用的其他所有对象的闭包。
九: public class PipedInputStreamextendsInputStream 该对象是涉及到多线程的对象:
管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,数据由某个线程从
对象读取,
PipedInputStream
并由其他线程将其写入到相应的 PipedOutputStream
。不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。
十:RandomAccessFile: 类的概述
此类的实例支持对随机访问文件的读取和写入。随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。存在指向该隐含数组的光标或索引,
称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;
输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针可以
通过 getFilePointer
方法读取,并通过 seek
方法设置。
(一)特点:
(1) 该类不算是IO体系中的子类,而是直接继承Object类;但是他是IO包中的成员,因为它具备读和写的功能,内部封装了一个数组,而且通过
指针对数组,而且通过指针对数字的元素进行操作,可以通过getFilePointer获取指针的位置;同时还可以通过seek改变指针的位置;
其实完成读写的原理是内部封装了字节流输入流和字节输出流;
(2)该类只能操作文件;而且文件还要有模式,读写r w 读 r :而且该对象的构造函数要操作的文件不存在覆盖,会自动创建;
(3)如果模式为r是不会创建文件,回去读取一个已经存在的文件,如果文件不存在就会出现异常;
(4)如果模式为 rw:操作的文件不存在,会自动创建文件,如果存在则不会覆盖:
(5)在实现多个线程下载数据时在IO流中只有该类可以实现,可以实现分开的没一个线程下一段数据这样就不会出现数据错乱了;
(二)构造函数:
RandomAccessFile(File file,String mode) 创建从中读取和向其中写入(可选)的随机访问文件流,该文件由File
参数指定。
mode 参数指定用以打开文件的访问模式。允许的值及其含意为:
值 |
含意 |
---|---|
"r" | 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException 。 |
"rw" | 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。 |
"rws" | 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。 |
"rwd" | 打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。 |
(三)特别的方法有:
writeInt(int v) 按四个字节将int
写入该文件,先写高字节。
write(int b) 向此文件写入指定的字节。
readInt() 从此文件读取一个有符号的 32 位整数。
readLine() 从此文件读取文本的下一行。
read(byte[] b) 将最多b.length
个数据字节从此文件读入 byte 数组。
seek(long pos) 设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。
getFilePointer() 返回此文件中的当前偏移量。
十一: 字符编码:
(一)字符流的出现是为了方便操作字符,但更重要的是加入了编码转换;那么就要通过子类转换流来完成就是: InputStreamReader 和
OutputStreamWriter;通过这两个对象在进行构造的时候可以加入字符编码的类型,但还有两个是可以转换的就是PrintStream和PrintWriter:
但这两个对象只能够打印而不能读取,
(二)常见的编码表:
(1) ASCll :美国标准信息交换码,用一个字节的7位可以表示;
(2) ISO8859-1:拉丁编码表,欧洲码表;用一个字节8位表示;
(3)GB2312:中国的中文编码表;
(4)GBK:中国的中文编码表升级,融合了更多的中文文字符号;
(5)Unicode:国际标准码,融合了多种文字,所有文字都用两个字节来表示,java语言使用的就是unicode;
(6)UTF-8:最多用三个字节来表示一个字符。
(三)编码与解码:
(1)编码:字符串变成字节码数组;
(2)解码:字节码数组变成字符串:
String------>byte[ ];Str.getbytes(charsetName);
byte[ ] ------->String : new String(byte[ ] ,charsetName);
(3)这编码转换要先转换成字节数组在将字节数组转换成字符串在这中间要指定编码格式;
使用字符转换流来转换-------如示例:
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
BufferedReader bi=null;
OutputStreamWriter isw=null;
try {//在写文件的时候使用的编码表是utf-8
isw=new OutputStreamWriter(new FileOutputStream("Text\\out.txt"),"utf-8");
isw.write("你好");
isw.flush();
//读数据时使用的了Iso8859-1码表
InputStreamReader isr=new InputStreamReader(new FileInputStream("Text\\out.txt"),"Iso8859-1");
bi=new BufferedReader(isr);
String name=null;
while((name=bi.readLine())!=null){
System.out.println(name);//读取出来的数据时乱码
//在这里在将字符串转换成读数据时的码表重新获取字节码
byte[] by=name.getBytes("Iso8859-1");
System.out.println(Arrays.toString(by));
//在将字节码转换成字符串
String names=new String(by,"utf-8");
//在读取就可以获得原文件的内容了;
System.out.println(names);
}
} catch (IOException e) {
throw new RuntimeException("数据异常");
}
finally{
if (isw!=null) {
try {
isw.close();
}catch (IOException e) {
throw new RuntimeException("输入流关闭异常");
}
}
if (bi!=null) {
try {
bi.close();
}catch (IOException e) {
throw new RuntimeException("读取流关闭异常");
}
}
}
}
-------android培训、java培训、期待与您交流! ----------