关于IO流的那些事

java.io流包括输入,输出两种流,每种输入输出流又可以分为字节流和字符流两大类。

File既可以代表文件,也可以代表目录。

用文件路径字符串来创建File实例,既可以用绝对路径,也可以用相对路径。在Myeclipse中相对路径一般都是用.代表该项目的路径,用./src/package/test.java来表示相对路径。

字节流主要以InputStream和OutStream作为基类,字符流主要以Reader和Writer作为基类。这几个类都是抽象类。

InputStream中有三个读操作方法:

abstract int read();
int read(byte[] b);
int read(byte[] b,int off,int len);

Reader中也有四个读操作方法:

int read();
int read(char[] cbuf);
abstract int read(char[] cbuf,int off,int len);
int read(CharBuffer target) 

OutStream中有三个写操作方法:

abstract void write(int b);
void write(byte[] b);
void write(byte[] b,int off,int len);

Writer中也有五个写操作方法:

void write(int c);
void write(char[] cbuf);
abstract void write(char[] cbuf,int off,int len);
write(String str);
write(String str, int off, int len);

显然字节流都是针对于byte来操作的,而字符流则是用char来操作。

如果输入/输出内容是文本内容,应该考虑使用字符流,如果输入/输出内容是二进制内容,应该考虑使用字节流。

与JDBC编程一样,程序里打开的IO资源不属于内存里的资源,垃圾回收机制无法回收该资源,所以应该显示关闭文件IO资源。因为它们都实现了AutoCloseable接口,所以可以通过自动关闭资源的try语句来关闭这些IO流。

很多流的构造器参数不是一个物理节点,而是已经存在的流,这种流是处理流。而所有节点流都是以物理IO节点作为构造器参数的。使用处理流来包装节点流是一种典型的装饰器设计模式。

处理流的优势:对于开发人员来说,使用处理流进行输入输出更简单,同时使用处理流执行效率更高。

各种流的使用:

在字符串中读取内容,或者将内容写入字符串(StringBuffer),可以用StringReader和StringWriter类。

直接要在屏幕上打印内容的时候考虑用PrintStream和PrintWriter类。

要将字节流转换成字符流的时候用InputStreamReader和OutStreamWriter。但是转换成字符流之后一般都要把字符流包在缓冲流里面,Java开发文档中是这样写的:

It is therefore advisable to wrap a BufferedReader around any Reader whose read() operations may be costly, such as FileReaders and InputStreamReaders.

如果只需要访问文件部分内容,而不是把文件从头读到尾,使用RandomAccessFile是更好的选择。而且RandomAccessFile还可以在已存在的文件后追加内容。

RandomAccessFile的两个常见访问方法:
void seek(long pos);
long getFilePointer();
RandomAccessFile的四种访问模式:
“r”:以只读方式打开指定文件
“rw”:以读写方式打开文件,如果不存在,就创建该文件。
“rws”:以读写方式打开文件,相对于”rw”模式,还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
“rwd”:以读写方式打开文件,相对于”rw”模式,还要求对文件内容的每个更新都同步写入到底层存储设备。
RandomAccessFile不能向指定位置插入内容,如果直接将文件记录指针移到中间位置后开始输出,新输出的内容会覆盖文件中原有的内容。如果需要在指定位置插入内容,则需要把插入点后面的内容读到缓冲区,然后把要插入的数据写入文件,再把缓冲区的内容追加到文件后面。

Java标准输入/输出是通过System.in和System.out来代表的

在System类中有三个类成员变量

static PrintStream err;
static InputStream in;
static PrintStream out;

System类中提供了3个重定向标准输入/输出的方法

static setErr(PrintStream err);
static setIn(InputStream in);
static setOut(PrintStream in);

例如重定向输入方法:

System.setIn(new FileInputStream("Test.java"));
Scanner sc=new Scanner(System.in);
sc.useDelimiter("\n");

Scanner类中是以空格作为分隔符的
A Scanner breaks its input into tokens using a delimiter pattern, which by default matches whitespace.
The default whitespace delimiter used by a scanner is as recognized by Character.isWhitespace

使用Runtime对象的exec()方法可以运行平台上的其他程序,该方法产生一个Process对象,这个对象代表这个Java程序启动的子进程。Process类提供了如下三个方法,用于让程序及其子进程进行通信:

InputStream getErrorStream();
InputStream getInputStream();
InputStream getOutputStream();

对象序列化:
对象序列化的目标是将对象保存在磁盘上,或者允许网络中直接传输对象。对象序列化机制是允许把二进制流持久地保存在磁盘上,通过网络将这种二进制流传输到另一个网络节点。其他程序一旦获得了这种二进制流,都可以将这种二进制流恢复成原来的java对象。

要使对象(不是类)可以序列化只要使目标类实现Serializeable接口即可。

序列化一般步骤:
1、创建ObjectOutputStream流。该流是处理流,建立在其他节点流的基础上。
2、调用writeObject()方法输出可序列化对象。
反序列化一般步骤
1、创建ObjectInputStream流。
2、调用readObject()方法读取流中的对象。

一个类含有引用类作为成成员变量,那么这个引用类必须是可序列化的,不然拥有这个类型成员变量的类也是不可序列化的。

java序列化机制的序列化算法
1、所有保存到磁盘中的对象都有一个序列化序号。
2。当程序视图序列化一个对象的时候,程序先检查这个对象是否已经被序列化过,只有该对象没有被序列化过,系统才会将该对象传换成字节序列并输出。
3、如果某个对象已经序列化过,程序只是直接输出一个序列化编号。
所以,只有第一次调用writeObject()方法来输出对象时转换成字节序列,并写入到ObjectOutputStream;在后面程序中就算是对象的实例变量发生了改变,再次调用writeObject()方法输出对象时,改变的实例变量也不会输出。

在实例变量前面使用transient关键字修饰,可以指定Java序列化时无须理会该实例变量。

自定义序列化:
自定义序列化的时候可以重写writeObject()和readObject()方法。但是writeObject()方法存储实例变量的顺序应该和readObject()方法中恢复实例变量的顺序一致,不然就不能正常恢复该Java对象。

另外还有一种自定义序列化机制
借助Object writeReplace() throws ObjectStreamException方法。
系统在序列化某个对象之前,会先调用该对象的writeReplace()方法,如果返回另一个对象,继续调用这个对象的writeReplace()方法,知道和这个方法不再返回另外一个对象,最后调用writeObject()方法。

与writeReplace()方法相对的是Object readResolve() throws ObjectStreamException方法。
这个方法会接着readObject()方法之后被调用,这个方法的返回值会代替原来反序列化的对象。这个方法在序列化单例类、枚举类的时候非常有用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值