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

黑马程序员——Java基础---IO流(File类、Properties类、其他流)

2014-11-25 13:05 721 查看
------- android培训java培训、java学习型技术博客、期待与您交流!
----------

第一讲 File类
一、简述

File类:文件和目录路径名的抽象表现形式。
作用:
用来将文件或者文件夹封装成对象。方便于对文件或文件夹的属性信息进行操作。

特点:
流只能操作数据,而想要操作数据被封装的文件的信息必须用File对象。
File类的实例是不可变的;也就是说,一旦创建,File 对象表示的抽象路径名将永不改变
File对象可以作为参数传递给流的构造函数。

二、创建对象

三种创建方式
File file = new File("a.txt");
将a.txt封装成File对象。可以将已有的和未出现的文件或者文件夹封装成对象。

File file = newFile("e:\\abc","b.txt");
将文件所在目录路径和文件一起传入,指定文件路径。

File f = new File("e:\\abc"); File file = new File(f,"c.txt");
将文件目录路径封装成对象。再创建文件对象。降低了文件于父目录的关联性。

三、常见方法:

创建:
boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false.
和输出流不一样,输出流对象一建立就创建文件,而文件已经存在,会覆盖。

boolean mkdir():创建文件夹。
boolean mkdirs():创建多层文件夹。

删除:
boolean delete(): 删除失败返回false.
void deleteOnExit():在程序退出时删除指定文件。

判断:
booelean canExecute():判断文件是否可执行。
boolean exists(): 判断文件或目录是否存在。
boolean isFile():判断是否是文件。
boolean isDirectory():判断是否是目录。
在判断文件对象是否是文件或者是目录时,必须要先判断该文件对象封装的内容是否存在。通过exists判断。
boolean isHidden():判断是否是隐藏文件。
boolean isAbsolute():判断是否是绝对路径。

获取信息:
String getName():获取文件名。
String getPath():获取文件相对路径。
String getParent():获取文件父目录。该方法返回的是绝对路径中的父目录。如果获取的是相对路径,返回null。如果相对路径中有上一层目录,那么该目录就是返回结果。
File getAbsoluteFile():获取文件绝对路径并将其封装成对象。
String getAbsolutePath():获取文件绝对路径。
long lastModified():获取文件最后一次修改时间。
long length(): 获取文件大小。
File.pathSeparator:返回当前系统默认的路径分隔符,windows默认为 “;”。
File.Separator:返回当前系统默认的目录分隔符,windows默认为 “\”。

重命名:
boolean renameTo():将文件重命名,并转移到制定目录下。

获取计算机的盘符:

File[] files = File.listRoots();

for (File f:files){
System.out.println(f);
}

String[] list()方法:
当list方法所属对象是文件时而不是目录时,返回数组为null,调用list方法的File对象必须是封装的一个目录,而且该目录必须存在。

例如:获取C盘下当前所有的文件夹以及文件的名称(包含隐藏文件)。

File f = new File("c:\\");

//File f = new File("c:\\abc.java");

String[] names = f.list();

for (String name:names){
System.out.println(name);

}

String[] list(FileNameFilter,filter)
返回满足过滤器的文件或目录。 
文件过滤器 FileNameFilter 接口,接口中只有一个返回值为boolean 型的accept()方法。

例如:用匿名内部类的方式来进行文件过滤:返回E盘下mp3文件:

File dir = new File("E:\\");

String[] arr = dir.list(new FilenameFilter()

{
public boolean accept(File dir,String name)

{
return name.endsWith(".mp3");
}
});

//E盘下文件。 

System.out.println("len:"+arr.length);

for (String name: arr){
System.out.println(name);
}             

注:list()方法 只返回当前文件目录下的文件及目录的名称。

File[] listFiles() 
返回当前目录下的文件以及文件夹的对象。

例如:获取当前目录下的文件及文件夹名称及长度。

File dir = new File("E:\\");

File[] files = dir.listFiles();

for (File f : files){
System.out.println(f.getName() +"::"+f.length());


File[] listFiles(FileNameFilter,filter)返回满足过滤器的文件或目录。

练习:删除一个带内容的目录
删除原理:在Windows中,删除目录从里面往外删除的。既然是从里往外删除,就需要用到递归。
注:在删除系统盘时,有些是删不掉的。因为有些隐藏目录Java无法访问。无法访问就导致返回数组为空,会出现空指针异常。
系统中有些文件看上去是文件实际是目录,看上去是目录实际上是文件。没有扩展名,会出现空指针异常,导致程序停止。
import java.io.*;
class  RemoveDir
{
public static void main(String[] args)
{
File dir = new File("H:\\Exercise");
removeDir(dir);
}

public static void removeDir(File dir)
{
File[] files = dir.listFiles();
for (int x = 0;x < files.length;x++)
{
if(files[x].isDirectory())
removeDir(files[x]);
else
System.out.println(files[x].toString()+"::"+files[x].delete());
}
System.out.println(dir+"::dir::"+dir.delete());
}
}


四、递归

什么是递归:
当一个功能被重复使用,而每一次使用该功能时的参数不确定,都由上次的功能元素结果来确定。
简单说:功能内部又用到该功能,但是传递的参数值不确定。(每次功能参与运算的未知内容不确定)。
其实递归就是在栈内存中不断的加载同一个函数。

递归的注意事项:
一定要定义递归的条件。限定条件,程序必须能够结束。
递归的次数不要过多。容易出现 StackOverflowError 栈内存溢出错误。
原因:当调用函数时会在栈内存中开辟空间,如果调用的次数过多,函数在栈内存中创建的空间就越大,函数没有执行结束,内存空间得不到释放,导致内存溢出。

练习:
import java.io.*;
class FileDemo3
{
public static void main(String[] args)
{
File dir = new File("G:\\360Downloads");
showDir(dir);
toBin(8);
int n = getSum(10);
System.out.println("n = "+ n);
}
//输出目录下所有文件夹及文件
public static void showDir(File dir)
{
System.out.println(dir);
File[] files = dir.listFiles();
for (int x = 0;x < files.length;x++)
{
if(files[x].isDirectory())
showDir(files[x]);
else
System.out.println(files[x]);
}
}
//求一个整数的2进制
public static void toBin(int num)
{
/*
while (num>0)
{
System.out.println(num%2);
num = num / 2;
}
*/
if (num>0)
{
toBin(num/2);
System.out.println(num%2);
}
}

public static int getSum(int n)
{
//递归求和
if (n==1)
return 1;
return n+getSum(n-1);
}
}


第二讲 Properties类

一、简述
      Properties类是Hashtable的子类。也就是说它具备map集合的特点。而且它里面存储的键值对都是字符串,不需要泛型。是集合中和IO技术相结合的集合容器。

特点:
一般用于键值对形式的配置文件。
在加载数据时,需要数据有固定格式:键=值。
可以持久化存储数据。

二、特有方法
设置
Object setProperty(String key,String value);
设置键和值,调用Hashtable的方法put

获取
String getProperty(String key)         指定key搜索value
Set<String> stringPropertyName()   返回属性列表的键集,存入Set集合

加载流和存入流
void load(InputStream ism) 从输入字节流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。
void load(Readerreader)    从输入字符流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。
void list(PrintStream out)    将属性列表输出到指定的输出流
void store(OutputStreamout,String comments) 对应load(InputStream )  将属性列表(键值对)写入输出流。comments属性列表的描述。
void store(Writerwriter, String comments);  对应load(Reader)将属性列表(键值对)写入输出流。comments属性列表的描述。

练习: 用于记录应用程序运行次数。如果使用次数已到,那么给出注册提示。
/*
练习:用于记录应用程序运行次数。如果使用次数已到,那么给出注册提示。

分析:
很容易想到的是:计数器。
可是该计数器定义在程序中,随着程序的运行而在内存中存在并进行了自增。可是随着该应用程序的退出,
该计数器也在内存中消失了。下一次再启动该程序,又重新开始从0记数。这样不是我们想要的。
程序即使结束,该计数器的值也存在。下一次程序启动后会先加载该计数器的值并加1后再重新存储起来。
所以要建立一个配置文件,用于记录该软件的使用次数。该配置文件使用键值对的形式。这样便于阅读数据,并操作数据。
键值对数据是map集合。数据是以文件形式存储,使用IO技术。那么map+IO -->Properties。

思路:1、用读取流关联文本信息文件。如果存在则读取,如果不存在,则创建
2、每次运行,将文件数据存入集合中,读取值,判断次数,如果小于等于5次,则次数增加1次,如果大于则输出提示信息。
3、将值小于等于5次的信息数据存入文件中
*/
import java.io.*;
import java.util.*;
class  RunCount
{
public static void main(String[] args) throws IOException
{
Properties prop = new Properties();
// 创建配置文件
File file = new File("count.ini");
// 如果文件不存在就创建一个文件
if(!file.exists())
file.createNewFile();
//创建流对象与文件相关联
FileInputStream fis = new FileInputStream("count.ini");
//将流中的数据加载进集合。
prop.load(fis);
//用于记录程序运行次数
int count = 0;
//根据键获取值
String value = prop.getProperty("time");
if(value != null)
{   //如果值不为空,将值转化成整数付给计数器。
count =Integer.parseInt(value);
if(count>=5)
{
System.out.println("您好,使用次数已到,请注册");
return ;
}
}
count++;
//设置键值
prop.setProperty("time",count+"");
//将设置的键值保存到文件中
FileOutputStream fos = new FileOutputStream(file);
prop.store(fos,"setTime");
//关闭流资源
fos.close();
fis.close();
}
}


第三讲 其他流

一、打印流

打印流:
包括PrintStream PrintWriter
该流提供了特有的打印方法,可以将各种数据类型的数据都原样打印。 

字节打印流:PrintStream
构造函数可以接受的参数类型:
File对象,File。
字符串路径,String.
自节输出流,OutputStream。

字符打印流:PrintWriter
构造函数可以接受的参数类型:
file对象,File。
字符串路径,String.
自节输出流,OutputStream。
字符输出流,Writer。
注:PrintWriter(OutputStream out,boolean autoFlush),autoFlush,如果为true,println、printf或format方法将刷新缓冲区。

练习:

import java.io.*;
class  PrintStreamDemo
{
public static void main(String[] args) throws IOException
{
//键盘录入
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
//创建打印流对象,指定目的地
//PrintWriter out = new PrintWriter(System.out);
// 创建打印流对象,指定目文件相关联,并加入缓冲技术
PrintWriter out =
new PrintWriter(new BufferedWriter(new FileWriter("a.txt")),true);
String line = null;
while ((line = bufr.readLine())!=null)
{
if("over".equals(line))
break;
//将数据写入缓冲区
//out.write(line);
//将数据从缓冲区刷新到目的地
//out.flush();
// 将数据写入缓冲区,从缓冲区刷新到目的地
out.println(line);
}
//关闭流
out.close();
bufr.close();
}
}


异常日志
      在程序使用过程当中,程序出现问题是不希望打印给用户看到的,因此,创建程序的异常日志,将出现的问题存储,方便程序员对程序进行修改。
示例:
import java.io.*;
import java.util.*;
import java.text.*;

class  ExceptionInfo
{
public static void main(String[] args) throws IOException
{
try
{
int[] arr = new int[2];
System.out.println(arr[3]);
}
catch (Exception e)
{
try
{
//创建时间对象
Date date = new Date();
//将时间格式化
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
String s =sdf.format(date);
//创建输出对象与文件相关联
PrintStream ps = new PrintStream("exception.log");
//输出异常发生时间
ps.println(s);
//设置输出设备为文件
System.setOut(ps);
}
catch (Exception ex)
{
throw new RuntimeException("日志文件创建失败");
}
e.printStackTrace(System.out);
}
}
}
获取系统信息

步骤:
创建Properties对象,接收System类的getProperties()获取的系统信息。
将信息输出到指定输出流中 
用Properties对象的list(PrintStream out)

将输出流中数据存入指定文件中
new PrintStream("sysout.txt")

import java.util.*;
import java.io.*;
class  SystemInfo
{
public static void main(String[] args) throws IOException
{
Properties prop = System.getProperties();
//将系统信息输出在控制台
//System.out.println(prop);
//prop.list(System.out);
//将系统属性信息存储到关联文件中
prop.list(new PrintStream("sysout.txt"));
}
}


二、 序列流 (SequenceInputStream)
作用:对多个流进行合并。
构造函数:
SequenceInputStream(InputStream s1,InputStream s2)
SequenceInputStream(Enumeration<? extends InputStream> e) 

常见合并多个流文件步骤
创建集合,并将流对象添加进集合
创建Enumeration对象,将集合元素加入。
创建SequenceInputStream对象,合并流对象
创建写入流对象,FileOutputStream关联写入文件
利用SequenceInputStream对象和FileOutputStream对象读数据进行反复读写操作。

/*
练习:合并多个.txt文件
*/
import java.io.*;
import java.util.*;
class SequenceDemo
{
public static void main(String[] args) throws IOException
{
Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("E:\\1.txt"));
v.add(new FileInputStream("E:\\2.txt"));
v.add(new FileInputStream("E:\\3.txt"));
Enumeration<FileInputStream> en = v.elements();
//创建序列流对象接收Enumeration对象
SequenceInputStream sis = new SequenceInputStream(en);
//创建输出流对象与文件相关联
FileOutputStream fos = new FileOutputStream("E:\\4.txt");
//创建缓冲区
byte[] buf = new byte[1024];
int len = 0;
while ((len =sis.read(buf))!=-1)
{
//将缓冲区读取的数据写到目的地
fos.write(buf,0,len);
}
//关闭流资源
fos.close();
sis.close();
}
}


练习:文件的切割与合并
import java.io.*;
import java.util.*;
class SplitMergeFile
{
public static void main(String[] args) throws IOException
{
//splitFile();
merge();
}
//切割
public static void splitFile()throws IOException
{
//创建读取流流对象与文件相关联
FileInputStream fis = new FileInputStream("E:\\1.bmp");
//创建写入流对象
FileOutputStream fos = null;
//创建缓冲区
byte[] buf = new byte[1024*1024];
int len = 0;
//对切割次数进行标记
int count = 1;
//将切割缓冲区数据读取并写入目的地
while ((len = fis.read(buf))!=-1)
{
fos = new FileOutputStream("E:\\splitfiles\\"+(count++)+".part");
fos.write(buf,0,len);
fos.close();
}
fis.close();
}
//合并
public static void merge()throws IOException
{
//创建集合对象
ArrayList<FileInputStream> al = new ArrayList<FileInputStream> ();
//创建流对象与文件相关联并将流对象添加到集合中
for (int x = 1;x<=3 ;x++)
{
al.add(new FileInputStream("E:\\splitfiles\\"+ x +".part"));
}
//创建迭代器
final Iterator<FileInputStream> it = al.iterator();
//枚举的匿名内部类来实现迭代
Enumeration<FileInputStream> en = new Enumeration<FileInputStream>()
{
//复写 Enumeration方法
public boolean hasMoreElements()
{
return it.hasNext();
}
public FileInputStream nextElement()
{
return it.next();
}
};
//c创建序列流对象接收Enumeration对象
SequenceInputStream sis = new SequenceInputStream(en);
//创建输出流对象与文件相关联
FileOutputStream fos = new FileOutputStream("E:\\splitfiles\\0.bmp");
//创建缓冲区
byte[] buf = new byte[1024*1024];
int len = 0;
while ((len = sis.read(buf))!= -1)
{
//将缓冲区读取的数据写到目的地
fos.write(buf,0,len);
}
//关闭流资源
fos.close();
sis.close();
}
}


三、对象的序列化:

对象的持久化存储(序列化)
对象本身存在于堆内存中,当程序结束后,内存中的垃圾回收,对象也就消失了。
用流将对内存中的对象存储在硬盘上,叫做对象的持久化存储。使用到的类:ObjectInputStream,ObjectOutputStream。
被操作的对象需要实现Serializable接口。

目的:将一个具体的对象进行持久化,写入到硬盘上。
注:
对象中静态数据不能被序列化,因为静态数据不在堆内存中,是存储在静态方法区中。
用transient关键字修饰变量,可以让非静态数据不被序列化。

Serializable接口:
用于启动对象的序列化功能,可以强制让指定类具备序列化功能,该接口中没有成员,这是一个标记接口。
这个标记接口用于给序列化类提供UID。这个uid是依据类中的成员的数字签名进行运行获取的。
如果不需要自动获取一个uid,可以在类中,手动指定一个名称为serialVersionUID id号。
"serialVersionUID"的字段(该字段必须是静态 (static)、最终 (final)的 long 型字段)。
如: public static final long serialVersionUID = 42L;

依据编译器的不同,或者对信息的高度敏感性。最好每一个序列化的类都进行手动显示的UID的指定。

写入流对象:
创建对象写入流,与文件关联,即传入目的。
通过写入writeObject(Object obj)方法,将对象作为参数传入,即可写入文件。

读取流对象
创建对象读取流,与文件关联,即传入源。
通过readObject()方法,读取文件中的对象,并返回这个对象。

/*
需求:将一个对象序列号,并从硬盘中读取序列化的对象
*/
import java.io.*;
public class ObjectStreamDemo {
public static void main(String[] args) {
writeObj();
readObj() ;
}
//将指定对象序列化到指定文件中
public static void writeObj()
{
ObjectOutputStream oos =null;
try {
//将一个对象写到文件当中,
//数据不是纯文本,对文件进行操作
//选择FileOutputStream
oos = new ObjectOutputStream(new FileOutputStream("person.object"));
//数据("lisi",29) 在堆内存中 被封装到Person对象中,
//将Person对象写入到文件"obj.txt"中
oos.writeObject(new Person("lisi",29,"kr"));
} catch (Exception e) {
throw new RuntimeException("写入数据失败");
}
finally{
try {
if(oos!=null)
oos.close();
} catch (IOException e) {
throw new RuntimeException("写入关闭失败");
}
}
}
//读取指定文件中的对象,也称反序列化
public static void readObj()
{
ObjectInputStream ois =null;
try {
//创建读取流对象,关联文件
ois = new ObjectInputStream(new FileInputStream("person.object"));
//读取文件中的对象
Person p = (Person)ois.readObject();
System.out.println(p.getName()+":"+p.getAge()+":"+p.getCountry());
} catch (Exception e) {
throw new RuntimeException("读取数据失败");
}
finally{
try {
if(ois!=null)
ois.close();
} catch (IOException e) {
throw new RuntimeException("读取关闭失败");
}
}
}
}
//创建Peason类,实现Serializable接口
class Person implements Serializable
{
//自定义serialVersionUID版本号
private static final long serialVersionUID = 42L;
private String name;
transient int age;//用transient修饰后age将不会进行序列化
static String country ="cn";//静态数据不会进行序列化
Person(String name,int age,String country)
{
this.name = name;
this.age = age;
this. country= country;
}
public String getName() {
return name + ":" + age +","+id+","+ country;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static String getCountry() {
return country;
}
public static void setCountry(String country) {
Person.country = country;
}
}


四、管道流:

管道流:PipedInputStream。PipedOutputStream。
特点:
输入输出可以直接进行连接,不用再借助数组或集合等容器进行临时存储。connect()方法,链接管道输入流和管道读取流。
通过结合线程使用。管道读取流可以读取管道写入流写入的数据。
注:因为read方法是阻塞式的,没有数据的read方法会让线程等待。使用单线程,先执行read,会发生死锁,所以需要使用多线程技术。
通常,数据由某个线程写入PipedOutputStream对象,并由其他线程从连接的 PipedInputStream 读取。

一般操作步骤:
要先创建一个读和写的两个类,实现Runnable接口,因为是两个不同的线程,覆盖run方法,注意,需要在内部处理异常。
创建两个管道流,并用connect()方法将两个流连接
创建读写对象,并传入两个线程内,并start执行。

练习:

import java.io.*;
class Read implements Runnable
{
private PipedInputStream in;
Read(PipedInputStream in)
{
this.in = in;
}
public void run()//覆盖run方法。异常不能抛,只能try。
{
try
{
byte[] buf = new byte[1024];
System.out.println("读取前..没有数据,阻塞");
//阻塞式方法read,没有数据就得等,等些入数据后才执行。
int len = in.read(buf);
System.out.println("读到数据..阻塞结束");
String s = new String(buf,0,len);
System.out.println(s);
in.close();
}
catch (IOException e)
{
throw new RuntimeException("管道读取流失败");
}
}
}

class Write implements Runnable
{
private PipedOutputStream out;
Write(PipedOutputStream out)
{
this.out = out;
}
public void run()
{
try
{
System.out.println("开始写入数据,等待6秒后.");
Thread.sleep(3000);
out.write("piped lai la".getBytes());
out.close();
}
catch (Exception e )
{
throw new RuntimeException("管道输出流失败");
}
}
}

class  PipedStreamDemo
{
public static void main(String[] args) throws IOException
{
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream();
in.connect(out);
Read r = new Read(in);
Write w = new Write(out);
new Thread(r).start();
new Thread(w).start();
}
}


五、RandomAccessFile类

作用:可以实现数据的分段写入。(下载软件原理,多线程下载)
该类不算是IO体系中子类,而是直接继承自Object。但是它是IO包中成员。因为它具备读和写的功能。
特点: 
该对象既可以读取,也可以写入。 
对象内部封装了一个byte数组,而且通过指针对数组的元素进行操作。,
该对象可以通过getFilePointer()方法获取指针位置。同时可以通过seek()方法改变指针的位置。
该对象操作的源和目的必须是文件。
该对象内部封装了字节输入流和字节输出流。

完成读写原理:
内部封装了字节输入流和字节输出流。byte数组操作的是字节。
通过构造函数可以看出,该类只能操作文件。
而且操作文件还有模式:只读r,读写rw等。,
如果模式为只读 r 。不会创建文件,会去读取一个已存在的文件。
如果该文件不存在,则会出现异常。
如果模式为rw。操作的文件不存在,会自动创建,如果存在则不会覆盖。

随机访问文件,自身具备读写的方法。
通过skipBytes(int x),seek(int x);来达到随机访问。
skipBytes(int x),调整对象中指针,只能向后,不能向前。
seek(int x) 调整对象中指针,可以前后移动。

注:在实现随机数据读取时,数据最好有规律。

练习:

import java.io.*;
class  RandomAccessFileDemo
{
public static void main(String[] args) throws IOException
{
writeFile();
readFile();
}
public static void readFile()throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","r");
//调整对象中指针。分段要有规律
//raf.seek(8*1);
//跳过指针的字节数。
raf.skipBytes(8);
byte[] buf = new byte[4];
raf.read(buf);
String name = new String(buf);
int age = raf.readInt();
System.out.println("name:"+name);
System.out.println("age = "+age);
raf.close();
}
public static void writeFile()throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.write("张三".getBytes());
//write方法只写出int类型的最低8位。
raf.writeInt(99);
raf.write("李四".getBytes());
raf.writeInt(97);
raf.close();
}
//在文件随机位置写入数据
public static void writeFile_2()throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.seek(8*3);
raf.write("周七".getBytes());
raf.writeInt(103);
raf.close();
}
}


 六、操作基本数据类型的流对象

操作基本数据类型的流对象:DataInputStream,DataOutputStream
可用于操作基本数据类型的流对象,包含读写各种基本数据类型的方法。

DataOutputStream  dos = new DataOutputStream(new FileOutputStream("data.txt"));

dos.writeInt(234);

dos.writeBoolean(true);

dos.writeDouble(9867.453);

dos.close();

DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));

int num = dis.readInt();

boolean b = dis.readBoolean();

double d = dis.readDouble();

System.out.println("num =" +num);

System.out.println("b =" + b);

System.out.println("d =" + d);

dis.close();

注:
String readUTF();//对应writeUTF,读取以UTF-8修改版编码写入的字符串
writeUTF(String str);//以与机器无关方式使用UTF-8修改版编码将一个字符串写入基础输出流。

七、 操作字节数组的流对象。

操作字节数组的流:ByteArrayInputStream和ByteArrayOutputStream
ByteArrayInputStream:  在构造的时候,需要接收数据源,而且数据源是一个字节数组。
ByteArrayOutputStream:在构造的时候,不用定义数据目的,因为该对象中已经封装了一个可变长度的字节数组。这就是数据目的地。
因为这两个流对象操作的都是数组并没有使用系统资源,所以不用进行close关闭。即使关闭后,仍可调用。
内部包含缓冲区,相当于以内存作为流操作源和目的,不会产生任何IO异常。
对象中封装了数组。 
特有方法:
ByteArrayOutputStream中:
writeTo(OutputStream out);
将此 byte 数组输出流的全部内容写入到指定的输出流参数中,这与使用out.write(buf,
0, count)调用该输出流的 write 方法效果一样。
因为这个方法用到了字节输出流,需要抛IO异常,也是字节数组流中唯一需要抛异常的方法。

int size();//当前缓冲区的大小
String toString();使用平台默认的字符集,通过解码字节将缓冲区内容转换为字符串。

对应的字符数组和字符串
字符数组流:CharArrayReader和CharArrayWriter
字符串流:   StringReader和StringWriter

import java.io.*;

class  ByteArrayStream
{
public static void main(String[] args)
{
//System.out.println("Hello World!");
//数据源。
ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFG".getBytes());
// 数据目的
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int by = 0;
while ((by = bis.read())!= -1)
{
bos.write(by);
}
System.out.println(bos.size());
System.out.println(bos.toString());
//bos.writeTo(new FileOutputStream("a.txt"));
}
}


------- android培训java培训、java学习型技术博客、期待与您交流!
----------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: