------- android培训、java培训、期待与您交流! ----------
IO流分类
按流向:输入流、输出流;
按数据:字节流,字符流。
基类:
字节流:InputStream;OutPutStream
字符流:Reader;Writer;
字符流
数据的最常见体现形式是文件,先以操作文件为主来演示,需求:在硬盘上创建一个文件,并写入文字数据。Writer——OutputStreamWriter——FileWriter
方法:write(str /字符/字符数组/) 方法:将字符串写入到缓冲
flush()方法:刷新流对象中的缓冲的数据,将数据刷入到目的地中;
close()方法:关闭流资源,关闭前刷新流,将数据存入目的地中。
如果文件创建成功,一定要执行close方法关闭资源,需要捕捉IO异常;
FileWriter(File file, boolean append) 根据给定的 File 对象构造一个FileWriter对象
windows下的换行是 \r\n linux下是\n;
Reader——InputStreamReader——FileReader
方法:read(), 从输入流获取一个字符并作为数字返回,读到末尾,返回-1;
小程序,读取文件 输出到命令窗口;复制文件。
使用字符数组作为缓冲区,注意捕捉异常 。读写完毕,在finally中关闭流。
——————————————————
缓冲流:提高了对数据的读写效率。
BufferedWriterBufferedReader
缓冲区要结合流才能使用,再流的基础上对流的功能进行了增强。
关闭缓冲区就可以关闭缓冲区中的流对象,只要关闭缓冲区即可。
newLine()方法
BufferedReader 字符读取缓冲流
readLine()读取一行;
小练习:使用缓冲区复制一个文件。
自定义读取缓冲区,读取一行的方法。
LineNumberReader
装饰设计模式
当要对已有的对象进行功能增强时,可以定义一个类,将已有的对象传入,给予已有功能,并提供加强功能,那么自定义的该类就称为装饰类。
BufferReader其实就是装饰设计模式的体现。 readLine方法。
装饰类通常通过构造方法接收被装饰的对象,并给予被装饰对象提供更强的功能。
装饰模式比继承灵活,避免了继承的臃肿,降低了类与类之间的关系。
装饰类因为增强已有对象,具备的功能和已有的相同,只不过提供了增强功能,所以装饰类和被装饰类属于一个体系。
字节流
InputStreamOutputStream
FileOutputStream fos = new FileOutputStream("xxxx.txt") ;
fos.write("abcdef".getBytes()) ; //字符串转为字节数组
//不需要刷新缓冲区,就可以写入数据,但是要关闭资源
fos.close() ;
FileInputStream fis = new FileInputStream("dddd.dd") ;
byte[] buf = new byte[fis.available()] ; //available 方法返回下一步可读取的字符数,换行符是两个字符
//返回一个刚刚好的缓冲区,不用循环了,这种方法比较危险,一般定义 byte[1024]
fis.read(buf) ;
System.out.println(new String(buf)) ;
fis.close() ;
————————————————————
缓冲区
BufferedInputStreamBufferedOutputStream
标准输入输出
FileInputStream in = System.in ;int by = in.read();
字节流转换字符流:
InputStreamReaderInputStreamReader sdr = new InputStreamReader(in) ;
BufferedReader br = new BufferedReader(sdr) ;
br.readline();
字符到字节流的桥梁
OutputStreamWriterFileOutputStream fos = System.out ;
OutputStreamWriter osw = new OutputStreamWriter(fos) ;
BufferedWriter bw = new BufferedWriter(osw) ;
bw.write(str );
bw.newLine() ; //加上换行
bw.flush() ;
键盘录入最常见写法。
1、键盘录入,输出控制台;2、键盘录入,输出文件;
3、读取文件,输出控制台。
流操作的基本规律:
该用哪一个流对象?
1、明确源和目的;
源:输入流 InputStream Reader
目的:输出流 OutputStream Writer
2、明确操作的数据是不是纯文本。
纯文本:字符流 Reader Writer
非纯文本:字节流 InputStream OutputStream
3、体系明确后,在确定使用那个具体的对象
通过设备区分:
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台
File类
方法:
1、创建:
boolean creatNewFile(); 在指定位置上创建文件,如果文件存在,返回false和输出流不同,输出流对象已建立就创建文件,如果文件存在,覆盖。
static File creatTempFile(xxx, xx); 创建临时文件
boolean mkdir("xx"); 创建目录
boolean mkdirs("xx\\xx\\xx"); 创建多级目录
2、删除
boolean delete(); 删除文件,成功返回true 。deleteOnExit(); 退出时删除
3、判断
boolean exists(); 判断是否存在boolean isDirectory(File); 判断是否为目录,必须先判断是否存在
boolean isFile(File); 判断是否为文件,必须先判断是否存在
boolean isHidden(); 判断是否隐藏
boolean isAbsolute(); 判断是相对路径或绝对路径。
4、获取信息
getName();getParent(); //返回绝对路径中的文件父目录
getPath();
String getAbsolutePath();获取绝对路径
File getAbsoluteFile();返回对象
long length();返回占用字节
long lastModified();获取最后修改时间;
long time = file.lastModified();
Date date = new Date(time);
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG);
String strTime = df.format(date);
可以通过独立进程监控修改时间,如果被修改,通知程序加载新文件。
5、boolean renameTo(File dest); 重命名; 将文件重命名为dest,类似于剪切。
6、List
static File[] listRoots(); 列出系统根目录 如C:\ D:\String[] list(); 返回文件目录下的文件和文件名,,包括隐藏文件(一级目录),如果是文件,返回空,必须是目录。该目录必须存在。
Stringlist (FilenameFilter ff); 按文件名过滤;
|---FilenameFilter接口,重写方法 boolean accept(File dir,String name) ;
File[] listFiles();返回当前目录下的文件或目录的对象。
File[] listFiles(FileFilter filter);按文件过滤;
练习:删除一个带内容的目录:
在windows中,删除目录是从里面往外面删除的。public class RemoveDirTest {
public static void main(String[] args) {
File dir = new File("e:\\demodir");
removeDir(dir);
}
public static void removeDir(File dir) {
File[] files = dir.listFiles();
for(File file : files){
if(file.isDirectory()){
removeDir(file);
}else{
System.out.println(file+":"+file.delete());
}
}
System.out.println(dir+":"+dir.delete());
}
}
练习:遍历文件目录,将指定格式文件目录存储到一个文本列表。
递归:函数直接或间接的调用自身public class FileTest {
public static void main(String[] args) {
File dir = new File("d:\\java\\workspace");
listAll(dir,0);
}
public static void listAll(File dir,int level) {
System.out.println(getSpace(level)+dir.getName());
//获取指定目录下当前的所有文件夹或者文件对象
level++;
File[] files = dir.listFiles(new FileFilter(){
@Override
public boolean accept(File pathname) {
return pathname.isDirectory()||pathname.getName().endsWith(".java");
}
});
/*
FilenameFilter filter = new FilenameFilter(){
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".java");
}
};
filter.accept(dir,file.getName());//过滤的另一种方式
*/
for(int x=0; x<files.length; x++){
if(files[x].isDirectory()){
listAll(files[x],level);
}
else
System.out.println(getSpace(level)+files[x].getName());
}
}
private static String getSpace(int level) {
StringBuilder sb = new StringBuilder();
for(int x=0; x<level; x++){
sb.append(" ");
}
sb.append("|--");
return sb.toString();
}
}
Properties
Properties 是hashTable的子类,具备map集合的特点,键值对是字符串,是集合和IO相结合的容器,可以用于键值对形式的配置文件。在加载数据时,需要数据有固定格式,也就是键——值;
load(in); store(out,comments);comments为配置文件的首行说明文字,只能是英文字符
练习题:用于记录应用程序运行次数,如果次数已到,那么给出注册提示。
需要一个配置文件用于记录软件的使用次数。使用Properties配置文件可以实现应用程序数据的共享。public class PropertiesTest {
public static void main(String[] args) throws IOException {
getAppCount();
}
public static void getAppCount() throws IOException{
//将配置文件封装成File对象。
File confile = new File("count.properties");
if(!confile.exists()){
confile.createNewFile();
}
FileInputStream fis = new FileInputStream(confile);
Properties prop = new Properties();
prop.load(fis);
//从集合中通过键获取次数。
String value = prop.getProperty("time");
//定义计数器。记录获取到的次数。
int count =0;
if(value!=null){
count = Integer.parseInt(value);
if(count>=5){
throw new RuntimeException("使用次数已到,请注册,给钱!");
}
}
count++;
//将改变后的次数重新存储到集合中。
prop.setProperty("time", count+"");
FileOutputStream fos = new FileOutputStream(confile);
prop.store(fos, "");
fos.close();
fis.close();
}
}
打印流:
print()方法可以将各种数据和数据类型原样打印。不会抛出IOException.
构造函数可以接受的数据类型,如果目标是输出流,可以加自动刷新标记
PrintStream 字节打印流
1、File对象 File2、字符串路径 String
3、字节输出流 OutputStream
PrintWriter 字符打印流
1、File对象 File2、字符串路径 String
3、字节输出流 OutputStream
4、字符输出流 Writer
特殊:write(int)方法:将int最低八位输出
读取键盘:
BufferedReader bufr = new BufferedReader (new InputStreamReader(System.in)) ;序列输入流
SequenceInputStream(Enmuration<InputStream> en)构造方法将多个读取流合并为一个读取流。
示例
public class SequenceInputStreamDemo {
public static void main(String[] args) throws IOException {
//需求:将1.txt 2.txt 3.txt文件中的数据合并到一个文件中。
/*
Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("1.txt"));
v.add(new FileInputStream("2.txt"));
v.add(new FileInputStream("3.txt"));
Enumeration<FileInputStream> en = v.elements();//---Vector的elements()方法返回该集合的枚举
*/
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for(int x=1; x<=3; x++){
al.add(new FileInputStream(x+".txt"));
}
Enumeration<FileInputStream> en = Collections.enumeration(al); //---使用集合工具类的enumeration(Collection col)方法返回枚举.
/*
final Iterator<FileInputStream> it = al.iterator(); //---局部内部类只能访问被final修饰的局部变量
Enumeration<FileInputStream> en = new Enumeration<FileInputStream>(){//---自定义枚举
@Override
public boolean hasMoreElements() {
return it.hasNext();
}
@Override
public FileInputStream nextElement() {
return it.next();
}
};*/
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("1234.txt");
byte[] buf = new byte[1024];
int len = 0;
while((len=sis.read(buf))!=-1){
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
}
练习切割合并文件:
public class MergeFile {//---合并dir目录下的文件
public static void main(String[] args) throws IOException {
File dir = new File("c:\\partfiles");
mergeFile(dir);
}
public static void mergeFile(File dir) throws IOException { //---合并文件
//获取指定目录下的配置文件对象。
File[] files = dir.listFiles(new SuffixFilter(".properties"));
if(files.length!=1)
throw new RuntimeException(dir+",该目录下没有properties扩展名的文件或者不唯一");
File confile = files[0];
//获取文件中配置信息:合并文件名,文件个数==================================
Properties prop = new Properties();
FileInputStream fis = new FileInputStream(confile);
prop.load(fis);
String filename = prop.getProperty("filename");
int count = Integer.parseInt(prop.getProperty("partcount"));
//获取该目录下的所有碎片文件。 ==============================================
File[] partFiles = dir.listFiles(new SuffixFilter(".part"));
if(partFiles.length!=(count-1)){
throw new RuntimeException(" 碎片文件不符合要求,个数不对!应该"+count+"个");
}
//将碎片文件和流对象关联 并存储到集合中。
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for(int x=0; x<partFiles.length; x++){
al.add(new FileInputStream(partFiles[x]));
}
//将多个流合并成一个序列流。
Enumeration<FileInputStream> en = Collections.enumeration(al);
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream(new File(dir,filename));
byte[] buf = new byte[1024];
int len = 0;
while((len=sis.read(buf))!=-1){
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
}
public class SuffixFilter implements FilenameFilter {
private String suffix;
public SuffixFilter(String suffix) {
super();
this.suffix = suffix;
}
@Override
public boolean accept(File dir, String name) {
return name.endsWith(suffix);
}
}
public class SplitFileDemo {//---切割文件,并将信息保存到配置文件中
private static final int SIZE = 1024 * 1024;
public static void main(String[] args) throws Exception {
File file = new File("c:\\aa.mp3");
splitFile(file);
}
private static void splitFile(File file) throws IOException {
// 用读取流关联源文件。
FileInputStream fis = new FileInputStream(file);
// 定义一个1M的缓冲区。
byte[] buf = new byte[SIZE];
// 创建目的。
FileOutputStream fos = null;
int len = 0;
int count = 1;
/*
* 切割文件时,必须记录住被切割文件的名称,以及切割出来碎片文件的个数。 以方便于合并。
* 这个信息为了进行描述,使用键值对的方式。用到了properties对象
*/
Properties prop = new Properties();
File dir = new File("c:\\partfiles");
if (!dir.exists())
dir.mkdirs();
while ((len = fis.read(buf)) != -1) {
fos = new FileOutputStream(new File(dir, (count++) + ".part"));
fos.write(buf, 0, len);
fos.close();
}
//将被切割文件的信息保存到prop集合中。
prop.setProperty("partcount", count+"");
prop.setProperty("filename", file.getName());
fos = new FileOutputStream(new File(dir,count+".properties"));
//将prop集合中的数据存储到文件中。
prop.store(fos, "save file info");
fos.close();
fis.close();
}
}
对象流
ObjectInputStream 对象的反序列化ObjectOutputStream 对象序列化
对象序列化需要实现 Serializable 接口,可以指定序列化的版本号:
private static final long serialVersionUID = 1l;
static静态成员不能被序列化。只能序列化堆内存中的数据。
transient修饰符:瞬态化成员变量,使非静态成员不被序列化。
RandomAccessFile 随机访问文件类;
不算IO体系中的子类,直接继承自Object。具备读写功能,内部封装了一个数组,通过指针对数组中的元素操作,
可以通过getFilePointer获取指针位置,同时根据seek设置指针位置。
原理是其内部封装了字节读取流和输入流。
构造方法只能操作文件。
RandomAccessFile(File ,'r/rw');rw 代表读写模式
应用:断点续传功能
管道流
PipedInputStream / PipedOutputStreamPipedReader / PipedWriter
connect(Piped)连接管道流
需要使用多线程操作。
示例
public class PipedStream {
public static void main(String[] args) throws IOException {
PipedInputStream input = new PipedInputStream();
PipedOutputStream output = new PipedOutputStream();
input.connect(output);
new Thread(new Input(input)).start();
new Thread(new Output(output)).start();
}
}
class Input implements Runnable{
private PipedInputStream in;
Input(PipedInputStream in){
this.in = in;
}
public void run(){
try {
byte[] buf = new byte[1024];
int len = in.read(buf);
String s = new String(buf,0,len);
System.out.println("s="+s);
in.close();
} catch (Exception e) {
}
}
}
class Output implements Runnable{
private PipedOutputStream out;
Output(PipedOutputStream out){
this.out = out;
}
public void run(){
try {
Thread.sleep(5000);
out.write("hi,管道来了!".getBytes());
} catch (Exception e) {
}
}
}
可以操作基本数据类型的流对象
DataOutputStream(OutputStream out) 创建一个新的数据输出流,将数据写入指定基础输出流。DataInputStream(InputStream in) 使用指定的底层 InputStream 创建一个 DataInputStream。
写入UTF的方法:writeUTF("数据流"); 读取只能使用readUTF();
操作字节数组流
ByteArrayInputStream(byte[] buf) 创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。ByteArrayOutputStream() 创建一个新的 byte 数组输出流.通过toByteArray()和toString()获取数据.
close()方法无效;不会产生IOException;
writeTo(OutputStream out);将此 byte 数组输出流的全部内容写入到指定的输出流中。
用流的思想操作数组
操作字符数组
CharArrayReader
CharArrayWriter
操作字符串
StringReader
StringWriter
编码表
String str = new String("呵呵","UTF-8");byte[] buf = str.getBytes("UTF-8");
示例
public class Test {
public static void main(String[] args) throws IOException {
String str = "ab你好cd谢谢";
// int len = str.getBytes("gbk").length;
// for(int x=0; x<len; x++){
// System.out.println("截取"+(x+1)+"个字节结果是:"+cutStringByByte(str, x+1));
// }
int len = str.getBytes("utf-8").length;
for(int x=0; x<len; x++){
System.out.println("截取"+(x+1)+"个字节结果是:"+cutStringByU8Byte(str, x+1));
}
}
public static String cutStringByU8Byte(String str, int len) throws IOException {
byte[] buf = str.getBytes("utf-8");
int count = 0;
for(int x=len-1; x>=0; x--){ //---判断截取的最后几位是什么字符。
if(buf[x]<0)
count++;
else
break;
}
if(count%3==0) //---UTF-8的汉字是3个负数
return new String(buf,0,len,"utf-8");
else if(count%3==1)
return new String(buf,0,len-1,"utf-8");
else
return new String(buf,0,len-2,"utf-8");
}
public static String cutStringByByte(String str,int len) throws IOException{
byte[] buf = str.getBytes("gbk");
int count = 0;
for(int x=len-1; x>=0; x--){
if(buf[x]<0)
count++;
else
break;
}
if(count%2==0)
return new String(buf,0,len,"gbk");
else
return new String(buf,0,len-1,"gbk");
}
}
------- android培训、 java培训、期待与您交流! ----------