目录
1、流
1.1、什么是流?
可以读入一个字节序列的对象称作输入流。
可以向其中写入一个字节序列的对象做输出流。
字节序列的来源地和目的地可以是:
- 文件
- 网络连接
- 内存块
抽象类InputStream和OutPutStream构成了输入、输出类层次结构的基础。
我们称之为字节流。
因为面向字节的流不便于处理Unicode形式存储的信息,所以从Reader和Writer抽象类中继承出来的类专门用于处理Unicode字符的单独类层次结构。
我们称之为字符流。
1.2、读写字节
InputStream的抽象方法 read(),读入一个字节,返回读入的字节。
各个子类只需要覆盖这一个方法。
OutputStream的抽象方法write(),可以向某个输出位置写出一个字节。
需要注意的几个小点:
1、在执行read和write方法时,线程将会阻塞,直至字节被读入或者写出,其他线程可以抢占。
2、当完成流的读写时,应该通过调用close方法来进行关闭
3、关闭输出流的时候,还会刷新输出流的缓冲区
1.3、流类大家庭
注意点:
1、有FileInputStream,也有FileOutputStream
相对应的,有FileReader,也有FileWriter。
他们的参数都是一个File文件。
2、虽然我们有FileReader和FileWriter,我们在用的时候更加偏向使用BufferedReader和PrintWriter,他们两个都需要一个字符流对象来进行构造,这个最佳的字符流对象显而易见就是FileReader和FileWriter。
3、继承了FiltterInputStream类的只有三个,分别是BufferedInputStream,DataInputStream,PushbakInputStream
2、文本输入与输出
2.1、如何写出文本输出
对于文本输出,可以使用PrintWriter,这个类可以以文本格式打印字符串和数字。
PrintWriter out = new PrintWriter("emploee.txt");
//等同于
PrintWriter out = new PrintWriter(new FileWriter("emploee.txt"));
操作方法
String name = "哈尔希洛";
double age = "18.5";
out.print(name);
out.print(" ");
out.println(age)
println方法是在行中添加了目标系统中恰当的行结束。(每个系统都不一样)
如果没有设置自动冲刷(可以在构造函数里面进行调参),那么我们需要手动进行冲刷,才能在文本中看到写入结果。
out.flush();
2.2、如何读入文本输入
在Java SE5.0之前,处理文本的唯一方式是通过BufferedReader类。
拥有强大的readLine()方法,可以一次性读入一行文本。
必须要与字符流组合起来。
BufferedReader in = new BufferedReader(new FileReader("employee.dat"));
在Java核心技术推荐使用Scanner取代BufferedReader。
Scanner in = new Scanner(new File("employee.dat"));
(实际上)
BufferedReader是字符输入流中读取文本,缓冲各个字符,从而提供字符、数组和行的高效读取,速度比Scanner快,而且也可以设置缓冲区的大小,或者可使用默认的大小。
Scanner取得输入数据的依据是空格符:如按下空格键,Tab键或者Enter键,Scanner就会返回下一个输入。
所以说Scanner不能输入空格,如果希望取得含有空格的字符串BufferedReader可以做到。
3、对象流与序列化
我们可以将任何对象写出到流中,并在之后将其读回去,这种技术称为对象序列化。
保存对象数据需要使用
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.dat"));
使用
Student s = new Student();
Teacher t = new Teacher();
out.writeObject(s);
out.writerObject(t);
读入对象数据的使用是差不多的
ObjectInputStream in = new ObjectInputStream(new FileInputStream("employee.dat"));
使用
Student s = (Student)in.readObject();
Teacher t = (Teacher)in.readObject();
要完成上面这一系列操作的前提是,所有需要写出,读入的对象都应该实现Serializable接口。
实现这个接口之后,我们不需要重写任何东西,这只是一种标记。
序列化是一个很重要的应用,通过网络将对象集合传送到另一台计算机上。
保存文件原生地址内存毫无意义,这些地址对于在不同的处理器之间的通信也是毫无意义的。
用了序列化用序列号代替了内存地址,所以他允许将对象集合从一台机器送到另外一台机器。
对象序列化的算法(不涉及底层原理,这里仅仅做算法的思路描述):
写出时:
1、当遇到每一个对象引用时,都关联一个序列号。
2、对于每个对象,当第一次遇到时,保存其对象数据到流中。
3、如果某个对象之前就已经被保存过,那么就只写一段特殊标记
“与之前保存序列号x的对象相同”
读入时:
1、对于每个对象,当第一次遇到时,构建它,并使用流里面的数据初始化它,记录这个序列号和对象之间的关系
2、如果遇到特殊标记"与之前保存序列号x的对象相同"时,获取这个序列号相关联的对象引用。
4、使用文件(非重点)
流类:关心的是文件内容。
Files和Path是Java SE 7才新增进来的。
这两个类关心的是如何在磁盘中存储文件。
4.1、读写文件
1、轻松读取文件所有内容
byte[] bytes = Files.readAllBytes(path);
2、文件当做字符串来读
String connect = new String(bytes,charset);
3、如果希望将文件当做序列读入,那么可以调用
List<String> lines = Files.readAllLines(path,charset);
4、写出一个字符串到文件
Files.write(path,content.getBytes(charset)));
5、熟悉的流读入器、写出器
InputStream in = Files.newInputStream(path);
OutputStream out = Files.newOutputStream(path);
Reader in = Files.newBufferedReader(path,charset);
Reader in = Files.newBufferedWriter(path,charset);
4.2、复制、移动和删除文件
文件复制
Files.copy(fromPath,toPath);
文件移动
Files.move(fromPath,toPath);
文件删除
Files.delete(path);
4.3、创建文件和目录
创建新目录
Files.createDirectory(path);
创建新文件
Files.createFile(path);
4.4、获取文件信息
exists
isHidden
isReadable,isWritable,isExecutable
isRegularFile,isDirectory,isSymboliclink
...