您的位置:首页 > 编程语言 > Java开发

javaSE-IO补充 功能流对象(序列化和瞬态关键字)

2013-12-20 19:06 246 查看

打印流

PrintWriter与PrintStream

可以直接操作输入流和文件

/*
* 打印流:PrintStream
* 特点:
* 1,给字节输出流提供了打印方法。
* 2,方便打印数值表示形式。
* 3,构造函数接收File对象,字符串路径,OutputStream.
*/

PrintStream ps = new PrintStream("temp\\ps2.txt");

//		ps.write(97);//write写出一个int,只将最低一个字节写出。
//		ps.write(353);

//		ps.print(97);
ps.print(353); // 353 --> "353" --> 将数值保持表现形式不变,写到目的地中。都将数据转成字符串。

ps.close();
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter("temp\\pw.txt")),true);

String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
pw.println(line.toUpperCase());
//			pw.flush();
}

pw.close();
bufr.close();

序列流

SequenceInputStream

对多个流进行合并。

@Test
public void demo() throws Exception {
/*
* 演示序列流。 SequenceInputStream: 特地: 1,将多个源合并成一个源, 2,接收的是一个枚举接口对象。
*/

/* 效率太低了 不使用
* Vector<FileInputStream> v = new Vector<FileInputStream>(); v.add(new
* FileInputStream("temp\\1.txt")); v.add(new
* FileInputStream("temp\\2.txt")); v.add(new
* FileInputStream("temp\\3.txt"));
*/
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for (int x = 1; x <= 3; x++) {
al.add(new FileInputStream("temp\\" + x + ".txt"));
}

Enumeration<FileInputStream> en = Collections.enumeration(al);
SequenceInputStream sis = new SequenceInputStream(en);
BufferedReader in=new BufferedReader(new InputStreamReader(sis));
BufferedWriter out=new BufferedWriter(new FileWriter("temp/jiangyi.txt"));
String line=null;
while((line=in.readLine())!=null){
out.write(line);
out.newLine();
out.flush();
}
out.close();
in.close();
}
/*
* 将一个文件按照指定的大小进行切割。
* 思路:
* 1,一个输入流关联源文件。
* 2,当缓冲的数据满足了指定的大小后,则新建一个目的地进行继续的数据存储。
* 3,给每一个碎片文件编号。
*/public static void splitFile(File srcFile) throws IOException {

FileInputStream fis = new FileInputStream(srcFile);

FileOutputStream fos = null;

byte[] buf = new byte[1024*1024];//创建一个1M的缓冲区。

int len = 0;
int count = 1;
while((len=fis.read(buf))!=-1){

fos = new FileOutputStream(new File("temp\\",(count++)+".part"));
fos.write(buf,0,len);
fos.close();

}

//将源文件的配置信息存储到一个文件中和碎片文件在一起。
Properties prop = new Properties();
prop.setProperty("partcount", count+"");
prop.setProperty("srcfilename", srcFile.getName());

fos = new FileOutputStream(new File("temp\\",count+".properties"));

prop.store(fos, "save partfiles info");

fos.close();

fis.close();

}


操作对象(对象序列化)

ObjectInputStream与ObjectOutputStream

被操作的对象需要实现Serializable (标记接口);

能操纵对象的流对象

public static void writeObj() throws IOException {

/*
* 对象的序列化  ObjectOutputStream
* 将内存中的对象写到目的设备上。比如硬盘。
*/
FileOutputStream fos = new FileOutputStream("temp\\obj.object");
ObjectOutputStream oos = new ObjectOutputStream(fos);

oos.writeObject(new Person("mazi",23));

oos.close();

}

public static void readObj() throws IOException, ClassNotFoundException {

FileInputStream fis = new FileInputStream("temp\\obj.object");
ObjectInputStream ois = new ObjectInputStream(fis);

Object obj = ois.readObject();

Person p = (Person)obj;
System.out.println(p.getName()+":"+p.getAge());

ois.close();

}


以上代码写出的对象需实现序列化接口
public class Person implements Serializable {

/**
*
*/
private static final long serialVersionUID = 12367890L;
private static String name;
private transient/*瞬态*/ int age;

public Person() {
super();

}

public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

}


对象的序列化是要将对象持久存放在设备中

序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException。可序列化类可以通过声明名为
"serialVersionUID" 的字段(该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 serialVersionUID:

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java(TM) 对象序列化规范”中所述。不过,强烈建议 所有可序列化类都显式声明 serialVersionUID 值,原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException。因此,为保证 serialVersionUID
值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 private 修饰符显示声明 serialVersionUID(如果可能),原因是这种声明仅应用于直接声明类 -- serialVersionUID 字段作为继承成员没有用处。数组类不能声明一个明确的 serialVersionUID,因此它们总是具有默认的计算值,但是数组类没有匹配 serialVersionUID 值的要求。

瞬态

只能序列化的时候使用 可以让类在序列化时 不保存被瞬态修饰的成员属性   此成员的生命周期不能被延长

序列化总结
能持久化保存的对象 需实现序列化接口   
建议显示的定义序列化id
static修饰的成员属于类  无法被序列化  
transient修饰的成员无法延长生命周期也无法持久化 
其他成员才可以持久化

RandomAccessFile

io包的非流对象
随机访问文件,自身具备读写的方法。

通过skipBytes(int x),seek(int x)来达到随机访问
此类的实例支持对随机访问文件的读取和写入。随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针可以通过
getFilePointer 方法读取,并通过 seek 方法设置。

通常,如果此类中的所有读取例程在读取所需数量的字节之前已到达文件末尾,则抛出 EOFException(是一种 IOException)。如果由于某些原因无法读取任何字节,而不是在读取所需数量的字节之前已到达文件末尾,则抛出 IOException,而不是 EOFException。需要特别指出的是,如果流已被关闭,则可能抛出 IOException。



/*
* RandomAccessFile:
* 1,既可以读取,有可以写入。
* 2,只对文件操作。
* 3,内部维护了一个大型的byte数组,将字节输入流和字节输出流进行封装。
* 4,通过索引的方式对数组中的元素进行操作,获取和设置索引的方法是getFilePointer,seek。
* 5,随机的访问的原理:就是通过操作索引的方法对指针进行自定义的指定位置来进行读写。
*
* 对于被随机读取的数据最好有规律。
*/

构造方法摘要

RandomAccessFile(File file, String mode)

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

RandomAccessFile(String name, String mode)

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

mode说明
mode 参数指定用以打开文件的访问模式。允许的值及其含意为:


含意
"r"以只读方式打开。调用结果对象的任何 write 方法都将导致抛出
IOException
"rw"打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。
"rws"打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
"rwd"  打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。
"rws" 和 "rwd" 模式的工作方式极其类似
FileChannel
类的
force(boolean)
方法,分别传递true 和false 参数,除非它们始终应用于每个 I/O 操作,并因此通常更为高效。如果该文件位于本地存储设备上,那么当返回此类的一个方法的调用时,可以保证由该调用对此文件所做的所有更改均被写入该设备。这对确保在系统崩溃时不会丢失重要信息特别有用。如果该文件不在本地设备上,则无法提供这样的保证。
"rwd" 模式可用于减少执行的 I/O 操作数量。使用 "rwd" 仅要求更新要写入存储的文件的内容;使用 "rws" 要求更新要写入的文件内容及其元数据,这通常要求至少一个以上的低级别 I/O 操作。 

 
适用于多线程读写


管道流

PipedInputStream和PipedOutputStream
输入输出可以直接进行连接,通过结合线程使用


可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入 PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁。如果某个线程正从连接的管道输入流中读取数据字节,但该线程不再处于活动状态,则该管道被视为处于 毁坏 状态

管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,数据由某个线程从 PipedInputStream 对象读取,并由其他线程将其写入到相应的 PipedOutputStream。不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。管道输入流包含一个缓冲区,可在缓冲区限定的范围内将读操作和写操作分离开。如果向连接管道输出流提供数据字节的线程不再存在,则认为该管道已损坏。


public class PipedStreamDemo {

/**
* @param args
* @throws IOException
*/

public static void main(String[] args) throws IOException {

PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream();
in.connect(out);
new Thread(new Input(in)).start();
new Thread(new Output(out)).start();

}

}

class Input implements Runnable{

private PipedInputStream in;

public Input(PipedInputStream in) {
super();
this.in = in;
}

@Override
public void run() {

byte[] buf = new byte[1024];
int len;
try {
len = in.read(buf);//阻塞。
String str = new String(buf,0,len);
System.out.println(str);
} catch (IOException e) {

e.printStackTrace();
}

}

}

class Output implements Runnable{

private PipedOutputStream out;

public Output(PipedOutputStream out) {
super();
this.out = out;
}

@Override
public void run() {

try {
out.write("哈哈哈,我来了!".getBytes());
} catch (IOException e) {

e.printStackTrace();
}
}

}


操作基本数据类型

DataInputStream与DataOutputStream

write(int):将一个整数的四个字节中的最低字节写入到目的地。

* print(int);将一个整数的表现形式写入到目的地。你写的是什么,到目的地就是什么。

* writeInt(int);将一个整数的四个字节写入到目的地。保证数据字节的原样性。


/*
* 操作基本数据类型值的流对象。
*
*
*
*
*/
public static void readData() throws IOException {

FileInputStream fis = new FileInputStream("temp\\data.txt");

DataInputStream dis = new DataInputStream(fis);

int num = dis.readInt();
System.out.println(num);

dis.close();
}


操作字节数组

ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。

关闭 ByteArrayInputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。
对应的源设备是内存中的字节数组
此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据。

关闭 ByteArrayOutputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException
对应目的地是内存

ByteArrayInputStream bis = new ByteArrayInputStream("abcdef".getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();

int ch = 0;
while((ch=bis.read())!=-1){

bos.write(ch);
}
System.out.println(bos.toString());

试用场景 用流的思想去操作数组  不用判断溢出等操作  而且数组长度可变  可以缓存一些数据
操作字符数组

CharArrayReader与CharArrayWriter

操作字符串

StringReader 与 StringWriter

用法类似  目的地和源都是内存 一般不会抛IOException

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: