您的位置:首页 > 职场人生

黑马程序员——java基础(IO流其它类)

2015-05-02 20:18 435 查看
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

第十二章:java基础(IO流其它类)

本章概述:

第一部分:File类

第二部分:Properties类

第三部分:IO其他类

第一部分:File类

1、描述:

用来将文件或文件夹封装成对象,方便对文件和文件夹的属性信息进行操作

File对象可以作为参数传递给流的构造函数

2、字段:

separator 与系统有关的目录分隔符,如:“\\”

3、构造:

File(FileName) 可以将已有和未出现的文件或文件夹封装成对象

File(FileParent(或File对象),FileName)
文件的父目录和文件作为参数

4、File的常见方法

(1)创建

boolean createNewFile() 在指定位置创建文件,如果文件已经存在,则不创建

File createTempFile 创建临时文件

boolean mkdir 创建文件目录(只能创建一级目录)

boolean mkdirs 创建多级文件目录(如果有需要)

(2)删除

boolean delete 删除文件

void deleteOnExit 程序退出时删除

(3)判断

canExecute 判断文件是否可执行

canRead

canWrite

compareTo 比较两个文件路径的自然顺序

boolean exists 判断文件是否存在,在判断文件对象是否是文件或文件目录时必须先判断文件是否存在

boolean isDirectory 是否是文件目录

boolean isFile 判断是否是文件

boolean isHidden 判断文件对象是否是被隐藏的

boolean isAbsolute 判断是否是绝对路径

(4)获取信息

getName 返回文件对象名称,该名称是文件路径序列的最后一个名称

getPath 返回路径名称,既可以是绝对路径,也可以是相对路径

String getAbsolutePath 返回文件对象的绝对路径,如果是空抽象路径名,则返回当前目录(文件可以不存在)

File getAbsoluteFile 返回绝对路径的对象相当于File(this.getAbsolutePath())

long lastModified 返回上一次修改的时间

long length 返回文件的字节长度,如果该对象是文件夹,则返回的结果是不确定的

getParent 该方法返回的是绝对路径的父目录,如果获取的是相对路径则返回空, 如果相对路径中有上一层目录时,返回上一层目录

renameTo 重命名该文件对象

File[] listRoots 列出文件系统的根目录

String[] list 列出指定目录下的所有文件和文件夹,调用list方法的文件对象必须是文件目录,而且该目录必须存在, 有参数FileNameFilter的list方法可以返回指定格式的文件目录

File[] listFiles 返回一个抽象名数组,封装的是指定目录当前路径的所有文件对象

练习:遍历文件对象封装的目录的所有子目录和文件

步骤:

列出文件对象

判断对象是否是目录

如果是,则通过递归再调用该功能进行遍历

要限定条件

注意递归的次数,避免内存溢出

代码示例:

/*
需求:用File类创建一个包含某文件夹中文件目录的文本文件的代码示例
*/

import java.io.*;   //导入IO中的类
import java.util.*;  //导入集合所在包中的类

//定义类
class  FileDemo
{
//主函数
public static void main(String[] args)
{
//创建一个File对象,传入一个路径的字符串表示
File fi = new File("d:\\CodeFile\\Java\\");

//创建一个List集合,用于存放文件名
List<String> list = new ArrayList<String>();

//判断一下File表示的路径是否存在,是否是目录
if (fi.exists())
{
if (fi.isDirectory())
{
//调用自定义遍历文件夹的方法,将文件夹中的文件名和绝对路径字符串存入list集合中
dirList(list,fi);

}
}

//创建一个文件对象,传入要保存到哪个路径中的哪个文件中,这里把它放在了当前目录下
File file = new File("dirList.txt");

//调用自定义方法保存集合中的文件目录,传入list集合和要保存的位置的文件对象
writerDirList(list,file);
}

//定义一个遍历目录中文件的方法,传入保存文件的List集合和要遍历的目录
public static void dirList(List<String> list,File fi)
{
//用list方法获取文件对象内包含文件和文件夹名字字符串的数组
String[] fs = fi.list();

//如果数组不为空,则遍历
if(fs!= null)
{
//遍历数组中文件名和文件夹名
for(String str:fs)
{
//加入绝对路径,创建文件对象
File file = new File(fi,str);

//如果是目录,则递归遍历
if (file.isDirectory())
{
//把目录也加进去
list.add(file.toString());
//递归遍历
dirList(list,file);
}
else
{
//Java中除目录外的文件都是标准文件,将标准文件文件名添加到集合中
list.add(file.toString());
}
}
}
}

//定义一个写List中文件路径的方法,将集合中的文件路径字符串写到指定位置
public static void writerDirList(List<String> list,File file)
{

//创建一个字符流引用
BufferedWriter bufw = null;

try
{
//创建一个带缓冲的文件字符写入流,传入要写入数据的文件名
bufw = new BufferedWriter(new FileWriter(file));

//遍历list集合,将集合中的文件名字符串写入流中,并刷新到目的地
for (String str:list)
{
bufw.write(str);	//写入一条文件绝对路径的字符串
bufw.newLine();    //每写一条换行一次
bufw.flush();    //刷新
}

}
//处理IO异常
catch (IOException e)
{
e.printStackTrace();
}
//最后要关流
finally
{
//在里面单独try关流时抛出的异常
try
{
//如果流存在才关
if (bufw != null)
{
bufw.close();
}
}
//处理关流时的异常
catch (IOException e)
{
e.printStackTrace();
}

}

}

}


第二部分:Properties类

1、描述:

Properties类是HashTable的子类,也就是Map的子类,属于集合体系中的类

Properties类没有泛型定义,里面存储的键值对都是字符串

Properties是集合和IO技术相结合的集合容器,可以用两种思想去对该类对象进行操作

2、特点:

可以用于建立键值对形式的配置文件

3、方法

list(打印流) 可以将属性列表输出到指定的打印流中

load(流) 可以在指定的流中读取加载属性列表(配置信息)

setProperty("zhangsan","30") 调用HashTable的put方法添加元素

getProperty("zhangsan") 获取指定键在该列表中的元素

Set<String> StringPropertyNames 获取该列表中所有的键的Set视图

store(输出流,String) 用load方法指定输入流对应的输出流读取列表中的属性输出,String是关于该列表的注释

练习:限定程序的使用次数

代码示例:

//导入包中的类
import java.io.*;
import java.util.*;

//主类
class  PropertiesTest
{
//主函数
public static void main(String[] args)
{
//创建流引用
BufferedReader bufr;
BufferedWriter bufw;

try
{
//创建一个读取流,将配置文件中的信息读取到流中,文件要存在,否则报异常
bufr= new BufferedReader(new FileReader("ProgramCount.prop"));

//创建一个Properties对象,存储加载到的配置文件信息
Properties prop = new Properties();
//将读取流中的属性信息加载到Properties对象中
prop.load(bufr);

//读取“count”属性中的值,赋值给int变量coungt
int count = Integer.parseInt(prop.getProperty("count"));

//这是额外开的,将属性列表输出到流中(这里是默认输出流-控制台)
prop.list(System.out);

//创建一个写入流,关联原来的配置文件
bufw = new BufferedWriter(new FileWriter("programCount.prop"));

//将“count”属性中的值自增后以字符串的形式写入到Properties对象中
prop.setProperty("count",""+(++count));
//将属性列表写入到输出流中(写回配置文件)
prop.store(bufw,null);

//如果使用超过3次,提示用户付费,否则欢迎
if (count>3)
{
System.out.println("试用次数已到,拿钱!");
return;
}
else
{
System.out.println("欢迎");
}

}
//处理IO异常
catch (IOException e)
{
e.printStackTrace();
}
finally
{
//处理两个关闭流的异常
try
{
if (bufr!=null)
bufr.close();	//处理关闭读取流异常
}
catch (IOException e)
{
e.printStackTrace();
}
try
{
if(bufw!=null)
bufw.close();	//处理关闭写入流异常
}
catch (IOException ex)
{
ex.printStackTrace();
}

}

}
}


第三部分:IO中的其他类

1、打印流

(1)PrintWriter

打印流,该类属于Writer体系中的成员,该类没有对应的输入流,该类对象最大的特点就是该类提供了多种打印流中信息的方法,可以将流中的文本信息打印到各种设备中,简化了对文本信息的输出操作

构造函数可以接收的数据类型

File对象

字符串路径

字节输出流

字符输出流

(2)PrintStream

构造函数可以接收的数据类型,提供了比字符打印流更广泛的打印方法

方法:

print 该方法可以将各种数据类型原样打印

printf 带格式打印数据

println 打印加换行

代码示例:

/*
打印流:
该流提供了打印方法,可以将各种数据类型的数据都原样打印。

字节打印流:
PrintStream
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream

字符打印流:
PrintWriter
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
4,字符输出流。Writer
*/

import java.io.*;

//类
class  PrintStreamDemo
{
//主函数
public static void main(String[] args) throws IOException  //偷偷懒泡泡异常
{
//创建一个一行行读取键盘字符串的流,这是读取键盘的最常用写法
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

//创建一个打印流,将数据打印到文件写入流,写入到文本文件中,打印流第二个参数写true表示每次写入后刷新流
PrintWriter out = new PrintWriter(new FileWriter("a.txt"),true);

//创建一个字符串应用,用于临时指向从键盘读取出来的数据
String line = null;

//循环读取一行数据(当用户敲回车键表示输入一行数据完成)
while((line = bufr.readLine())!=null)
{
//如果用户输入“over”即表示要退出程序(这里不区分大小写),则跳出循环,结束录入
if("over".equals(line.toLowerCase()))
break;
//将用户输入的字符转成大写再打印出去
out.println(line.toUpperCase());
//out.flush();  //这里不用刷新了,构造时即使用的默认刷新的方法
}

//关闭流资源
out.close();
bufr.close();
}
}


2、序列流

SequenceInputStream

串联多个有序的流,当序列流中前面一个流读到结尾后,紧接着读取第二个流,直到序列流中的输入流都读完才算读完,该流可以将多个流中的数据合并成一个。

构造

SequenceInputStream(enumeration<? extends InputStream>) 接收一个输入流的枚举

elements

SequenceInputStream(InputStream i1,InputStream i2) 接收两个字节输入流

代码示例:

//导入要用到的包中的类
import java.io.*;
import java.util.*;

//类的定义
class  SequenceDemo
{
public static void main(String[] args) throws IOException
{
//创建一个Vector集合容器,因为Vector中有枚举迭代器
Vector <FileInputStream> v = new Vector<FileInputStream>();

//将三个输入流输入到容器中
v.add(new FileInputStream("c:\\1.txt"));
v.add(new FileInputStream("c:\\2.txt"));
v.add(new FileInputStream("c:\\3.txt"));

//使用Vector中的elements方法,返回一个枚举迭代器
Enumeration<FileInputStream> en = v.elements();

//创建一个序列流,构造时接收一个枚举迭代器
SequenceInputStream sis = new SequenceInputStream(en);

//创建一个输出流,用于接收序列流中输出的数据
FileOutputStream fos = new FileOutputStream("c:\\4.txt");

//定义一个字节数组缓冲区和一个int值来接收读取到的字节长度
byte[]buf = new byte[1024];
int len = 0;
//循环接收读取到的字节,并接收返回的接收的字节长度
while((len = sis.read(buf))!=-1)
{
//将读取到序列流中的字节读到输出流中,使用部分读取数组元素的方法,确保数据读到最后没有覆盖的数据不会再被重复读取
fos.write(buf,0,len);
}

//关闭流
sis.close();
fos.close();
}
}


3、对象流

用于给对象进行序列化

被操作的对象需要实现Serializable接口

静态成员不可以序列化

ObjectInputStream

ObjectOutputStream

方法

writeObject

writeInt

关键字transient

成员被transient修饰将不被序列化

代码示例:

//导入IO包中的类
import java.io.*;

//对象持久化的流演示类
class  ObjectStreamDemo
{
public static void main(String[] args) throws IOException,ClassNotFoundException
{
//注意;只有标记了可被序列化的类new出来的对象才具有被对象流操作的资格,
//所有可以被序列化的对象都实现了一个标记接口Serializable,该接口内没有定义成员,仅起标记作用

//调用自定义的写序列化对象和读序列化对象的方法
writeObj();
readObj();
}

//封装一个从文件中读取被序列化的对象的方法
public static void readObj() throws IOException,ClassNotFoundException
{
//创建一个对象输入流,构造时传入一个文件读取流,在读取流的目的地中读取出被持久化的对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.object"));

//由于对象序列化时要将对象向上转型为Object类对象,所以取出时要做强转动作,将对象类型还原
Person p = (Person) ois.readObject();

//对对象进行操作
System.out.println(p);

//关闭流资源
ois.close();
}

//封装一个将可被序列化的对象写入到持久化文件中的方法
public static void writeObj() throws IOException
{
//创建一个对象输出流,构造时传入一个文件写入流,将要持久化的对象存储到文件中
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.object"));

//存入一个可序列化的对象
oos.writeObject(new Person("lisi0",339,"kr"));

//关闭流资源
oos.close();
}
}


4、管道流

管道流是涉及到多线程技术的IO流,当

PipeInputStream

PipeOutputStream

代码示例:

import java.io.*;

//管道流演示类
class PipedStreamDemo
{
public static void main(String[] args) throws IOException
{
//分别创建一个管道输入流和管道输出流
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream();

//调用管道流中的connect方法可以将管道输入流和输出流建立连接
//该方法在管道输入流和输出流中都有定义,所以调用任意一方的该方法效果一样
//另外管道流的构造函数可以接收一个指定的对应输入/输出管道,也可以实现关联
in.connect(out);

//分别创建读和写数据的管道流的两个线程
Read r = new Read(in);  //读取数据管道流的激活线程对象
Write w = new Write(out);  //写入数据管道流的激活线程对象

//创建两个线程,传入激活线程对象,开启线程
new Thread(r).start();
new Thread(w).start();
}
}

//自定义读数据的管道流线程激活类,继承Runnable接口
class Read implements Runnable
{
//封装管道读取流
private PipedInputStream in;

//构造函数传入已关联写入管道流的读取管道流对象,并赋值给类中的引用
Read(PipedInputStream in)
{
this.in = in;
}

//线程run方法
public void run()
{
//定义一个字节数组作为缓冲区
byte[]buf = new byte[1024];

System.out.println("读取前!没有数据阻塞");

//父类的run方法没有抛出异常,所以如果有异常必须在方法里面处理掉
try
{
//将读取到的数据存入字节数组缓冲区,如果数据很多,要定义循环来接收(这里视数据字节数不超出数组长度,没有定义)
int len = in.read(buf);

System.out.println("读到数据!阻塞结束");

//我简单处理接收到的数据(转换成字符串并打印)
String s = new String(buf,0,len);
System.out.println(s);

}
catch (IOException e )
{
//读取数据出错下面的程序会受影响,抛出异常,让程序停掉
throw new RuntimeException("管道读取流失败");
}
//最后关闭流资源
finally
{
try
{
if(in!=null)
in.close();
}
catch (IOException e )
{
System.out.println("管道流关闭失败");
}
}
}
}

//定义一个写管道流线程激活类
class Write implements Runnable
{
//封装的管道输出流
private PipedOutputStream out;

//构造函数接收关联后的管道输出流
Write(PipedOutputStream out)
{
this.out = out;
}

//线程run方法
public void run()
{
try
{
System.out.println("3秒后开始写入数据,请等待···");

//为了看到方法阻塞效果,让线程睡3秒
Thread.sleep(3000);
out.write("管道流的数据来啦!!!".getBytes());
}
//处理线程中断异常和写线程IO异常
catch (IOException e)
{
throw new RuntimeException("管道输出流失败");
}
catch(InterruptedException e)
{
System.out.println("线程睡觉失败");
}
//finally关闭流资源
finally
{
try
{
if (out!=null)
{
out.close();
}
}
catch (IOException e)
{
e.toString();
}
}
}
}


5、RandomAccessFile

随机读写文件的流

该类不算IO体系中的子类,而是直接继承Object

但是它是IO包中的成员,因为它具备读和写功能

内部封装了数组,通过指针对数组元素进行操作

可以通过getFilePointer方法获取指针位置

同时可以通过seek方法改变指针位置

其实完成读写的原理靠的就是内部封装字节输入输出流

通过构造函数可以看出该类只能操作文件,而且操作文件还有模式(如:r 只读,rw读和写等)

方法

read基本数据类型

write

writeInt

···

seek 调整指针(可以前后调)

skipBytes 跳过指定字节数(不可以往前跳)

readLine

close

代码示例:

//随机读写文件流示例

import java.io.*;

//随机读写文件流演示类
class  RandomAccessFileDemo
{
public static void main(String[] args) throws IOException
{
//调用封装了随机写入流的函数
randomWriteFile();
//调用封装了随机读取流的函数
randomReadFile();
}

//封装随机读文件的函数
public static void randomReadFile() throws IOException
{
//创建一个随机文件读写流对象,指定模式为"r",只读
//注意:随机文件读写流没有对应的读取和写入流配对,只用构造时指定的模式来区分该对象可以做读操作还是写操作
//如果模式为只读r,不会创建文件,会去读取一个已存在的文件,如果该文件不存在,则会出现异常。
//如果模式rw。操作的文件不存在,会自动创建,如果存在则不会覆盖。
RandomAccessFile raf = new RandomAccessFile("ran.txt","r");

//该方法可以调整对象中的指针,使指针定位在相应的字节索引位置上。
raf.seek(8*0);

//该方法在读取的时候可以跳过指定的字节数
raf.skipBytes(8);

//下面是读取数据存入字节数组缓冲的常见操作
byte[]buf = new byte[4];
raf.read(buf);

String name = new String(buf);  //将读取的数据转成字符串

//读一个带符号的int类型位宽的整数
//注意读取的时候操作类型的顺序要和写入时一致,否则可能造成读取的数据错乱
int age = raf.readInt();

//操作数据
System.out.println("name="+name);
System.out.println("age="+age);

raf.close();  //关闭流资源
}

//封装随机写文件数据的函数
public static void randomWriteFile() throws IOException
{
//创建随机读写文件读写,模式为读和写
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");

//写入各种数据
raf.write("李四".getBytes());
raf.writeInt(97);
raf.write("王五".getBytes());
raf.writeInt(99);

raf.close();  //关闭流资源
}
}


6、操作基本数据类型的流

DataInputStream

方法:

read基本数据类型

DataOutputStream

构造

DataOutputStream(OutputStream)

方法:

write基本数据类型

writeUTFT

代码示例:

//数据流示例
import java.io.*;

class  DataStreamDemo
{
public static void main(String[] args) throws IOException
{
//调用操作基本数据类型的流演示
writeData();
readData();

}

public static void readData() throws IOException
{
//数据读取流
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));

//使用数据读取流中的读取基本数据的方法读取各种数据
//读取的时候要按写入的类型的顺序读取,否则可能会出错
int num = dis.readInt();
boolean b = dis.readBoolean();
double d = dis.readDouble();
//使用与机器无关的方式用UTF-8修改版读取流中的数据编码成字符串
String s = dis.readUTF();

//操作读取到的数据(打印)
System.out.println("num="+num);
System.out.println("b="+b);
System.out.println("d="+d);
System.out.println("s="+s);

dis.close();  //关闭流资源
}

public static void writeData() throws IOException
{
//数据写入流
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));

//使用数据写入流中的方法写入各种基本数据
dos.writeInt(234);
dos.writeBoolean(true);
dos.writeDouble(9887.543);
//使用与机器无关的方式用UTF-8修改版编码将字符串写入到流中
dos.writeUTF("你好");

dos.close();  //关闭流资源

}
}


7、操作内存中数据的流

(2)操作字节数组的流

ByteArrayInputStream

ByteArrayOutputStream

writeTo(OutputStream) 将字节数组输出流中的全部内容输出到指定输出流中

(3)操作字符数组的流

CharArrayReader

CharArrayWriter

(4)操作字符串的流

StringReader

StringWriter

扩展:

转换流的编码表

ASCII编码表(一个字节的7位)

ISO8859-1拉丁码表(一个字节的8位)

GBK2312中文码表

GBK

Unicode国际标准码,融合了多种码表(所有文字都用两个字节表示,Java语言使用的就是Unicode)

UTF-8(最多使用三个字节表示)

编码

String——byte[] str.getBytes

解码

byte[]——String new String(byte[],指定编码表)

本章总结:

1、本章介绍了大量的IO流类,这些流在一般情况下使用的频率会稍低,但是每一个类型的流都有其独特的功能,在特定的场景下,这些类都能很好的为我们完成指定的功能设计。

2、File类是一个操作文件的的类,它将计算机中的文件和文件夹封装成了对象,以便为程序中需要用到文件资源的功能提供很好的操作方式,其中需要注意的是文件和文件夹的区分和判断,文件绝对路径和相对路径文件的适用场景,对存在的和不存在的文件选取的操作方式,这些都是我们在操作File类时需要细心管理的思路。

3、Properties类属于HasHTable的子类,所以它是一个容器,里面放置的都是一些系统属性的字符串表示形式的键值对,Properties只能存储String类型的对象,不需要定义泛型。

4、打印流、序列流、对象流、随机读写流以及操作内存的流等在特定场景下都有很好的应用,这些流不需要去死记硬背,通常操作流的思路都相差不远,我们只需要对其有一定的了解,在真正应用的时候想不起细节了可以再翻查一下API,应用的次数多了自然就会熟练了。

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: