您的位置:首页 > 移动开发 > Objective-C

IO(打印流、序列流、ObjectStream、管道流、RandomAccessFile、DataStream、ByteArrayStream)

2013-06-20 14:08 253 查看
IO包中扩展功能的流对象:基本都是装饰设计模式。

——————————————————————————————————

打印流

打印流:该打印流提供了打印方法,可以将各种是数据类型的数据原样打印
字节打印流:PtintStream
构造函数:参数类型:1、File对象;2、字符串路径;3、字节输出流

前两个都JDK1.5版本才出现。而且在操作文本文件时,可指定字符编码了。

当目的是一个字节输出流时,如果使用的println方法,可以在printStream对象上加入一个true参数。这样对于println方法可以进行自动的刷新,而不是等待缓冲区满了再刷新。最终print方法都将具体的数据转成字符串,而且都对IO异常进行了内部处理。

既然操作的数据都转成了字符串,那么使用PrintWriter更好一些。因为PrintWrite是字符流的子类,可以直接操作字符数据,同时也可以指定具体的编码。

字符打印流:PrintWrtier
构造函数:参数类型:1、File对象;2、字符串路径;3、字节输出流;4、字符输出流

1和2可以加入编码,3和4加入true时自动刷新

BufferedReader bffr = new BufferedReader(new InputStreamReader(System.in));
//BufferedWriter bffw = new BufferedWriter(new OutputStreamWriter(System.out));
PrintWriter pw = new PrintWriter(System.out);
String line = null;
while((line=bffr.readLine())!=null)
{
if(line.equals("over"))
break;
//bffw.write(line);
//bffw.newLine();
//bffw.flush();
pw.println(line);
pw.flush();
}
}


——————————————————————————————————

序列流
SequenceInputStream

构造函数:1、Enumeration(枚举);2、两个字节读取流。
1、在Vector存储多个字节读取流对象,用Enumeration(枚举)中转作为参数传递给合并流。
就可以把Vector中的多个读取流对象按合并成一个读取流SequenceInputStream。
2、就是把两个读取流对象变成一个读取流SequenceInputStream

{
Vector<InputStream> v = new Vector<InputStream>();
v.add(new FileInputStream("a.txt"));
v.add(new FileInputStream("b.txt"));
v.add(new FileInputStream("c.txt"));
Enumeration<InputStream> en = v.elements();
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("0.txt");
byte[] buf = new byte[1024*1024];
int num = 0;
while((num=sis.read(buf))!=-1)
{
fos.write(buf,0,num);
}
sis.close();
fos.close();
}


分割文件:

原理是在循环获取输出流的循环体中创建读取流对象,写入数据,关闭流,用计数器命名输入流封装的文件。

{
//关联一个需要分割的文件
FileInputStream fis = new FileInputStream("c:\\008_007.jpg");
FileOutputStream fos = null;
byte[] buf = new byte[1024*1024];
int len =0;
int count = 1;
while ((len=fis.read(buf))!=-1)
{
fos = new FileOutputStream("c:\\"+count+".part");
fos.write(buf,0,len);
fos.close();
count++;
}
fis.close();
}


合并原理:多个读取流对应一个输出流。

切割原理:一个读取流对应多个输出流。

——————————————————————————————————

ObjectStream
对象的序列化:将一个具体的对象进行持久化存储到可以长期保存数据的介质当中,如硬盘、光盘、U盘子类

注意:静态数据不能被序列化,因为静态数据不在堆内存中,是存储在静态方法区中。

如何将非静态的数据不进行序列化?

用transient 关键字修饰此变量即可。被transient修饰的变量就算在标记前序列化的值重新导入,也会回到默认值。一个变量在标记前建立对象序列化后,修改类,给这个类的这个变量加上transient后重新导入对象,这个变量的值不会导入

序列化的对象必须要有对应的class在包中或者导入才能那个加载

Serializable接口:用于启动对象的序列化功能,可以强制让指定类具备序列化功能。

Serializable接口中没有方法,这种接口称为标记接口。

Serializable给类加上一个UID号,其对象在序列化时都有一个ID标识与类的UID想匹配。

对象在序列化后与之对应的类可能发生改变,类发生改变后,重新编译时,UID也会变化。与序列化的对象UD就会不匹配。UID是通过类中的成员算出开的。

ID的作用就是告诉虚拟机这个对象是哪个类的对象。

也就是说一个对象要想序列化,他的类必须实现Serializable接口。

ObjectInputStream与ObjectOutputStream
用于对象持久化的存储和读取,相对应使用

public static void writeObj()throws IOException
{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));
oos.writeObject(new Person("zhangsan",90,"cn"));
oos.close();
}
public static void readObj()throws Exception
{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));
Person p = (Person)ois.readObject();
System.out.println(p);
ois.close();
}
——————————————————————————————————

管道流
管道流:管道读取流和管道写入流可以像管道一样对接上,管道读取流就可以读取管道写入流写入的数据。

管道流:需要多线程使用,因为单线程,先执行read,会发生死锁,因为read方法是阻塞式的,没有数据的read方法会让线程等待。

class myPipedDemo
{
public static void main(String[] args) throws IOException
{
PipedOutputStream pos = new PipedOutputStream();
PipedInputStream pis = new PipedInputStream();
pis.connect(pos);//将两个流连接;
read r = new read(pis);
write w = new write(pos);
w.setStr("大范甘迪发生过的风格的风格好似打工是大法官的风格是大法官");
Thread t1 =new Thread(r);
Thread t2 =new Thread(w);
t1.start();
t2.start();
}
}
class read implements Runnable//输出流,吧管道流作为参数传递到线程类里面
{
PipedInputStream in;
read(PipedInputStream in)
{
this.in=in;
}
public void run()
{
try
{
byte[] num = new byte[10];
int len = 0;
while((len=in.read(num))!=-1)
{
String s = new String(num,0,len);
System.out.print(s);
}
in.close();
}
catch (IOException e)
{
System.out.println("管道输出流失败");
}

}
}
class write implements Runnable//输入流
{
PipedOutputStream out;
String str;
write(PipedOutputStream out)
{
this.out=out;
}
public void run()
{
try
{
out.write(str.getBytes());
out.close();
}
catch (IOException e)
{
System.out.println("管道输入流失败");
}
}
void setStr(String str)
{
this.str = str;
}
}


——————————————————————————————————

RandomAccessFile
RandomAccessFile:

该类不算IO体系中的子类,而是直接继承自Object。但是他是IO包中的成员,因为他具备读写功能;它内部封装了一个数组,而且通过指针对数组的元素进行操作。

完成读写的原理就是内部封装了字节读取流和写入流。

构造方法:

RandomAccessFile(File file, String mode) :创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。

RandomAccessFile(String name, String RandomAccessFile(File file, String mode) :创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。

RandomAccessFile(String name, String mode) :创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。 ) :创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。

通过构造方法可以看出,该类只能操作未见(局限性)
而且操作文件还有模式mode:"r","rw","rws","rwd"
"r":只读 :不会创建文件,只会去读取一个已存在的文件,文件不存在,抛异常
"rw":读写:操作的文件不存在,会自动创建。如果存在则也不会覆盖
方法摘要:

void write(byte[] b) :将 b.length 个字节从指定 byte 数组写入到此文件,并从当前文件指针开始。
void write(byte[] b, int off, int len) :将 len 个字节从指定 byte 数组写入到此文件,并从偏移量 off 处开始。
void write(int b) :向此文件写入指定的字节。
int read() :从此文件中读取一个数据字节。
int read(byte[] b) :将最多 b.length 个数据字节从此文件读入 byte 数组。
int read(byte[] b, int off, int len) :将最多 len 个数据字节从此文件读入 byte 数组。
String readLine() :从此文件读取文本的下一行。
long getFilePointer() :返回此文件中的当前偏移量。
long length():返回此文件的长度。
void seek(long pos) :设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。如果文件数据是有规律的就比较容易获取想要的数据

int skipBytes(int n):跳过指定的字节数,不过只能往后跳,不能往前跳。

可以通过getFilePointer方法获取指针位置,同时可以通过seek方法改变指针位置,跳过指定的字节位置,进行写入,或者在指定的位置写入数据(覆盖原位置上的数据)。

用法:数据的分段写入(即下载工具的断点续传和多线程)

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_2()throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.seek(8*0);
raf.write("周期".getBytes());
raf.writeInt(103);
raf.close();
}
public static void writeFile()throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.write("李四".getBytes());
raf.writeInt(97);
raf.write("王五".getBytes());
raf.writeInt(99);
raf.close();
}


——————————————————————————————————

DataStream
DataInputStream与DataOutputStream

可以用于操作基本数据类型的数据的流对象
DataOutputStream的方法writerXXX时,按照不同数据类型写入到文件中,当用DataInputStream获取文件时,用readXXX方法读取,顺序必须和写入顺序一样,否则乱码。
数据存储后用TXT打开是乱码,因为记事本跟虚拟机的编码不同。
用writerXXX和readXXX读写基本数据类型免去强转的麻烦

public static void main(String[] args) throws IOException
{
FileInputStream fis = new FileInputStream("raf2.txt");
DataInputStream dis = new DataInputStream(fis);
byte[] bus = new byte[1024];
int len = dis.read(bus);
String str = new String(bus,0,len);
System.out.println(str);
}


——————————————————————————————————

ByteArrayStream
操作直接数组的流对象
ByteArrayInputStream:在构造时需要就诶收数据源,为字节数组。

ByteArrayOutputStream:在构造时,不用定义数据目的,因为该对象已经内部封装了可变长度的字节数组,这就是目的。

因为这两个流对象都操作数组,并没有使用系统资源,所以不用关闭流。
ByteArrayOutputStream内部封装的是一个自动增长的缓冲区数组。

数组的操作只有设置和获取,相当于流操作的写和读。用流的思想操作数组。
同理:
CharArrayReader与CharArrayWriter
StringReader与StringReader
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐