IO流
Input/Output 完成输入/输出
应用程序运行时——数据在内存中 ←→ 把数据写入硬盘(磁带) 内存中的数据不可持久保存的
输入:从外部存储器(硬盘、磁带、U盘)把数据读入内存。
输出:从内存中把数据写入外部存储区(硬盘、磁带、U盘)中,这样就可以保证:即使程序退出了,数据依然不会丢失。
File — 代表磁盘上的文件或目录。
● listRoots() :列出磁盘上所有的根目录
● exists:判断是否存在
● mkdir:创建目录
● listFiles():列出当前目录下所有的文件和子目录
● listFiles(FileFilter filter) :列出当前目录下符合指定条件的文件和子目录
● File[] listFiles(FilenameFilter filter) :列出当前目录下符合指定条件的文件和子目录
列出某个磁盘所有的文件 —— 这就要用到递归
--------------------->>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<-----------------------
IO流 File的特征:只能访问磁盘上的文件和目录 它无法访问磁盘上的内容 如果要访问文件的内容,必须使用IO流。
--------------------->>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<-----------------------
流的分类:
按流的方向来分(从程序所在的内存的角度来看):
—输入流:把外部输入读入当前程序所在内。
—输出流:把当前程序所在内存的数据输出到外部
按流处理得数据来分:
— 字节流:它处理数据单元是字节(8bit),适应性广、功能强大。
— 字符流:它处理的数据单元是字符。通常来说它主要处理文本文件, 它在处理文本文件时,比字节流更方便。
按流的角色来分:
— 节点流:直接和一个IO的物理节点(磁盘上的文件、网络)关联。
— 包装流(处理流):以节点为基础,包装之后得到的流。都继承FilterXxx等基类。
流的概念模型
输入流:负责把外部的数据、读入到程序所在的内存。
缓存流
外部存储器的速度比内存速度要慢,外部存储器的读写与内存的读写并不同步!!
——通过缓存就可以解决这种不同步的问题
反正你把流用完了,别调用了flush(把缓存中的内容刷入实际的节点)方法 调用close()也可以
——系统会在关闭之前,自动刷缓存。
IO流一共涉及到40多个类
字节流 字符流
InputStream OutputStream Reader Writer(抽象)根基类不会拿来使用
FileInputStream FileOutputStream FileReader FileWriter(访问文件)
ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter(数组)
PipedInputStream PipedOutputStream PipedReader PipedWriter(访问管道)
-->(两个进程之间通信的时候)
SringReader StringWriter(访问字符串)
BufferInputStream BufferOutputStream BufferReader BufferWriter(缓存)
--> 性能得到提升
FilterInputStream FilterOutputStream FilterReader FilterWriter(过滤、抽象)
PrintStream PrintWriter(打印)
InputStreamReader OutputSteramWriter(转换) DataInputStream DataOutStream (特殊)
所有以InputStream结尾的都是【字节输入流】
所有以OutputStream结尾的都是【字节输出流】
所有以Reader结尾的都是【字符输入流】
所有以Writer结尾的都是【字节输出流】
-------------------------------->>>>>>>>>>>>>><<<<<<<<<<<<<<<<-------------------------------------------------
节点流直接与IO节点关联
——IO节点很多:键盘、网络、文件、磁带....
把节点流包装成过滤流:消除节点流的差异:
而且PrintStream的
PrintStream ps = new PrintStream(fos);//fos为文件
ps.println("我有一个房子");
ps == System.out 都属于PrintStream的属性
过滤流,建立在节点流的基础之上。
过滤流的好处:
— 消除底层节点之间的差异
— 使用过滤流的方法执行IO更加便捷
FileOutPutStream → PrintStream
FileWiter → PrintWiter
如果已经知道要读的内容是字符内容,就可以按如下的方式转换
InputStream → InputStreamReader → BufferedReader
FileInputStream fis = new InputStreamReader("ReadFile.java");
InputStreamReader reader = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(reader);
换为一行:
BufferedReader br = new BufferedReader(
new InputStreamReader(
new InputStreamReader("ReadFile.java")));
-------------------------------->>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<----------------------------------------
DataInputStream与DataOutputStream
它们是两个特殊的流
——它们并不是节点流,是过滤流(建立在已有IO的基础之上)
—— 它们只要增加一些特定的方法来读取特定的数据。
重定向标准输入输出:
System.in — 标准输入。通常代表键盘
System.out — 标准输出。通常代表屏幕
System.setOut() —— 可以将标准重定向到另一个输出流
System.setIn() —— 可以将标准重定向到另一个输入流
System.setOut(new PrintSteam("out.txt")) ; 可以将输出的内容直接放入文件...
System.setIn(new FileInputStreamSteam("out.txt")) ; 可以从文件读取内容并输出
Java虚拟机读取其他进程的数据:
Java如何启动其他进程:Runtime实例.exec()
该方法的返回值是一个Process对象
Process — 代表一个进程
进程就是运行中的应用程序。
{
Runtime runtime = Rintime getRuntime();
//启动javac应用程序返回
Process proc = runtime.exec("java.exe");
//要得到javac应用程序输出的内容,此处应该用输入流?还是输出流
//对javac来说,是输出;但对于我们应用程序来说,用输入流
InuputStreamReader reader = new InuputStreamReader (proc.getErrorStream());
BuffereReader br = new BuffereReader(reader); String line =null;
System.out.println("编译出错,错误信息如下"); //控制BufferedReader每次读取一行
while((line = br.readLine()) != null) {
System.out.println(line);
}
}
StringWriter sw = new StringWriter();
sw.Writer(line);
RandomAccessFile — 随机(任意)访问
Random — 想访问文件的那个点,就访问文件的哪个点(任意)。
特征:A。即可读,又可写、还可追加。------> 【相当于DataInputStream与DataOutputStream】合体 RandomAccessFile它不会覆盖原有的文件内容。 B。只能访问文件!!这就是它的局限性。 创建RandomAccessFile,需要指定读(r)、写(rw)模式。 体现它的“random【任意】”性的方法是:
● seek(long pos) — 用于把记录指针移动到任意位置,想要访问哪个点就访问哪个点 一开始,它的记录指针位于文件的开始位置。
使用RandomAccessFile来追加文件内容:1.把记录指针移动到最后; 2.执行输出即可
使用RandomAccessFile来插入文件内容:1.把记录指针移动到指定位置; 2.从当前位置到文件结尾的内容,先读取、并保存 3.输出要插入的内容。4.输出之前保存的内容。
IO体系------>>>
------------------------------------->>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<-------------------------------------------
Java传统IO的基本体系:
字节输入流 字节输出流 字符输入流 字符输出流
InputSteam OutputStream Reader Writer
访问文件 FileXxx
访问数组 ByteArrayXxx CharArrayXxx
访问管道 PipedXxx
访问字符串 StringXxx
过滤流 FileterInputStream FileterOutputStream FileterReader FilterWriter
缓冲流 BufferedXxx
打印流 PrintStream PrintWriter
转换流 InputStreamReader OutputStreamWriter
特殊流 DataInputStream DataOutputStream
ObjectInputStream ObjectOutputStream
RandomAccessFile — 1.它只能访问文件。相当于DataInputStream和DataOutputStream组合
2.任意,由seek(int pos)。
------------------------------------->>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<-------------------------------------------
序列化 java对象(内存) ←→ 二进制流
目的: A。在有些时候,需要把对象存储到外部存储中持久保持
B。在有些时候,需要把对象通过网络传输。
......
● 可序列化的对象,Java要求可序列化的类实现下面两个接口的任意之一:
— Serializable:接口只是一个标记性的接口,实现该接口无需实现任何方法。
— Externalizable 实现该接口要实现方法。
● 序列化的IO流:
ObjectInputStream — 负责从二进制流“恢复”对象。readObject
ObjectOutputStream — 负责把对象保存到二进制中。writeObiect
● 引用变量的序列化机制
A。引用变量所引用的对象的所有属性的类都应该是可序列化的。
B。序列化的底层机制:
(1)每序列化一个对象,都会给为该对象设置一个编号
(2)如果程序第一次序列化某个对象。系统会真的将该对象序列化、并输出。
(3)如果要序列化的对象是之前已经序列化的。此时系统只输出一个编号。 这种序列化机制,就是为了保存磁盘里的二进制与内存中的对象是对应的。
● transient — 修饰符。
用于修饰实例成员变量。(不能与static同时使用!)
transient 用于执行被修饰的Field不会被序列化。
static修饰的是类变量 — 序列化机制负责序列化实例。
static修饰的类变量存储在类信息中,并不是在存储在对象里 ——因此static修饰的类变量不会被序列化!
为什么要用transient?
对于一些敏感信息,比如银行卡帐号、密码,就不应该被序列化出来,此时就可以通过transinet来修饰这些属性。
● 完全自定义的序列化
对于一些敏感信息,可以使用transient来阻止它们进行序列化。
但将一些属性完全阻止在序列化之外,有时候也并不完善。
此时可以借助与“定制序列化”,
自定义序列化机制,为序列化类增加如下两个方法:
--> 系统会调用这两个方法完成实际的序列化
1 private void writeObject(java.io.ObjectOutputStream out) 2 throws IOException 3 { 4 out.writeUTF(account);//自然也可以做更复杂的加密 5 out.writeUTF(new StringBuilder(password).reverse().toString) 6 } 7 private void readObject(java.io.ObjectInputStream in) 8 throws IOException, ClassNotFoundException 9 {10 //恢复的顺序要与之前写入的顺序保持一致11 this.account = in.readUTF();12 this.password = new StringBuilder(in.readUTF().reverse().toString());13 }
● 版本号
当我们的类经常使用时,有时候系统无法确定“反序列化”的class文件是否还正确。
建议显示为“可序列化”指定一个版本号。
/*即使你不指定,系统也默认一个版本号,但不稳定*/
seralver.exe — 专门用于查看该类的版本号
seralver — show:显示图形化界面
seralver 完整的类名:显示制定的类的版本号
定义版本号:十分简单: static final long serialVersionUID = 50L;
—— 自定义的版本号的好处:更稳定。 只有当我们修改了类定义时,可由程序员显示地控制改变版本号。
Java 7 传统的Java里,只有一个File类,即代表文件,又代表目录。
=== Arrays Object 、Collections 、Paths 、Files ====
Path — 接口,专门代表了一个平台无关的路径。
Paths — 工具类。所有的方法都是static的。
Files — 操作文件的工具类。 提供了大量的方法来操作文件。
------------------------------------->>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<-------------------------------------------